getmtime()対datetime.now():


8

このコードは、1年に1回、時計のシフトの夜(中央ヨーロッパ夏時間から中央ヨーロッパ時間)に誤った警告を出力します。

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)

このコードを毎年1時間のクロックシフトでも機能させるにはどうすればよいですか。

更新

私は日付時刻ではなく年齢のみを気にします。

回答:


6

投稿されたフラグメントは、現地時間からUTC時間に切り替えることで簡単に改善できます。UTCには夏時間(夏時間)の変更はありません。これら2つの日時関数now()-> utcnow()docs)とfromtimestamp()-> utcfromtimestamp()docs)を置き換えるだけです。

ただし、予想される唯一の出力が秒単位のファイル経過時間である場合は、変換せずにタイムスタンプ(「エポック」からの秒数)を直接使用できます。

import time
import os.path

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

3
そもそもUTCを使用することは、普遍的に正しいアプローチです。
コンスタンティン

@konstantinなぜ正しいアプローチなのですか?私は(このコンテキストでは)日時(timedelta)のみを考慮しているので、この単純なソリューションが好きです。
guettli

@guettli、これはおそらくあなたのユースケースにとって最良かつ最も簡単な答えだと思います。時間を比較する際に最も重要なことは、like for likeを比較することです。この例では、UTCタイムスタンプとUTCタイムスタンプの両方なので、常に機能します。コードが元々機能しなかった理由は、タイムゾーンに対応していないためにUTCタイムスタンプとの関連性がなくなったオブジェクトを比較していたためです。もっと複雑なことをするつもりなら、datetimeオブジェクトで作業するほうが簡単なので、私の答えはより役立つかもしれませんが、単純な比較ではこれでうまくいきます。
KillerKode

1
@guettli私はそれを「普遍的に正しいアプローチ」とラベル付けしました。入力として受け取った日時とタイムゾーンに関するいくつかのアプリオリな仮定でのみ機能するシステムとインターフェースをデバッグするのに数日ではなく何時間も費やしたからです。たとえば、サーバーがクライアントと同じタイムゾーンで実行されておらず、日時が明示的なUTCオフセットなしで渡され、ローカルの日時として解釈される場合、なんらかの方法で問題が解決する可能性があります(たとえば、デルタを計算する場合)が、簡単にデバッグできるのは苦痛です。誰もが最初に/できるだけ早くUTCに固執する場合は避けてください。
コンスタンティン

1
@guettli私の答えを受け入れてくれてありがとう。私の短い答えはそのような寛大な報奨金の価値がなく、あなたは私に過大な支払いをしたのではないかと心配しています。よろしく
SchöneGrüßenach

3

どちらの日時オブジェクトも「ナイーブ」です。つまり、DSTを認識していません。datetime.now()マシンが実行されている現在の時刻を返します。これには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 -としてVPfBが彼の答えで指摘し、os.path.getmtimeUTCタイムスタンプ(チェック返すosモジュールのドキュメント時間モジュールのドキュメントを)。したがって、最も簡単な解決策はdatetime、最初にへの変換をスキップし、UTCタイムスタンプのみを使用することです。たとえば、現在のUTCタイムスタンプをとして取得しtime.time()ます。

タイムゾーンでの作業は怒っあなたを運転...しかし、いくつかの良いリソースは例えば、そこにそこにいることができ、この中のポストは


1

あなたの問題は、タイムゾーンに気づかれずに時間を取っていることです。したがって、クロックが変化すると、クロックが変化する前のタイムスタンプとクロックが変化した後のタイムスタンプの比較が終了し、コードでこれが認識されなくなります。

代わりに、日付時刻オブジェクトを特定のタイムゾーンに基づくようにして、時計の変更に関する問題が発生しないようにする必要があります。これには、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)

なぜあなたのソリューションはよりも優れていますage = time.time() - os.path.getmtime(file_name)。日時ではなく、年齢(時間のデルタ)だけに関心があります。
guettli

1
タイムデルタだけに関心がある場合は、関心がありません。私がこの方法でアプローチした理由は、CETタイムゾーンにあると述べ、日時オブジェクトを操作していることを示したためです。このアプローチは、2つの異なるタイムゾーン間の時間を比較する場合に役立ちます。タイムゾーンが同じ場合は、タイムスタンプを比較するだけで十分です。他の唯一の考慮事項は、システム時刻がNTPサーバーと同期していることを確認することです。
KillerKode
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.