getmtime () so với datetime.now ():


8

Mã này in một cảnh báo sai một lần mỗi năm, vào đêm của sự thay đổi đồng hồ (thời gian mùa hè trung tâm châu Âu sang trung tâm châu Âu):

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)

Làm thế nào để làm cho mã này hoạt động ngay cả trong suốt một giờ đồng hồ hàng năm này?

Cập nhật

Tôi chỉ quan tâm đến tuổi, không phải thời gian.

Câu trả lời:


6

Đoạn được đăng có thể dễ dàng cải thiện bằng cách chuyển từ thời gian cục bộ sang thời gian UTC. Không có thay đổi thời gian mùa hè (tiết kiệm ánh sáng ban ngày) trong UTC. Chỉ cần thay thế hai hàm datetime này now()-> utcnow()( docs ) và fromtimestamp()-> utcfromtimestamp()( docs ).

Tuy nhiên, nếu đầu ra dự kiến ​​duy nhất là tuổi tập tin tính bằng giây, chúng ta có thể trực tiếp sử dụng dấu thời gian (giây từ "epoch") mà không cần chuyển đổi:

import time
import os.path

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

3
Sử dụng UTC ở nơi đầu tiên là cách tiếp cận đúng đắn.
konstantin

@konstantin tại sao là cách tiếp cận righ? Tôi thích giải pháp đơn giản này, vì tôi (trong bối cảnh này) chỉ quan tâm đến tuổi (timedelta) chứ không phải thời gian.
guettli

@guettli, tôi sẽ nói đây có lẽ là câu trả lời tốt nhất và đơn giản nhất cho trường hợp sử dụng của bạn. Điều quan trọng nhất khi so sánh thời gian là bạn đang so sánh like cho thích, trong ví dụ này, đó là dấu thời gian UTC so với dấu thời gian UTC vì vậy sẽ luôn hoạt động. Lý do mã của bạn ban đầu không hoạt động là do bạn so sánh các đối tượng không còn liên quan đến dấu thời gian UTC vì chúng không nhận biết được múi giờ. Nếu bạn có ý định làm những việc phức tạp hơn, thì câu trả lời của tôi có thể hữu ích hơn vì nó dễ dàng hơn để làm việc với các đối tượng datetime, nhưng để so sánh đơn giản thì điều này hoạt động.
KillerKode

1
@guettli Tôi gọi nó là "cách tiếp cận đúng đắn" bởi vì tôi đã dành quá nhiều giờ nếu không phải ngày gỡ lỗi các hệ thống và giao diện chỉ hoạt động với một số giả định tiên nghiệm về thời gian và thời gian nhận được làm đầu vào. Nếu ví dụ: máy chủ của bạn không chạy trong cùng múi giờ với máy khách và thời gian dữ liệu được truyền đi mà không có bù UTC rõ ràng và được hiểu là thời gian dữ liệu cục bộ, mọi thứ vẫn có thể giải quyết được (ví dụ như khi tính toán deltas) nhưng có thể dễ dàng gỡ lỗi tránh nếu mọi người chỉ dính vào UTC ngay từ đầu / càng sớm càng tốt.
konstantin

1
@guettli Cảm ơn bạn đã chấp nhận câu trả lời của tôi. Tôi hy vọng nó hữu ích, vì tôi hơi sợ câu trả lời ngắn gọn của tôi không xứng đáng với số tiền thưởng hào phóng như vậy và bạn đã trả tiền cho tôi. Trân trọng (Schöne Grüße nach Chemnitz)
VPfB

3

cả hai đối tượng datetime của bạn đều 'ngây thơ', nghĩa là họ không biết về DST. datetime.now()trả về thời gian hiện tại máy của bạn chạy và có thể bao gồm DST. Cùng đi cho datetime.fromtimestamp(os.path.getmtime()).

# 1 - nội địa hóa các đối tượng datetime của bạn có thể là một tùy chọn; cái gì đó như

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 - một tùy chọn khác, sử dụng chuyển đổi UTC với 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 - với tư cách là VPfB chỉ ra trong câu trả lời của mình, os.path.getmtimetrả về dấu thời gian UTC (kiểm tra tài liệu mô-đun ostài liệu mô-đun thời gian ). Vì vậy, giải pháp đơn giản nhất có thể là bỏ qua chuyển đổi sang datetimevị trí đầu tiên và chỉ sử dụng dấu thời gian UTC; ví dụ: lấy dấu thời gian UTC hiện tại là time.time().

Làm việc với các múi giờ có thể khiến bạn phát điên ... nhưng có một số tài nguyên tốt ngoài đó, vd bài đăng trung bình này .


1

Vấn đề của bạn là bạn đang nhận được thời gian của bạn mà không nhận thức được múi giờ. Vì vậy, khi đồng hồ thay đổi, bạn kết thúc so sánh một dấu thời gian từ trước khi đồng hồ thay đổi và một dấu thời gian khác sau khi đồng hồ thay đổi và mã của bạn không thấy điều này.

Thay vào đó, bạn nên đặt các đối tượng datetime của mình dựa trên múi giờ cụ thể để bạn không gặp vấn đề với việc thay đổi đồng hồ, tôi khuyên bạn nên sử dụng mô-đun pytz để giúp bạn điều này. Bạn có thể thấy một danh sách các múi giờ có sẵn trong câu trả lời này: Có danh sách các múi giờ Pytz không?

Dưới đây là một ví dụ mã đơn giản về cách bạn có thể làm điều này với các đối tượng nhận biết múi giờ:

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)

Tại sao giải pháp của bạn tốt hơn age = time.time() - os.path.getmtime(file_name). Tôi chỉ quan tâm đến tuổi (đồng bằng thời gian) chứ không phải thời gian.
guettli

1
Nếu bạn chỉ quan tâm đến đồng bằng thời gian, thì không. Lý do tôi tiếp cận nó theo cách này là vì bạn đã đề cập đến nó trong múi giờ CET và cho thấy bạn đang làm việc với các đối tượng datetime, cách tiếp cận này có thể hữu ích nếu bạn so sánh thời gian giữa hai múi giờ khác nhau. Nếu múi giờ của bạn giống nhau thì chỉ cần so sánh dấu thời gian là đủ. Việc xem xét duy nhất khác là đảm bảo thời gian hệ thống của bạn được đồng bộ hóa với máy chủ NTP.
KillerKode
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.