@@ -1657,73 +1657,81 @@ def tzinfo(self):
16571657
16581658 # OPERATIONS #
16591659
1660+ def _get_both_normalized_ticks (self , other , strict = True ):
1661+ if (isinstance (other , (time , Time ))
1662+ and ((self .utc_offset () is None )
1663+ ^ (other .utcoffset () is None ))):
1664+ if strict :
1665+ raise TypeError ("can't compare offset-naive and offset-aware "
1666+ "times" )
1667+ else :
1668+ return None , None
1669+ if isinstance (other , Time ):
1670+ other_ticks = other .__ticks
1671+ elif isinstance (other , time ):
1672+ other_ticks = int (3600000000000 * other .hour
1673+ + 60000000000 * other .minute
1674+ + NANO_SECONDS * other .second
1675+ + 1000 * other .microsecond )
1676+ else :
1677+ return None , None
1678+ utc_offset = other .utcoffset ()
1679+ if utc_offset is not None :
1680+ other_ticks -= utc_offset .total_seconds () * NANO_SECONDS
1681+ self_ticks = self .__ticks
1682+ utc_offset = self .utc_offset ()
1683+ if utc_offset is not None :
1684+ self_ticks -= utc_offset .total_seconds () * NANO_SECONDS
1685+ return self_ticks , other_ticks
1686+
16601687 def __hash__ (self ):
16611688 """"""
1662- return hash (self .__ticks ) ^ hash (self .tzinfo )
1689+ if self .__nanosecond % 1000 == 0 :
1690+ return hash (self .to_native ())
1691+ self_ticks = self .__ticks
1692+ if self .utc_offset () is not None :
1693+ self_ticks -= self .utc_offset ().total_seconds () * NANO_SECONDS
1694+ return hash (self_ticks )
16631695
16641696 def __eq__ (self , other ):
16651697 """`==` comparison with :class:`.Time` or :class:`datetime.time`."""
1666- if isinstance (other , Time ):
1667- return self .__ticks == other .__ticks and self .tzinfo == other .tzinfo
1668- if isinstance (other , time ):
1669- other_ticks = (3600000000000 * other .hour
1670- + 60000000000 * other .minute
1671- + NANO_SECONDS * other .second
1672- + 1000 * other .microsecond )
1673- return self .ticks == other_ticks and self .tzinfo == other .tzinfo
1674- return False
1698+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other ,
1699+ strict = False )
1700+ if self_ticks is None :
1701+ return False
1702+ return self_ticks == other_ticks
16751703
16761704 def __ne__ (self , other ):
16771705 """`!=` comparison with :class:`.Time` or :class:`datetime.time`."""
16781706 return not self .__eq__ (other )
16791707
16801708 def __lt__ (self , other ):
16811709 """`<` comparison with :class:`.Time` or :class:`datetime.time`."""
1682- if isinstance (other , Time ):
1683- return (self .tzinfo == other .tzinfo
1684- and self .ticks < other .ticks )
1685- if isinstance (other , time ):
1686- if self .tzinfo != other .tzinfo :
1687- return False
1688- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1689- return self .ticks < other_ticks
1690- return NotImplemented
1710+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1711+ if self_ticks is None :
1712+ return NotImplemented
1713+ return self_ticks < other_ticks
16911714
16921715 def __le__ (self , other ):
16931716 """`<=` comparison with :class:`.Time` or :class:`datetime.time`."""
1694- if isinstance (other , Time ):
1695- return (self .tzinfo == other .tzinfo
1696- and self .ticks <= other .ticks )
1697- if isinstance (other , time ):
1698- if self .tzinfo != other .tzinfo :
1699- return False
1700- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1701- return self .ticks <= other_ticks
1702- return NotImplemented
1717+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1718+ if self_ticks is None :
1719+ return NotImplemented
1720+ return self_ticks <= other_ticks
17031721
17041722 def __ge__ (self , other ):
17051723 """`>=` comparison with :class:`.Time` or :class:`datetime.time`."""
1706- if isinstance (other , Time ):
1707- return (self .tzinfo == other .tzinfo
1708- and self .ticks >= other .ticks )
1709- if isinstance (other , time ):
1710- if self .tzinfo != other .tzinfo :
1711- return False
1712- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1713- return self .ticks >= other_ticks
1714- return NotImplemented
1724+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1725+ if self_ticks is None :
1726+ return NotImplemented
1727+ return self_ticks >= other_ticks
17151728
17161729 def __gt__ (self , other ):
17171730 """`>` comparison with :class:`.Time` or :class:`datetime.time`."""
1718- if isinstance (other , Time ):
1719- return (self .tzinfo == other .tzinfo
1720- and self .ticks >= other .ticks )
1721- if isinstance (other , time ):
1722- if self .tzinfo != other .tzinfo :
1723- return False
1724- other_ticks = 3600 * other .hour + 60 * other .minute + other .second + (other .microsecond / 1000000 )
1725- return self .ticks >= other_ticks
1726- return NotImplemented
1731+ self_ticks , other_ticks = self ._get_both_normalized_ticks (other )
1732+ if self_ticks is None :
1733+ return NotImplemented
1734+ return self_ticks > other_ticks
17271735
17281736 def __copy__ (self ):
17291737 return self .__new (self .__ticks , self .__hour , self .__minute ,
@@ -1757,6 +1765,21 @@ def replace(self, **kwargs):
17571765 nanosecond = kwargs .get ("nanosecond" , self .__nanosecond ),
17581766 tzinfo = kwargs .get ("tzinfo" , self .__tzinfo ))
17591767
1768+ def _utc_offset (self , dt = None ):
1769+ if self .tzinfo is None :
1770+ return None
1771+ value = self .tzinfo .utcoffset (dt )
1772+ if value is None :
1773+ return None
1774+ if isinstance (value , timedelta ):
1775+ s = value .total_seconds ()
1776+ if not (- 86400 < s < 86400 ):
1777+ raise ValueError ("utcoffset must be less than a day" )
1778+ if s % 60 != 0 or value .microseconds != 0 :
1779+ raise ValueError ("utcoffset must be a whole number of minutes" )
1780+ return value
1781+ raise TypeError ("utcoffset must be a timedelta" )
1782+
17601783 def utc_offset (self ):
17611784 """Return the UTC offset of this time.
17621785
@@ -1770,19 +1793,7 @@ def utc_offset(self):
17701793 :raises TypeError: if `self.tzinfo.utcoffset(self)` does return anything but
17711794 None or a :class:`datetime.timedelta`.
17721795 """
1773- if self .tzinfo is None :
1774- return None
1775- value = self .tzinfo .utcoffset (self )
1776- if value is None :
1777- return None
1778- if isinstance (value , timedelta ):
1779- s = value .total_seconds ()
1780- if not (- 86400 < s < 86400 ):
1781- raise ValueError ("utcoffset must be less than a day" )
1782- if s % 60 != 0 or value .microseconds != 0 :
1783- raise ValueError ("utcoffset must be a whole number of minutes" )
1784- return value
1785- raise TypeError ("utcoffset must be a timedelta" )
1796+ return self ._utc_offset ()
17861797
17871798 def dst (self ):
17881799 """Get the daylight saving time adjustment (DST).
@@ -2194,17 +2205,52 @@ def hour_minute_second_nanosecond(self):
21942205
21952206 # OPERATIONS #
21962207
2208+ def _get_both_normalized (self , other , strict = True ):
2209+ if (isinstance (other , (datetime , DateTime ))
2210+ and ((self .utc_offset () is None )
2211+ ^ (other .utcoffset () is None ))):
2212+ if strict :
2213+ raise TypeError ("can't compare offset-naive and offset-aware "
2214+ "datetimes" )
2215+ else :
2216+ return None , None
2217+ self_norm = self
2218+ utc_offset = self .utc_offset ()
2219+ if utc_offset is not None :
2220+ self_norm -= utc_offset
2221+ self_norm = self_norm .replace (tzinfo = None )
2222+ other_norm = other
2223+ if isinstance (other , (datetime , DateTime )):
2224+ utc_offset = other .utcoffset ()
2225+ if utc_offset is not None :
2226+ other_norm -= utc_offset
2227+ other_norm = other_norm .replace (tzinfo = None )
2228+ else :
2229+ return None , None
2230+ return self_norm , other_norm
2231+
21972232 def __hash__ (self ):
21982233 """"""
2199- return hash (self .date ()) ^ hash (self .time ())
2234+ if self .nanosecond % 1000 == 0 :
2235+ return hash (self .to_native ())
2236+ self_norm = self
2237+ utc_offset = self .utc_offset ()
2238+ if utc_offset is not None :
2239+ self_norm -= utc_offset
2240+ return hash (self_norm .date ()) ^ hash (self_norm .time ())
22002241
22012242 def __eq__ (self , other ):
22022243 """
22032244 `==` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
22042245 """
2205- if isinstance (other , (DateTime , datetime )):
2246+ if not isinstance (other , (datetime , DateTime )):
2247+ return NotImplemented
2248+ if self .utc_offset () == other .utcoffset ():
22062249 return self .date () == other .date () and self .time () == other .time ()
2207- return False
2250+ self_norm , other_norm = self ._get_both_normalized (other , strict = False )
2251+ if self_norm is None :
2252+ return False
2253+ return self_norm == other_norm
22082254
22092255 def __ne__ (self , other ):
22102256 """
@@ -2216,45 +2262,55 @@ def __lt__(self, other):
22162262 """
22172263 `<` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
22182264 """
2219- if isinstance (other , (DateTime , datetime )):
2265+ if not isinstance (other , (datetime , DateTime )):
2266+ return NotImplemented
2267+ if self .utc_offset () == other .utcoffset ():
22202268 if self .date () == other .date ():
22212269 return self .time () < other .time ()
2222- else :
2223- return self .date () < other .date ()
2224- return NotImplemented
2270+ return self .date () < other .date ()
2271+ self_norm , other_norm = self ._get_both_normalized (other )
2272+ return (self_norm .date () < other_norm .date ()
2273+ or self_norm .time () < other_norm .time ())
22252274
22262275 def __le__ (self , other ):
22272276 """
22282277 `<=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
22292278 """
2230- if isinstance (other , (DateTime , datetime )):
2279+ if not isinstance (other , (datetime , DateTime )):
2280+ return NotImplemented
2281+ if self .utc_offset () == other .utcoffset ():
22312282 if self .date () == other .date ():
22322283 return self .time () <= other .time ()
2233- else :
2234- return self .date () < other . date ( )
2235- return NotImplemented
2284+ return self . date () <= other . date ()
2285+ self_norm , other_norm = self ._get_both_normalized ( other )
2286+ return self_norm <= other_norm
22362287
22372288 def __ge__ (self , other ):
22382289 """
22392290 `>=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
22402291 """
2241- if isinstance (other , (DateTime , datetime )):
2292+ if not isinstance (other , (datetime , DateTime )):
2293+ return NotImplemented
2294+ if self .utc_offset () == other .utcoffset ():
22422295 if self .date () == other .date ():
22432296 return self .time () >= other .time ()
2244- else :
2245- return self .date () > other . date ( )
2246- return NotImplemented
2297+ return self . date () >= other . date ()
2298+ self_norm , other_norm = self ._get_both_normalized ( other )
2299+ return self_norm >= other_norm
22472300
22482301 def __gt__ (self , other ):
22492302 """
22502303 `>` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
22512304 """
2252- if isinstance (other , (DateTime , datetime )):
2305+ if not isinstance (other , (datetime , DateTime )):
2306+ return NotImplemented
2307+ if self .utc_offset () == other .utcoffset ():
22532308 if self .date () == other .date ():
22542309 return self .time () > other .time ()
2255- else :
2256- return self .date () > other .date ()
2257- return NotImplemented
2310+ return self .date () > other .date ()
2311+ self_norm , other_norm = self ._get_both_normalized (other )
2312+ return (self_norm .date () > other_norm .date ()
2313+ or self_norm .time () > other_norm .time ())
22582314
22592315 def __add__ (self , other ):
22602316 """Add a :class:`datetime.timedelta`.
@@ -2358,7 +2414,7 @@ def as_timezone(self, tz):
23582414 """
23592415 if self .tzinfo is None :
23602416 return self
2361- utc = (self - self .utcoffset ()).replace (tzinfo = tz )
2417+ utc = (self - self .utc_offset ()).replace (tzinfo = tz )
23622418 return tz .fromutc (utc )
23632419
23642420 def utc_offset (self ):
@@ -2367,7 +2423,7 @@ def utc_offset(self):
23672423 See :meth:`.Time.utc_offset`.
23682424 """
23692425
2370- return self .__time .utc_offset ( )
2426+ return self .__time ._utc_offset ( self )
23712427
23722428 def dst (self ):
23732429 """Get the daylight saving time adjustment (DST).
0 commit comments