@@ -1657,73 +1657,81 @@ def tzinfo(self):
1657
1657
1658
1658
# OPERATIONS #
1659
1659
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
+
1660
1687
def __hash__ (self ):
1661
1688
""""""
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 )
1663
1695
1664
1696
def __eq__ (self , other ):
1665
1697
"""`==` 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
1675
1703
1676
1704
def __ne__ (self , other ):
1677
1705
"""`!=` comparison with :class:`.Time` or :class:`datetime.time`."""
1678
1706
return not self .__eq__ (other )
1679
1707
1680
1708
def __lt__ (self , other ):
1681
1709
"""`<` 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
1691
1714
1692
1715
def __le__ (self , other ):
1693
1716
"""`<=` 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
1703
1721
1704
1722
def __ge__ (self , other ):
1705
1723
"""`>=` 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
1715
1728
1716
1729
def __gt__ (self , other ):
1717
1730
"""`>` 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
1727
1735
1728
1736
def __copy__ (self ):
1729
1737
return self .__new (self .__ticks , self .__hour , self .__minute ,
@@ -1757,6 +1765,21 @@ def replace(self, **kwargs):
1757
1765
nanosecond = kwargs .get ("nanosecond" , self .__nanosecond ),
1758
1766
tzinfo = kwargs .get ("tzinfo" , self .__tzinfo ))
1759
1767
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
+
1760
1783
def utc_offset (self ):
1761
1784
"""Return the UTC offset of this time.
1762
1785
@@ -1770,19 +1793,7 @@ def utc_offset(self):
1770
1793
:raises TypeError: if `self.tzinfo.utcoffset(self)` does return anything but
1771
1794
None or a :class:`datetime.timedelta`.
1772
1795
"""
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 ()
1786
1797
1787
1798
def dst (self ):
1788
1799
"""Get the daylight saving time adjustment (DST).
@@ -2194,17 +2205,52 @@ def hour_minute_second_nanosecond(self):
2194
2205
2195
2206
# OPERATIONS #
2196
2207
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
+
2197
2232
def __hash__ (self ):
2198
2233
""""""
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 ())
2200
2241
2201
2242
def __eq__ (self , other ):
2202
2243
"""
2203
2244
`==` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2204
2245
"""
2205
- if isinstance (other , (DateTime , datetime )):
2246
+ if not isinstance (other , (datetime , DateTime )):
2247
+ return NotImplemented
2248
+ if self .utc_offset () == other .utcoffset ():
2206
2249
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
2208
2254
2209
2255
def __ne__ (self , other ):
2210
2256
"""
@@ -2216,45 +2262,55 @@ def __lt__(self, other):
2216
2262
"""
2217
2263
`<` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2218
2264
"""
2219
- if isinstance (other , (DateTime , datetime )):
2265
+ if not isinstance (other , (datetime , DateTime )):
2266
+ return NotImplemented
2267
+ if self .utc_offset () == other .utcoffset ():
2220
2268
if self .date () == other .date ():
2221
2269
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 ())
2225
2274
2226
2275
def __le__ (self , other ):
2227
2276
"""
2228
2277
`<=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2229
2278
"""
2230
- if isinstance (other , (DateTime , datetime )):
2279
+ if not isinstance (other , (datetime , DateTime )):
2280
+ return NotImplemented
2281
+ if self .utc_offset () == other .utcoffset ():
2231
2282
if self .date () == other .date ():
2232
2283
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
2236
2287
2237
2288
def __ge__ (self , other ):
2238
2289
"""
2239
2290
`>=` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2240
2291
"""
2241
- if isinstance (other , (DateTime , datetime )):
2292
+ if not isinstance (other , (datetime , DateTime )):
2293
+ return NotImplemented
2294
+ if self .utc_offset () == other .utcoffset ():
2242
2295
if self .date () == other .date ():
2243
2296
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
2247
2300
2248
2301
def __gt__ (self , other ):
2249
2302
"""
2250
2303
`>` comparison with :class:`.DateTime` or :class:`datetime.datetime`.
2251
2304
"""
2252
- if isinstance (other , (DateTime , datetime )):
2305
+ if not isinstance (other , (datetime , DateTime )):
2306
+ return NotImplemented
2307
+ if self .utc_offset () == other .utcoffset ():
2253
2308
if self .date () == other .date ():
2254
2309
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 ())
2258
2314
2259
2315
def __add__ (self , other ):
2260
2316
"""Add a :class:`datetime.timedelta`.
@@ -2358,7 +2414,7 @@ def as_timezone(self, tz):
2358
2414
"""
2359
2415
if self .tzinfo is None :
2360
2416
return self
2361
- utc = (self - self .utcoffset ()).replace (tzinfo = tz )
2417
+ utc = (self - self .utc_offset ()).replace (tzinfo = tz )
2362
2418
return tz .fromutc (utc )
2363
2419
2364
2420
def utc_offset (self ):
@@ -2367,7 +2423,7 @@ def utc_offset(self):
2367
2423
See :meth:`.Time.utc_offset`.
2368
2424
"""
2369
2425
2370
- return self .__time .utc_offset ( )
2426
+ return self .__time ._utc_offset ( self )
2371
2427
2372
2428
def dst (self ):
2373
2429
"""Get the daylight saving time adjustment (DST).
0 commit comments