27
27
datetime ,
28
28
time ,
29
29
timedelta ,
30
+ timezone ,
30
31
)
31
32
from functools import total_ordering
32
33
from re import compile as re_compile
@@ -778,7 +779,7 @@ def __getattr__(self, name):
778
779
def today (cls , tz = None ):
779
780
"""Get the current date.
780
781
781
- :param tz: timezone or None to get a local :class:`.Date`.
782
+ :param tz: timezone or None to get the local :class:`.Date`.
782
783
:type tz: datetime.tzinfo or None
783
784
784
785
:rtype: Date
@@ -790,11 +791,11 @@ def today(cls, tz=None):
790
791
if tz is None :
791
792
return cls .from_clock_time (Clock ().local_time (), UnixEpoch )
792
793
else :
793
- return tz . fromutc (
794
- DateTime .from_clock_time (
795
- Clock (). utc_time (), UnixEpoch
796
- ). replace ( tzinfo = tz )
797
- ). date ()
794
+ return (
795
+ DateTime .utc_now ()
796
+ . replace ( tzinfo = timezone . utc ). astimezone ( tz )
797
+ . date ( )
798
+ )
798
799
799
800
@classmethod
800
801
def utc_today (cls ):
@@ -819,14 +820,7 @@ def from_timestamp(cls, timestamp, tz=None):
819
820
supported by the platform C localtime() function. It’s common for
820
821
this to be restricted to years from 1970 through 2038.
821
822
"""
822
- if tz is None :
823
- return cls .from_clock_time (
824
- ClockTime (timestamp ) + Clock ().local_offset (), UnixEpoch
825
- )
826
- else :
827
- return tz .fromutc (
828
- DateTime .utc_from_timestamp (timestamp ).replace (tzinfo = tz )
829
- ).date ()
823
+ return cls .from_native (datetime .fromtimestamp (timestamp , tz ))
830
824
831
825
@classmethod
832
826
def utc_from_timestamp (cls , timestamp ):
@@ -1427,7 +1421,11 @@ def now(cls, tz=None):
1427
1421
if tz is None :
1428
1422
return cls .from_clock_time (Clock ().local_time (), UnixEpoch )
1429
1423
else :
1430
- return tz .fromutc (DateTime .from_clock_time (Clock ().utc_time (), UnixEpoch )).time ().replace (tzinfo = tz )
1424
+ return (
1425
+ DateTime .utc_now ()
1426
+ .replace (tzinfo = timezone .utc ).astimezone (tz )
1427
+ .timetz ()
1428
+ )
1431
1429
1432
1430
@classmethod
1433
1431
def utc_now (cls ):
@@ -1768,7 +1766,12 @@ def replace(self, **kwargs):
1768
1766
def _utc_offset (self , dt = None ):
1769
1767
if self .tzinfo is None :
1770
1768
return None
1771
- value = self .tzinfo .utcoffset (dt )
1769
+ try :
1770
+ value = self .tzinfo .utcoffset (dt )
1771
+ except TypeError :
1772
+ # For timezone implementations not compatible with the custom
1773
+ # datetime implementations, we can't do better than this.
1774
+ value = self .tzinfo .utcoffset (dt .to_native ())
1772
1775
if value is None :
1773
1776
return None
1774
1777
if isinstance (value , timedelta ):
@@ -1810,7 +1813,12 @@ def dst(self):
1810
1813
"""
1811
1814
if self .tzinfo is None :
1812
1815
return None
1813
- value = self .tzinfo .dst (self )
1816
+ try :
1817
+ value = self .tzinfo .dst (self )
1818
+ except TypeError :
1819
+ # For timezone implementations not compatible with the custom
1820
+ # datetime implementations, we can't do better than this.
1821
+ value = self .tzinfo .dst (self .to_native ())
1814
1822
if value is None :
1815
1823
return None
1816
1824
if isinstance (value , timedelta ):
@@ -1831,7 +1839,12 @@ def tzname(self):
1831
1839
"""
1832
1840
if self .tzinfo is None :
1833
1841
return None
1834
- return self .tzinfo .tzname (self )
1842
+ try :
1843
+ return self .tzinfo .tzname (self )
1844
+ except TypeError :
1845
+ # For timezone implementations not compatible with the custom
1846
+ # datetime implementations, we can't do better than this.
1847
+ return self .tzinfo .tzname (self .to_native ())
1835
1848
1836
1849
def to_clock_time (self ):
1837
1850
"""Convert to :class:`.ClockTime`.
@@ -1860,8 +1873,8 @@ def iso_format(self):
1860
1873
:rtype: str
1861
1874
"""
1862
1875
s = "%02d:%02d:%02d.%09d" % self .hour_minute_second_nanosecond
1863
- if self .tzinfo is not None :
1864
- offset = self . tzinfo . utcoffset ( self )
1876
+ offset = self .utc_offset ()
1877
+ if offset is not None :
1865
1878
s += "%+03d:%02d" % divmod (offset .total_seconds () // 60 , 60 )
1866
1879
return s
1867
1880
@@ -1970,9 +1983,24 @@ def now(cls, tz=None):
1970
1983
if tz is None :
1971
1984
return cls .from_clock_time (Clock ().local_time (), UnixEpoch )
1972
1985
else :
1973
- return tz .fromutc (cls .from_clock_time (
1974
- Clock ().utc_time (), UnixEpoch
1975
- ).replace (tzinfo = tz ))
1986
+ try :
1987
+ return tz .fromutc (cls .from_clock_time (
1988
+ Clock ().utc_time (), UnixEpoch
1989
+ ).replace (tzinfo = tz ))
1990
+ except TypeError :
1991
+ # For timezone implementations not compatible with the custom
1992
+ # datetime implementations, we can't do better than this.
1993
+ utc_now = cls .from_clock_time (
1994
+ Clock ().utc_time (), UnixEpoch
1995
+ )
1996
+ utc_now_native = utc_now .to_native ()
1997
+ now_native = tz .fromutc (utc_now_native )
1998
+ now = cls .from_native (now_native )
1999
+ return now .replace (
2000
+ nanosecond = (now .nanosecond
2001
+ + utc_now .nanosecond
2002
+ - utc_now_native .microsecond * 1000 )
2003
+ )
1976
2004
1977
2005
@classmethod
1978
2006
def utc_now (cls ):
@@ -2019,8 +2047,9 @@ def from_timestamp(cls, timestamp, tz=None):
2019
2047
ClockTime (timestamp ) + Clock ().local_offset (), UnixEpoch
2020
2048
)
2021
2049
else :
2022
- return tz .fromutc (
2023
- cls .utc_from_timestamp (timestamp ).replace (tzinfo = tz )
2050
+ return (
2051
+ cls .utc_from_timestamp (timestamp )
2052
+ .replace (tzinfo = timezone .utc ).astimezone (tz )
2024
2053
)
2025
2054
2026
2055
@classmethod
@@ -2326,7 +2355,15 @@ def __add__(self, other):
2326
2355
time_ = Time .from_ticks (round_half_to_even (
2327
2356
seconds * NANO_SECONDS + t .nanoseconds
2328
2357
))
2329
- return self .combine (date_ , time_ )
2358
+ return self .combine (date_ , time_ ).replace (tzinfo = self .tzinfo )
2359
+ if isinstance (other , Duration ):
2360
+ t = (self .to_clock_time ()
2361
+ + ClockTime (other .seconds , other .nanoseconds ))
2362
+ days , seconds = symmetric_divmod (t .seconds , 86400 )
2363
+ date_ = self .date () + Duration (months = other .months ,
2364
+ days = days + other .days )
2365
+ time_ = Time .from_ticks (seconds * NANO_SECONDS + t .nanoseconds )
2366
+ return self .combine (date_ , time_ ).replace (tzinfo = self .tzinfo )
2330
2367
return NotImplemented
2331
2368
2332
2369
def __sub__ (self , other ):
@@ -2356,7 +2393,7 @@ def __sub__(self, other):
2356
2393
return timedelta (days = days , seconds = t .seconds ,
2357
2394
microseconds = (t .nanoseconds // 1000 ))
2358
2395
if isinstance (other , Duration ):
2359
- return NotImplemented
2396
+ return self . __add__ ( - other )
2360
2397
if isinstance (other , timedelta ):
2361
2398
return self .__add__ (- other )
2362
2399
return NotImplemented
@@ -2415,7 +2452,18 @@ def as_timezone(self, tz):
2415
2452
if self .tzinfo is None :
2416
2453
return self
2417
2454
utc = (self - self .utc_offset ()).replace (tzinfo = tz )
2418
- return tz .fromutc (utc )
2455
+ try :
2456
+ return tz .fromutc (utc )
2457
+ except TypeError :
2458
+ # For timezone implementations not compatible with the custom
2459
+ # datetime implementations, we can't do better than this.
2460
+ native_utc = utc .to_native ()
2461
+ native_res = tz .fromutc (native_utc )
2462
+ res = self .from_native (native_res )
2463
+ return res .replace (
2464
+ nanosecond = (native_res .microsecond * 1000
2465
+ + self .nanosecond % 1000 )
2466
+ )
2419
2467
2420
2468
def utc_offset (self ):
2421
2469
"""Get the date times utc offset.
@@ -2513,8 +2561,17 @@ def iso_format(self, sep="T"):
2513
2561
2514
2562
:rtype: str
2515
2563
"""
2516
- return "%s%s%s" % (self .date ().iso_format (), sep ,
2517
- self .timetz ().iso_format ())
2564
+ s = "%s%s%s" % (self .date ().iso_format (), sep ,
2565
+ self .timetz ().iso_format ())
2566
+ time_tz = self .timetz ()
2567
+ offset = time_tz .utc_offset ()
2568
+ if offset is not None :
2569
+ # the time component will have taken care of formatting the offset
2570
+ return s
2571
+ offset = self .utc_offset ()
2572
+ if offset is not None :
2573
+ s += "%+03d:%02d" % divmod (offset .total_seconds () // 60 , 60 )
2574
+ return s
2518
2575
2519
2576
def __repr__ (self ):
2520
2577
""""""
0 commit comments