@@ -1783,73 +1783,81 @@ def tzinfo(self):
17831783
17841784 # OPERATIONS #
17851785
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+
17861813 def __hash__ (self ):
17871814 """"""
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 )
17891821
17901822 def __eq__ (self , other ):
17911823 """`==` 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
18011829
18021830 def __ne__ (self , other ):
18031831 """`!=` comparison with :class:`.Time` or :class:`datetime.time`."""
18041832 return not self .__eq__ (other )
18051833
18061834 def __lt__ (self , other ):
18071835 """`<` 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
18171840
18181841 def __le__ (self , other ):
18191842 """`<=` 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
18291847
18301848 def __ge__ (self , other ):
18311849 """`>=` 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
18411854
18421855 def __gt__ (self , other ):
18431856 """`>` 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
18531861
18541862 def __copy__ (self ):
18551863 return self .__new (self .__ticks , self .__hour , self .__minute ,
@@ -1883,6 +1891,21 @@ def replace(self, **kwargs):
18831891 nanosecond = kwargs .get ("nanosecond" , self .__nanosecond ),
18841892 tzinfo = kwargs .get ("tzinfo" , self .__tzinfo ))
18851893
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+
18861909 def utc_offset (self ):
18871910 """Return the UTC offset of this time.
18881911
@@ -1896,19 +1919,7 @@ def utc_offset(self):
18961919 :raises TypeError: if `self.tzinfo.utcoffset(self)` does return anything but
18971920 None or a :class:`datetime.timedelta`.
18981921 """
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 ()
19121923
19131924 def dst (self ):
19141925 """Get the daylight saving time adjustment (DST).
@@ -1997,6 +2008,7 @@ def __format__(self, format_spec):
19972008 """"""
19982009 raise NotImplementedError ()
19992010
2011+
20002012Time .min = Time (hour = 0 , minute = 0 , second = 0 , nanosecond = 0 )
20012013Time .max = Time (hour = 23 , minute = 59 , second = 59 , nanosecond = 999999999 )
20022014Time .resolution = Duration (nanoseconds = 1 )
@@ -2330,17 +2342,52 @@ def hour_minute_second_nanosecond(self):
23302342
23312343 # OPERATIONS #
23322344
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+
23332369 def __hash__ (self ):
23342370 """"""
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 ())
23362378
23372379 def __eq__ (self , other ):
23382380 """
23392381 `==` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
23402382 """
2341- if isinstance (other , (DateTime , datetime )):
2383+ if not isinstance (other , (datetime , DateTime )):
2384+ return NotImplemented
2385+ if self .utc_offset () == other .utcoffset ():
23422386 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
23442391
23452392 def __ne__ (self , other ):
23462393 """
@@ -2352,45 +2399,55 @@ def __lt__(self, other):
23522399 """
23532400 `<` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
23542401 """
2355- if isinstance (other , (DateTime , datetime )):
2402+ if not isinstance (other , (datetime , DateTime )):
2403+ return NotImplemented
2404+ if self .utc_offset () == other .utcoffset ():
23562405 if self .date () == other .date ():
23572406 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 ())
23612411
23622412 def __le__ (self , other ):
23632413 """
23642414 `<=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
23652415 """
2366- if isinstance (other , (DateTime , datetime )):
2416+ if not isinstance (other , (datetime , DateTime )):
2417+ return NotImplemented
2418+ if self .utc_offset () == other .utcoffset ():
23672419 if self .date () == other .date ():
23682420 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
23722424
23732425 def __ge__ (self , other ):
23742426 """
23752427 `>=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
23762428 """
2377- if isinstance (other , (DateTime , datetime )):
2429+ if not isinstance (other , (datetime , DateTime )):
2430+ return NotImplemented
2431+ if self .utc_offset () == other .utcoffset ():
23782432 if self .date () == other .date ():
23792433 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
23832437
23842438 def __gt__ (self , other ):
23852439 """
23862440 `>` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
23872441 """
2388- if isinstance (other , (DateTime , datetime )):
2442+ if not isinstance (other , (datetime , DateTime )):
2443+ return NotImplemented
2444+ if self .utc_offset () == other .utcoffset ():
23892445 if self .date () == other .date ():
23902446 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 ())
23942451
23952452 def __add__ (self , other ):
23962453 """Add a :class:`datetime.timedelta`.
@@ -2494,7 +2551,7 @@ def as_timezone(self, tz):
24942551 """
24952552 if self .tzinfo is None :
24962553 return self
2497- utc = (self - self .utcoffset ()).replace (tzinfo = tz )
2554+ utc = (self - self .utc_offset ()).replace (tzinfo = tz )
24982555 return tz .fromutc (utc )
24992556
25002557 def utc_offset (self ):
@@ -2503,7 +2560,7 @@ def utc_offset(self):
25032560 See :meth:`.Time.utc_offset`.
25042561 """
25052562
2506- return self .__time .utc_offset ( )
2563+ return self .__time ._utc_offset ( self )
25072564
25082565 def dst (self ):
25092566 """Get the daylight saving time adjustment (DST).
0 commit comments