getmtime () против datetime.now (): - PullRequest
       54

getmtime () против datetime.now ():

8 голосов
/ 28 октября 2019

Этот код печатает ложное предупреждение один раз в год, в ночь смены часов (летнее время из центральной Европы в центральноевропейское):

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)

Как заставить этот код работать даже в течение этого ежегодногочасовая смена?

Обновление

Я забочусь только о возрасте, а не о дате и времени.

Ответы [ 3 ]

6 голосов
/ 01 ноября 2019

Размещенный фрагмент может быть легко улучшен путем переключения с местного времени на UTC. В UTC нет изменений летнего (летнего) времени. Просто замените эти две функции даты и времени now() -> utcnow() ( документы ) и fromtimestamp() -> utcfromtimestamp() ( документы ).

Однако,если единственным ожидаемым результатом является возраст файла в секундах, мы можем напрямую использовать временные метки (секунды из «эпохи») без преобразования:

import time
import os.path

...
age = time.time() - os.path.getmtime(file_name)
3 голосов
/ 28 октября 2019

оба ваших объекта даты и времени являются «наивными», что означает, что они не знают о летнем времени. datetime.now() возвращает текущее время работы вашей машины, которое может включать DST. То же самое касается datetime.fromtimestamp(os.path.getmtime()).

# 1 - локализация ваших объектов datetime может быть вариантом;что-то вроде

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 - как VPfB указывает в своем ответе, os.path.getmtime возвращает метку времени UTC (проверьте документы по модулю и документы по модулю ). Таким образом, самое простое решение - пропустить преобразование в datetime и использовать только метки времени UTC;например, получение текущей метки времени UTC как time.time().

Работа с часовыми поясами может свести вас с ума ... но есть некоторые хорошие ресурсы, например, этот средний пост .

1 голос
/ 05 ноября 2019

Ваша проблема в том, что вы тратите свое время без учета часового пояса. Поэтому, когда часы меняются, вы заканчиваете сравнивать одну временную метку, которая была до смены часов, и другую, которая находится после смены часов, и ваш код этого не видит.

Вместо этого вы должны получить свои объекты даты и времени на основев определенном часовом поясе, чтобы у вас не было проблем с изменением часов, я рекомендую использовать модуль pytz, чтобы помочь вам в этом. Вы можете увидеть список доступных часовых поясов в этом ответе: Есть ли список часовых поясов Pytz?

Вот простой пример кода того, как вы можете сделать это с объектами, поддерживающими часовой пояс:

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)
...