getmtime() 对比 datetime.now():

getmtime() vs datetime.now():

此代码每年在时钟转换的晚上(欧洲中部夏令时到欧洲中部时间)打印一次错误警告:

import os
import datetime

now = datetime.datetime.now()
age = now - datetime.datetime.fromtimestamp(os.path.getmtime(file_name))
if (age.seconds + age.days * 24 * 3600) < -180:
    print('WARN: file has timestap from future?: %s' % age)

如何使此代码即使在每年一小时的时钟转换期间也能正常工作?

更新

我只关心年龄,不关心日期时间。

您的两个日期时间对象都是 'naive',这意味着它们不知道 DST。 datetime.now() returns 您机器的当前运行时间,可能包括 DST。 datetime.fromtimestamp(os.path.getmtime()).

也是如此

#1 - 本地化日期时间对象可能是一种选择;像

from datetime import datetime
import tzlocal
now_aware = tzlocal.get_localzone().localize(datetime.now())
file_mtime = datetime.fromtimestamp(os.path.getmtime(file))
# assuming the file was created on a machine in the same timezone (!):
file_mtime_aware = now_aware.tzinfo.localize(file_mtime)
age = now_aware - file_mtime_aware

#2 - 另一种选择,使用 UTC 转换 datetime:

now = datetime.utcnow()
age = now - datetime.utcfromtimestamp(os.path.getmtime(file_name))
if (age.seconds + age.days * 24 * 3600) < -180:
    print(f'WARN: file has timestamp from future?: {age} s')

#3 - points out in his answer, os.path.getmtime returns a UTC timestamp (check os module docs and time module docs)。因此,最简单的解决方案可能是首先跳过转换为 datetime 并仅使用 UTC 时间戳;例如获取当前 UTC 时间戳 time.time().

使用时区可能会让您发疯...但是那里有一些很好的资源,例如this medium post.

通过从本地时间切换到 UTC 时间,可以轻松改进发布的片段。 UTC 中没有夏令时(夏令时)时间变化。只需替换这两个日期时间函数 now() -> utcnow() (docs) and fromtimestamp() -> utcfromtimestamp() (docs).

但是,如果唯一的预期输出是以秒为单位的文件年龄,我们可以直接使用时间戳(来自 "epoch" 的秒数)而不进行任何转换:

import time
import os.path

...
age = time.time() - os.path.getmtime(file_name)

你的问题是你在没有时区意识的情况下得到你的时间。因此,当时钟发生变化时,您结束比较时钟变化之前的一个时间戳和时钟变化之后的另一个时间戳,而您的代码看不到这一点。

您应该让您的日期时间对象基于特定的时区,这样您就不会遇到时钟更改的问题,我建议使用 pytz 模块来帮助您解决这个问题。您可以在此答案中查看可用时区列表:Is there a list of Pytz Timezones?

这是一个简单的代码示例,说明如何使用时区感知对象执行此操作:

import os
from datetime import datetime
import pytz


def get_datetime_now(timezone):
    """
    Returns timezone aware datetime object for right now
    """
    if timezone not in pytz.all_timezones:
        return None
    tz = pytz.timezone(timezone)
    dt = datetime.now().astimezone()
    return dt.astimezone(tz)


def timestamp_to_datetime(timestamp, timezone):
    """
    Returns a datetime object from a timestamp
    """
    if timezone not in pytz.all_timezones:
        return None
    tz = pytz.timezone(timezone)
    dt = datetime.fromtimestamp(timestamp).astimezone()
    return dt.astimezone(tz)


timezone = 'CET'

file_timestamp = os.path.getmtime(file_name)

now = get_datetime_now(timezone)
file_datetime = timestamp_to_datetime(file_timestamp, timezone)
age = now - file_datetime

if (age.seconds + age.days * 24 * 3600) < -180:
    print('WARN: file has timestap from future?: %s' % age)