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

仿真时间戳

对实现分布式仿真而言,我们需要:

  1. 一个数字表示时间戳;
  2. 本地能够提供一个按照时区的时间表示。
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 微秒。

结论

  1. datetime是时间的表示与计算;
  2. time是时间的获取;
  3. timezone是时区的操作。
  4. Python时间戳的精度是微秒(windows/linux)。
posted @ 2023-04-24 18:28  大福是小强  阅读(26)  评论(0编辑  收藏  举报  来源