Python仿真时间戳的实现
Python中的时间相关的包
在Python中实现时间戳的功能,与Java/Kotlin的结果类似,但是Python中的时间和日期功能分散在几个包中,而且有些包的功能重叠,这里做一个总结。
datetime:时间的表示与计算
这个包里定义tzinfo
类,用于表示时区信息,但是这个类是抽象类,需要自己实现。
class tzinfo:
@abstractmethod
def tzname(self, __dt: datetime | None) -> str | None: ...
@abstractmethod
def utcoffset(self, __dt: datetime | None) -> timedelta | None: ...
@abstractmethod
def dst(self, __dt: datetime | None) -> timedelta | None: ...
def fromutc(self, __dt: datetime) -> datetime: ...
tzinfo
的类层次结构如下:
import datetime
def print_tree(parent_cls, level: int = 0):
print('\t' * level, parent_cls)
for cls in parent_cls.__subclasses__():
print_tree(cls, level + 1)
print_tree(datetime.tzinfo)
<class 'datetime.tzinfo'>
<class 'datetime.timezone'>
<class 'dateutil.tz._common._tzinfo'>
<class 'dateutil.tz._common.tzrangebase'>
<class 'dateutil.tz.win.tzwinbase'>
<class 'dateutil.tz.win.tzwin'>
<class 'dateutil.tz.win.tzwinlocal'>
<class 'dateutil.tz.tz.tzrange'>
<class 'dateutil.tz.tz.tzstr'>
<class 'dateutil.tz.tz.tzlocal'>
<class 'dateutil.tz.tz.tzfile'>
<class 'dateutil.tz.tz._tzicalvtz'>
<class 'dateutil.tz.tz.tzutc'>
<class 'dateutil.tz.tz.tzoffset'>
<class 'zoneinfo.ZoneInfo'>
now()
从datetime的源代码中可以看到,类方法now()
方法调用的是time.time()
,然后再调用fromtimestamp()
方法。
import time as _time
# ......
class datetime(date):
# ......
@classmethod
def now(cls, tz=None):
"Construct a datetime from time.time() and optional time zone info."
t = _time.time()
return cls.fromtimestamp(t, tz)
这一下子就跑到time
模块。
timezone:时区相关的操作
PEP 615 – Support for the IANA Time Zone Database in the Standard Library,这个PEP提出了Python标准库中支持IANA时区数据库的需求,目前已经被接受,在Python 3.9中已经实现。
import zoneinfo
tz = zoneinfo.ZoneInfo("America/New_York")
ltz = zoneinfo.ZoneInfo("Asia/Chongqing")
now = datetime.datetime.now(ltz)
d = datetime.datetime.fromtimestamp(now.timestamp(), tz)
print(now, now.timestamp(), d, d.timestamp(), sep="\n")
2023-04-24 18:03:13.258219+08:00
1682330593.258219
2023-04-24 06:03:13.258219-04:00
1682330593.258219
仿真时间戳
对实现分布式仿真而言,我们需要:
- 一个数字表示时间戳;
- 本地能够提供一个按照时区的时间表示。
def timestamp_int64():
return int(datetime.datetime.now().timestamp() * 1e6)
print(timestamp_int64())
def local_time(ts_int, tz=zoneinfo.ZoneInfo("Asia/Chongqing")):
return datetime.datetime.fromtimestamp(ts_int / 1e6, tz)
print(local_time(timestamp_int64()))
import timeit
t = timeit.timeit(timestamp_int64, number=1000000)
print(f"获取时间戳的平均时间:{t:>10.3f} 微秒。")
1682331774518957
2023-04-24 18:22:54.518957+08:00
获取时间戳的平均时间: 0.508 微秒。
结论
- datetime是时间的表示与计算;
- time是时间的获取;
- timezone是时区的操作。
- Python时间戳的精度是微秒(windows/linux)。