@@ -1783,73 +1783,81 @@ def tzinfo(self):
1783
1783
1784
1784
# OPERATIONS #
1785
1785
1786
+ def _get_both_normalized_ticks (self , other , strict = True ):
1787
+ if (isinstance (other , (time , Time ))
1788
+ and ((self .utc_offset () is None )
1789
+ ^ (other .utcoffset () is None ))):
1790
+ if strict :
1791
+ raise TypeError ("can't compare offset-naive and offset-aware "
1792
+ "times" )
1793
+ else :
1794
+ return None , None
1795
+ if isinstance (other , Time ):
1796
+ other_ticks = other .__ticks
1797
+ elif isinstance (other , time ):
1798
+ other_ticks = int (3600000000000 * other .hour
1799
+ + 60000000000 * other .minute
1800
+ + NANO_SECONDS * other .second
1801
+ + 1000 * other .microsecond )
1802
+ else :
1803
+ return None , None
1804
+ utc_offset = other .utcoffset ()
1805
+ if utc_offset is not None :
1806
+ other_ticks -= utc_offset .total_seconds () * NANO_SECONDS
1807
+ self_ticks = self .__ticks
1808
+ utc_offset = self .utc_offset ()
1809
+ if utc_offset is not None :
1810
+ self_ticks -= utc_offset .total_seconds () * NANO_SECONDS
1811
+ return self_ticks , other_ticks
1812
+
1786
1813
def __hash__ (self ):
1787
1814
""""""
1788
- return hash (self .__ticks ) ^ hash (self .tzinfo )
1815
+ if self .__nanosecond % 1000 == 0 :
1816
+ return hash (self .to_native ())
1817
+ self_ticks = self .__ticks
1818
+ if self .utc_offset () is not None :
1819
+ self_ticks -= self .utc_offset ().total_seconds () * NANO_SECONDS
1820
+ return hash (self_ticks )
1789
1821
1790
1822
def __eq__ (self , other ):
1791
1823
"""`==` comparison with :class:`.Time` or :class:`datetime.time`."""
1792
- if isinstance (other , Time ):
1793
- return self .__ticks == other .__ticks and self .tzinfo == other .tzinfo
1794
- if isinstance (other , time ):
1795
- other_ticks = (3600000000000 * other .hour
1796
- + 60000000000 * other .minute
1797
- + NANO_SECONDS * other .second
1798
- + 1000 * other .microsecond )
1799
- return self .ticks_ns == other_ticks and self .tzinfo == other .tzinfo
1800
- return False
1824
+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other ,
1825
+ strict = False )
1826
+ if self_ticks is None :
1827
+ return False
1828
+ return self_ticks == other_ticks
1801
1829
1802
1830
def __ne__ (self , other ):
1803
1831
"""`!=` comparison with :class:`.Time` or :class:`datetime.time`."""
1804
1832
return not self .__eq__ (other )
1805
1833
1806
1834
def __lt__ (self , other ):
1807
1835
"""`<` comparison with :class:`.Time` or :class:`datetime.time`."""
1808
- if isinstance (other , Time ):
1809
- return (self .tzinfo == other .tzinfo
1810
- and self .ticks_ns < other .ticks_ns )
1811
- if isinstance (other , time ):
1812
- if self .tzinfo != other .tzinfo :
1813
- return False
1814
- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1815
- return self .ticks_ns < other_ticks
1816
- return NotImplemented
1836
+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1837
+ if self_ticks is None :
1838
+ return NotImplemented
1839
+ return self_ticks < other_ticks
1817
1840
1818
1841
def __le__ (self , other ):
1819
1842
"""`<=` comparison with :class:`.Time` or :class:`datetime.time`."""
1820
- if isinstance (other , Time ):
1821
- return (self .tzinfo == other .tzinfo
1822
- and self .ticks_ns <= other .ticks_ns )
1823
- if isinstance (other , time ):
1824
- if self .tzinfo != other .tzinfo :
1825
- return False
1826
- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1827
- return self .ticks_ns <= other_ticks
1828
- return NotImplemented
1843
+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1844
+ if self_ticks is None :
1845
+ return NotImplemented
1846
+ return self_ticks <= other_ticks
1829
1847
1830
1848
def __ge__ (self , other ):
1831
1849
"""`>=` comparison with :class:`.Time` or :class:`datetime.time`."""
1832
- if isinstance (other , Time ):
1833
- return (self .tzinfo == other .tzinfo
1834
- and self .ticks_ns >= other .ticks_ns )
1835
- if isinstance (other , time ):
1836
- if self .tzinfo != other .tzinfo :
1837
- return False
1838
- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1839
- return self .ticks_ns >= other_ticks
1840
- return NotImplemented
1850
+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1851
+ if self_ticks is None :
1852
+ return NotImplemented
1853
+ return self_ticks >= other_ticks
1841
1854
1842
1855
def __gt__ (self , other ):
1843
1856
"""`>` comparison with :class:`.Time` or :class:`datetime.time`."""
1844
- if isinstance (other , Time ):
1845
- return (self .tzinfo == other .tzinfo
1846
- and self .ticks_ns >= other .ticks_ns )
1847
- if isinstance (other , time ):
1848
- if self .tzinfo != other .tzinfo :
1849
- return False
1850
- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1851
- return self .ticks_ns >= other_ticks
1852
- return NotImplemented
1857
+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1858
+ if self_ticks is None :
1859
+ return NotImplemented
1860
+ return self_ticks > other_ticks
1853
1861
1854
1862
def __copy__ (self ):
1855
1863
return self .__new (self .__ticks , self .__hour , self .__minute ,
@@ -1883,6 +1891,21 @@ def replace(self, **kwargs):
1883
1891
nanosecond = kwargs .get ("nanosecond" , self .__nanosecond ),
1884
1892
tzinfo = kwargs .get ("tzinfo" , self .__tzinfo ))
1885
1893
1894
+ def _utc_offset (self , dt = None ):
1895
+ if self .tzinfo is None :
1896
+ return None
1897
+ value = self .tzinfo .utcoffset (dt )
1898
+ if value is None :
1899
+ return None
1900
+ if isinstance (value , timedelta ):
1901
+ s = value .total_seconds ()
1902
+ if not (- 86400 < s < 86400 ):
1903
+ raise ValueError ("utcoffset must be less than a day" )
1904
+ if s % 60 != 0 or value .microseconds != 0 :
1905
+ raise ValueError ("utcoffset must be a whole number of minutes" )
1906
+ return value
1907
+ raise TypeError ("utcoffset must be a timedelta" )
1908
+
1886
1909
def utc_offset (self ):
1887
1910
"""Return the UTC offset of this time.
1888
1911
@@ -1896,19 +1919,7 @@ def utc_offset(self):
1896
1919
:raises TypeError: if `self.tzinfo.utcoffset(self)` does return anything but
1897
1920
None or a :class:`datetime.timedelta`.
1898
1921
"""
1899
- if self .tzinfo is None :
1900
- return None
1901
- value = self .tzinfo .utcoffset (self )
1902
- if value is None :
1903
- return None
1904
- if isinstance (value , timedelta ):
1905
- s = value .total_seconds ()
1906
- if not (- 86400 < s < 86400 ):
1907
- raise ValueError ("utcoffset must be less than a day" )
1908
- if s % 60 != 0 or value .microseconds != 0 :
1909
- raise ValueError ("utcoffset must be a whole number of minutes" )
1910
- return value
1911
- raise TypeError ("utcoffset must be a timedelta" )
1922
+ return self ._utc_offset ()
1912
1923
1913
1924
def dst (self ):
1914
1925
"""Get the daylight saving time adjustment (DST).
@@ -1997,6 +2008,7 @@ def __format__(self, format_spec):
1997
2008
""""""
1998
2009
raise NotImplementedError ()
1999
2010
2011
+
2000
2012
Time .min = Time (hour = 0 , minute = 0 , second = 0 , nanosecond = 0 )
2001
2013
Time .max = Time (hour = 23 , minute = 59 , second = 59 , nanosecond = 999999999 )
2002
2014
Time .resolution = Duration (nanoseconds = 1 )
@@ -2330,17 +2342,52 @@ def hour_minute_second_nanosecond(self):
2330
2342
2331
2343
# OPERATIONS #
2332
2344
2345
+ def _get_both_normalized (self , other , strict = True ):
2346
+ if (isinstance (other , (datetime , DateTime ))
2347
+ and ((self .utc_offset () is None )
2348
+ ^ (other .utcoffset () is None ))):
2349
+ if strict :
2350
+ raise TypeError ("can't compare offset-naive and offset-aware "
2351
+ "datetimes" )
2352
+ else :
2353
+ return None , None
2354
+ self_norm = self
2355
+ utc_offset = self .utc_offset ()
2356
+ if utc_offset is not None :
2357
+ self_norm -= utc_offset
2358
+ self_norm = self_norm .replace (tzinfo = None )
2359
+ other_norm = other
2360
+ if isinstance (other , (datetime , DateTime )):
2361
+ utc_offset = other .utcoffset ()
2362
+ if utc_offset is not None :
2363
+ other_norm -= utc_offset
2364
+ other_norm = other_norm .replace (tzinfo = None )
2365
+ else :
2366
+ return None , None
2367
+ return self_norm , other_norm
2368
+
2333
2369
def __hash__ (self ):
2334
2370
""""""
2335
- return hash (self .date ()) ^ hash (self .time ())
2371
+ if self .nanosecond % 1000 == 0 :
2372
+ return hash (self .to_native ())
2373
+ self_norm = self
2374
+ utc_offset = self .utc_offset ()
2375
+ if utc_offset is not None :
2376
+ self_norm -= utc_offset
2377
+ return hash (self_norm .date ()) ^ hash (self_norm .time ())
2336
2378
2337
2379
def __eq__ (self , other ):
2338
2380
"""
2339
2381
`==` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2340
2382
"""
2341
- if isinstance (other , (DateTime , datetime )):
2383
+ if not isinstance (other , (datetime , DateTime )):
2384
+ return NotImplemented
2385
+ if self .utc_offset () == other .utcoffset ():
2342
2386
return self .date () == other .date () and self .time () == other .time ()
2343
- return False
2387
+ self_norm , other_norm = self ._get_both_normalized (other , strict = False )
2388
+ if self_norm is None :
2389
+ return False
2390
+ return self_norm == other_norm
2344
2391
2345
2392
def __ne__ (self , other ):
2346
2393
"""
@@ -2352,45 +2399,55 @@ def __lt__(self, other):
2352
2399
"""
2353
2400
`<` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2354
2401
"""
2355
- if isinstance (other , (DateTime , datetime )):
2402
+ if not isinstance (other , (datetime , DateTime )):
2403
+ return NotImplemented
2404
+ if self .utc_offset () == other .utcoffset ():
2356
2405
if self .date () == other .date ():
2357
2406
return self .time () < other .time ()
2358
- else :
2359
- return self .date () < other .date ()
2360
- return NotImplemented
2407
+ return self .date () < other .date ()
2408
+ self_norm , other_norm = self ._get_both_normalized (other )
2409
+ return (self_norm .date () < other_norm .date ()
2410
+ or self_norm .time () < other_norm .time ())
2361
2411
2362
2412
def __le__ (self , other ):
2363
2413
"""
2364
2414
`<=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2365
2415
"""
2366
- if isinstance (other , (DateTime , datetime )):
2416
+ if not isinstance (other , (datetime , DateTime )):
2417
+ return NotImplemented
2418
+ if self .utc_offset () == other .utcoffset ():
2367
2419
if self .date () == other .date ():
2368
2420
return self .time () <= other .time ()
2369
- else :
2370
- return self .date () < other . date ( )
2371
- return NotImplemented
2421
+ return self . date () <= other . date ()
2422
+ self_norm , other_norm = self ._get_both_normalized ( other )
2423
+ return self_norm <= other_norm
2372
2424
2373
2425
def __ge__ (self , other ):
2374
2426
"""
2375
2427
`>=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2376
2428
"""
2377
- if isinstance (other , (DateTime , datetime )):
2429
+ if not isinstance (other , (datetime , DateTime )):
2430
+ return NotImplemented
2431
+ if self .utc_offset () == other .utcoffset ():
2378
2432
if self .date () == other .date ():
2379
2433
return self .time () >= other .time ()
2380
- else :
2381
- return self .date () > other . date ( )
2382
- return NotImplemented
2434
+ return self . date () >= other . date ()
2435
+ self_norm , other_norm = self ._get_both_normalized ( other )
2436
+ return self_norm >= other_norm
2383
2437
2384
2438
def __gt__ (self , other ):
2385
2439
"""
2386
2440
`>` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2387
2441
"""
2388
- if isinstance (other , (DateTime , datetime )):
2442
+ if not isinstance (other , (datetime , DateTime )):
2443
+ return NotImplemented
2444
+ if self .utc_offset () == other .utcoffset ():
2389
2445
if self .date () == other .date ():
2390
2446
return self .time () > other .time ()
2391
- else :
2392
- return self .date () > other .date ()
2393
- return NotImplemented
2447
+ return self .date () > other .date ()
2448
+ self_norm , other_norm = self ._get_both_normalized (other )
2449
+ return (self_norm .date () > other_norm .date ()
2450
+ or self_norm .time () > other_norm .time ())
2394
2451
2395
2452
def __add__ (self , other ):
2396
2453
"""Add a :class:`datetime.timedelta`.
@@ -2494,7 +2551,7 @@ def as_timezone(self, tz):
2494
2551
"""
2495
2552
if self .tzinfo is None :
2496
2553
return self
2497
- utc = (self - self .utcoffset ()).replace (tzinfo = tz )
2554
+ utc = (self - self .utc_offset ()).replace (tzinfo = tz )
2498
2555
return tz .fromutc (utc )
2499
2556
2500
2557
def utc_offset (self ):
@@ -2503,7 +2560,7 @@ def utc_offset(self):
2503
2560
See :meth:`.Time.utc_offset`.
2504
2561
"""
2505
2562
2506
- return self .__time .utc_offset ( )
2563
+ return self .__time ._utc_offset ( self )
2507
2564
2508
2565
def dst (self ):
2509
2566
"""Get the daylight saving time adjustment (DST).
0 commit comments