Skip to content

Commit 3de498e

Browse files
committed
add nanosecond
1 parent 049a7dd commit 3de498e

File tree

1 file changed

+43
-30
lines changed

1 file changed

+43
-30
lines changed

Lib/_pydatetime.py

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,14 @@ def _build_struct_time(y, m, d, hh, mm, ss, dstflag):
161161
dnum = _days_before_month(y, m) + d
162162
return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag))
163163

164-
def _format_time(hh, mm, ss, us, timespec='auto'):
164+
def _format_time(hh, mm, ss, us, sus, timespec='auto'):
165165
specs = {
166166
'hours': '{:02d}',
167167
'minutes': '{:02d}:{:02d}',
168168
'seconds': '{:02d}:{:02d}:{:02d}',
169169
'milliseconds': '{:02d}:{:02d}:{:02d}.{:03d}',
170-
'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}'
170+
'microseconds': '{:02d}:{:02d}:{:02d}.{:06d}',
171+
'submicroseconds': '{:02d}:{:02d}:{:02d}.{:06d}{:03d}',
171172
}
172173

173174
if timespec == 'auto':
@@ -180,7 +181,7 @@ def _format_time(hh, mm, ss, us, timespec='auto'):
180181
except KeyError:
181182
raise ValueError('Unknown timespec value')
182183
else:
183-
return fmt.format(hh, mm, ss, us)
184+
return fmt.format(hh, mm, ss, us, sus)
184185

185186
def _format_offset(off, sep=':'):
186187
s = ''
@@ -578,11 +579,12 @@ def _check_date_fields(year, month, day):
578579
raise ValueError('day must be in 1..%d' % dim, day)
579580
return year, month, day
580581

581-
def _check_time_fields(hour, minute, second, microsecond, fold):
582+
def _check_time_fields(hour, minute, second, microsecond, submicrosecond, fold):
582583
hour = _index(hour)
583584
minute = _index(minute)
584585
second = _index(second)
585586
microsecond = _index(microsecond)
587+
submicrosecond = _index(submicrosecond)
586588
if not 0 <= hour <= 23:
587589
raise ValueError('hour must be in 0..23', hour)
588590
if not 0 <= minute <= 59:
@@ -591,9 +593,11 @@ def _check_time_fields(hour, minute, second, microsecond, fold):
591593
raise ValueError('second must be in 0..59', second)
592594
if not 0 <= microsecond <= 999999:
593595
raise ValueError('microsecond must be in 0..999999', microsecond)
596+
if not 0 <= submicrosecond <= 999:
597+
raise ValueError('Currently submicrosecond must be in 0..999', submicrosecond)
594598
if fold not in (0, 1):
595599
raise ValueError('fold must be either 0 or 1', fold)
596-
return hour, minute, second, microsecond, fold
600+
return hour, minute, second, microsecond, submicrosecond, fold
597601

598602
def _check_tzinfo_arg(tz):
599603
if tz is not None and not isinstance(tz, tzinfo):
@@ -1350,7 +1354,15 @@ def __reduce__(self):
13501354
args = getinitargs()
13511355
else:
13521356
args = ()
1353-
return (self.__class__, args, self.__getstate__())
1357+
getstate = getattr(self, "__getstate__", None)
1358+
if getstate:
1359+
state = getstate()
1360+
else:
1361+
state = getattr(self, "__dict__", None)
1362+
if state is None:
1363+
return (self.__class__, args)
1364+
else:
1365+
return (self.__class__, args, state)
13541366

13551367

13561368
class IsoCalendarDate(tuple):
@@ -1408,9 +1420,9 @@ class time:
14081420
Properties (readonly):
14091421
hour, minute, second, microsecond, tzinfo, fold
14101422
"""
1411-
__slots__ = '_hour', '_minute', '_second', '_microsecond', '_tzinfo', '_hashcode', '_fold'
1423+
__slots__ = '_hour', '_minute', '_second', '_microsecond', '_submicrosecond', '_tzinfo', '_hashcode', '_fold'
14121424

1413-
def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
1425+
def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0, submicrosecond=0):
14141426
"""Constructor.
14151427
14161428
Arguments:
@@ -1436,14 +1448,15 @@ def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold
14361448
self.__setstate(hour, minute or None)
14371449
self._hashcode = -1
14381450
return self
1439-
hour, minute, second, microsecond, fold = _check_time_fields(
1440-
hour, minute, second, microsecond, fold)
1451+
hour, minute, second, microsecond, submicrosecond, fold = _check_time_fields(
1452+
hour, minute, second, microsecond, submicrosecond, fold)
14411453
_check_tzinfo_arg(tzinfo)
14421454
self = object.__new__(cls)
14431455
self._hour = hour
14441456
self._minute = minute
14451457
self._second = second
14461458
self._microsecond = microsecond
1459+
self._submicrosecond = submicrosecond
14471460
self._tzinfo = tzinfo
14481461
self._hashcode = -1
14491462
self._fold = fold
@@ -1476,6 +1489,11 @@ def microsecond(self):
14761489
"""microsecond (0-999999)"""
14771490
return self._microsecond
14781491

1492+
@property
1493+
def submicrosecond(self):
1494+
"""submicrosecond (0-999)"""
1495+
return self._submicrosecond
1496+
14791497
@property
14801498
def tzinfo(self):
14811499
"""timezone info object"""
@@ -1563,9 +1581,9 @@ def __hash__(self):
15631581
assert not m % timedelta(minutes=1), "whole minute"
15641582
m //= timedelta(minutes=1)
15651583
if 0 <= h < 24:
1566-
self._hashcode = hash(time(h, m, self.second, self.microsecond))
1584+
self._hashcode = hash(time(h, m, self.second, self.microsecond, self.submicrosecond))
15671585
else:
1568-
self._hashcode = hash((h, m, self.second, self.microsecond))
1586+
self._hashcode = hash((h, m, self.second, self.microsecond, self.submicrosecond))
15691587
return self._hashcode
15701588

15711589
# Conversion to string
@@ -1605,7 +1623,7 @@ def isoformat(self, timespec='auto'):
16051623
'minutes', 'seconds', 'milliseconds' and 'microseconds'.
16061624
"""
16071625
s = _format_time(self._hour, self._minute, self._second,
1608-
self._microsecond, timespec)
1626+
self._microsecond, self._submicrosecond, timespec)
16091627
tz = self._tzstr()
16101628
if tz:
16111629
s += tz
@@ -1755,7 +1773,7 @@ class datetime(date):
17551773
__slots__ = time.__slots__
17561774

17571775
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
1758-
microsecond=0, tzinfo=None, *, fold=0):
1776+
microsecond=0, tzinfo=None, *, fold=0, submicrosecond=0):
17591777
if (isinstance(year, (bytes, str)) and len(year) == 10 and
17601778
1 <= ord(year[2:3])&0x7F <= 12):
17611779
# Pickle support
@@ -1773,8 +1791,8 @@ def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
17731791
self._hashcode = -1
17741792
return self
17751793
year, month, day = _check_date_fields(year, month, day)
1776-
hour, minute, second, microsecond, fold = _check_time_fields(
1777-
hour, minute, second, microsecond, fold)
1794+
hour, minute, second, microsecond, submicrosecond, fold = _check_time_fields(
1795+
hour, minute, second, microsecond, submicrosecond, fold)
17781796
_check_tzinfo_arg(tzinfo)
17791797
self = object.__new__(cls)
17801798
self._year = year
@@ -1784,6 +1802,7 @@ def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
17841802
self._minute = minute
17851803
self._second = second
17861804
self._microsecond = microsecond
1805+
self._submicrosecond = submicrosecond
17871806
self._tzinfo = tzinfo
17881807
self._hashcode = -1
17891808
self._fold = fold
@@ -1825,19 +1844,13 @@ def _fromtimestamp(cls, t, utc, tz):
18251844
18261845
A timezone info object may be passed in as well.
18271846
"""
1828-
frac, t = _math.modf(t)
1829-
us = round(frac * 1e6)
1830-
if us >= 1000000:
1831-
t += 1
1832-
us -= 1000000
1833-
elif us < 0:
1834-
t -= 1
1835-
us += 1000000
18361847

1848+
t = str(t)
1849+
t, us, sus = map(int, [t[:-9], t[-9:-3], t[-3:]])
18371850
converter = _time.gmtime if utc else _time.localtime
18381851
y, m, d, hh, mm, ss, weekday, jday, dst = converter(t)
18391852
ss = min(ss, 59) # clamp out leap seconds if the platform has them
1840-
result = cls(y, m, d, hh, mm, ss, us, tz)
1853+
result = cls(y, m, d, hh, mm, ss, us, tz, submicrosecond=sus)
18411854
if tz is None and not utc:
18421855
# As of version 2015f max fold in IANA database is
18431856
# 23 hours at 1969-09-30 13:00:00 in Kwajalein.
@@ -1852,11 +1865,11 @@ def _fromtimestamp(cls, t, utc, tz):
18521865
return result
18531866

18541867
y, m, d, hh, mm, ss = converter(t - max_fold_seconds)[:6]
1855-
probe1 = cls(y, m, d, hh, mm, ss, us, tz)
1868+
probe1 = cls(y, m, d, hh, mm, ss, us, tz, submicrosecond=sus)
18561869
trans = result - probe1 - timedelta(0, max_fold_seconds)
18571870
if trans.days < 0:
18581871
y, m, d, hh, mm, ss = converter(t + trans // timedelta(0, 1))[:6]
1859-
probe2 = cls(y, m, d, hh, mm, ss, us, tz)
1872+
probe2 = cls(y, m, d, hh, mm, ss, us, tz, submicrosecond=sus)
18601873
if probe2 == result:
18611874
result._fold = 1
18621875
elif tz is not None:
@@ -1888,7 +1901,7 @@ def utcfromtimestamp(cls, t):
18881901
@classmethod
18891902
def now(cls, tz=None):
18901903
"Construct a datetime from time.time() and optional time zone info."
1891-
t = _time.time()
1904+
t = _time.time_ns()
18921905
return cls.fromtimestamp(t, tz)
18931906

18941907
@classmethod
@@ -1901,7 +1914,7 @@ def utcnow(cls):
19011914
"datetime.datetime.now(datetime.UTC).",
19021915
DeprecationWarning,
19031916
stacklevel=2)
1904-
t = _time.time()
1917+
t = _time.time_ns()
19051918
return cls._fromtimestamp(t, True, None)
19061919

19071920
@classmethod
@@ -2142,7 +2155,7 @@ def isoformat(self, sep='T', timespec='auto'):
21422155
"""
21432156
s = ("%04d-%02d-%02d%c" % (self._year, self._month, self._day, sep) +
21442157
_format_time(self._hour, self._minute, self._second,
2145-
self._microsecond, timespec))
2158+
self._microsecond, self._submicrosecond, timespec))
21462159

21472160
off = self.utcoffset()
21482161
tz = _format_offset(off)

0 commit comments

Comments
 (0)