@@ -820,6 +820,44 @@ def as_hours(self):
820820 self .assertEqual (str (t3 ), str (t4 ))
821821 self .assertEqual (t4 .as_hours (), - 1 )
822822
823+ def test_subclass_date (self ):
824+ class DateSubclass (date ):
825+ pass
826+
827+ d1 = DateSubclass (2018 , 1 , 5 )
828+ td = timedelta (days = 1 )
829+
830+ tests = [
831+ ('add' , lambda d , t : d + t , DateSubclass (2018 , 1 , 6 )),
832+ ('radd' , lambda d , t : t + d , DateSubclass (2018 , 1 , 6 )),
833+ ('sub' , lambda d , t : d - t , DateSubclass (2018 , 1 , 4 )),
834+ ]
835+
836+ for name , func , expected in tests :
837+ with self .subTest (name ):
838+ act = func (d1 , td )
839+ self .assertEqual (act , expected )
840+ self .assertIsInstance (act , DateSubclass )
841+
842+ def test_subclass_datetime (self ):
843+ class DateTimeSubclass (datetime ):
844+ pass
845+
846+ d1 = DateTimeSubclass (2018 , 1 , 5 , 12 , 30 )
847+ td = timedelta (days = 1 , minutes = 30 )
848+
849+ tests = [
850+ ('add' , lambda d , t : d + t , DateTimeSubclass (2018 , 1 , 6 , 13 )),
851+ ('radd' , lambda d , t : t + d , DateTimeSubclass (2018 , 1 , 6 , 13 )),
852+ ('sub' , lambda d , t : d - t , DateTimeSubclass (2018 , 1 , 4 , 12 )),
853+ ]
854+
855+ for name , func , expected in tests :
856+ with self .subTest (name ):
857+ act = func (d1 , td )
858+ self .assertEqual (act , expected )
859+ self .assertIsInstance (act , DateTimeSubclass )
860+
823861 def test_division (self ):
824862 t = timedelta (hours = 1 , minutes = 24 , seconds = 19 )
825863 second = timedelta (seconds = 1 )
@@ -2604,33 +2642,58 @@ def __new__(cls, *args, **kwargs):
26042642 ts = base_d .timestamp ()
26052643
26062644 test_cases = [
2607- ('fromtimestamp' , (ts ,)),
2645+ ('fromtimestamp' , (ts ,), base_d ),
26082646 # See https://bugs.python.org/issue32417
2609- # ('fromtimestamp', (ts, timezone.utc)),
2610- ('utcfromtimestamp' , (utc_ts ,)),
2611- ('fromisoformat' , (d_isoformat ,)),
2612- ('strptime' , (d_isoformat , '%Y-%m-%dT%H:%M:%S.%f' )),
2613- ('combine' , (date (* args [0 :3 ]), time (* args [3 :]))),
2647+ ('fromtimestamp' , (ts , timezone .utc ),
2648+ base_d .astimezone (timezone .utc )),
2649+ ('utcfromtimestamp' , (utc_ts ,), base_d ),
2650+ ('fromisoformat' , (d_isoformat ,), base_d ),
2651+ ('strptime' , (d_isoformat , '%Y-%m-%dT%H:%M:%S.%f' ), base_d ),
2652+ ('combine' , (date (* args [0 :3 ]), time (* args [3 :])), base_d ),
26142653 ]
26152654
2616- for constr_name , constr_args in test_cases :
2655+ for constr_name , constr_args , expected in test_cases :
26172656 for base_obj in (DateTimeSubclass , base_d ):
26182657 # Test both the classmethod and method
26192658 with self .subTest (base_obj_type = type (base_obj ),
26202659 constr_name = constr_name ):
2621- constr = getattr (base_obj , constr_name )
2660+ constructor = getattr (base_obj , constr_name )
26222661
2623- dt = constr (* constr_args )
2662+ dt = constructor (* constr_args )
26242663
26252664 # Test that it creates the right subclass
26262665 self .assertIsInstance (dt , DateTimeSubclass )
26272666
26282667 # Test that it's equal to the base object
2629- self .assertEqual (dt , base_d . replace ( tzinfo = None ) )
2668+ self .assertEqual (dt , expected )
26302669
26312670 # Test that it called the constructor
26322671 self .assertEqual (dt .extra , 7 )
26332672
2673+ def test_subclass_now (self ):
2674+ # Test that alternate constructors call the constructor
2675+ class DateTimeSubclass (self .theclass ):
2676+ def __new__ (cls , * args , ** kwargs ):
2677+ result = self .theclass .__new__ (cls , * args , ** kwargs )
2678+ result .extra = 7
2679+
2680+ return result
2681+
2682+ test_cases = [
2683+ ('now' , 'now' , {}),
2684+ ('utcnow' , 'utcnow' , {}),
2685+ ('now_utc' , 'now' , {'tz' : timezone .utc }),
2686+ ('now_fixed' , 'now' , {'tz' : timezone (timedelta (hours = - 5 ), "EST" )}),
2687+ ]
2688+
2689+ for name , meth_name , kwargs in test_cases :
2690+ with self .subTest (name ):
2691+ constr = getattr (DateTimeSubclass , meth_name )
2692+ dt = constr (** kwargs )
2693+
2694+ self .assertIsInstance (dt , DateTimeSubclass )
2695+ self .assertEqual (dt .extra , 7 )
2696+
26342697 def test_fromisoformat_datetime (self ):
26352698 # Test that isoformat() is reversible
26362699 base_dates = [
0 commit comments