@@ -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