web-dev-qa-db-ja.com

pythonのUTCタイムスタンプをdatetimeで取得します

日付を指定してUTCタイムスタンプを取得する方法はありますか?私が期待するもの:

datetime(2008, 1, 1, 0, 0, 0, 0)

結果になるはずです

 1199145600

単純な日時オブジェクトを作成するということは、タイムゾーン情報がないことを意味します。 datetime.utcfromtimestampのドキュメントを見ると、UTCタイムスタンプの作成はタイムゾーン情報を除外することを意味します。単純なdatetimeオブジェクトを作成すると(私がしたように)UTCタイムスタンプになります。しかしながら:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

結果として

2007-12-31 23:00:00

Datetimeオブジェクトにはまだ隠されたタイムゾーン情報がありますか?私は何を間違えていますか?

71
pat

ナイーブdatetimeとは?

デフォルトのdatetimeオブジェクトは「ナイーブ」であると言われます:それらは時間帯情報なしで時間情報を保持します。単純なdatetimeを、明確なOriginのない相対番号(例:+4)として考えてください(実際、Originはシステムの境界全体で共通です)。全世界で共通のOriginを持つ絶対変数(8)としてdatetimeを認識することを考えてください。

タイムゾーン情報なしできません「単純な」日付時刻を非単純な時刻表現に変換します(どこから始めればわからない場合は+4がターゲットになりますか?)。これが、datetime.datetime.toutctimestamp()メソッドを使用できない理由です。 (cf: http://bugs.python.org/issue1457227

datetimedtがナイーブかどうかを確認するには、dt.tzinfoをチェックし、Noneの場合はナイーブです:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

私はナイーブな日付時刻があります、私は何ができますか?

特定のコンテキストに応じて仮定を行う必要があります。あなたが自問しなければならない質問は、UTCのdatetimeでしたか?それとも現地時間でしたか?

  • TCを使用していた場合(問題はありません):

    import calendar
    
    def dt2ts(dt):
        """Converts a datetime object to UTC timestamp
    
        naive datetime will be considered UTC.
    
        """
    
        return calendar.timegm(dt.utctimetuple())
    
  • TCを使用していない場合、地獄へようこそ。

    前の関数を使用する前に、datetimeを非ナイーブにする必要があります。これには、目的のタイムゾーンを返す必要があります。

    タイムゾーンの名前およびDSTが有効かどうかに関する情報が必要です。ターゲットのナイーブなdatetimeを生成する場合(DSTに関する最後の情報はコーナーケースに必要です):

    import pytz     ## pip install pytz
    
    mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone
    
    dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly
    

    is_dstを指定しない場合の結果

    is_dstを使用しないと、逆方向のDSTが設定されている間にターゲット日時が生成された場合(たとえば、1時間を削除してDST時間を変更する場合)、誤った時刻(およびUTCタイムスタンプ)が生成されます。

    誤ったis_dstを指定すると、当然、DSTのオーバーラップまたはホールでのみ不正な時間(およびUTCタイムスタンプ)が生成されます。また、「穴」で発生する不正確な時間(DSTの前方シフトにより存在しなかった時間)を提供する場合、is_dstはこの偽の時間を考慮する方法の解釈を提供し、これは.normalize(..)が実際に何かを行う唯一のケースですここでは、実際の有効な時間として変換されます(必要に応じて、日時とDSTオブジェクトを変更します)。 .normalize()は最後に正しいUTCタイムスタンプを持つために必要ではないことに注意してください。しかし、特にこの変数を別の場所で再利用する場合、変数に偽の時間があるという考えが嫌いならおそらくお勧めです。

    および以下を使用しない:(cf: pytzを使用した日時のタイムゾーン変換

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    どうして?これは、.replace()がターゲット時間を考慮せずにtzinfoを盲目的に置換し、不正なDSTオブジェクトを選択するためです。 .localize()はターゲット時間とis_dstヒントを使用して正しいDSTオブジェクトを選択します。

古い不正解(これを報告してくれた@ J.F.Sebastienに感謝します):

単純なdatetimeオブジェクトを作成するときにタイムゾーン(ローカルOrigin)を推測するのは非常に簡単です。これは、単純なdatetimeオブジェクトの作成と取得したい瞬間との間で変更しないことが望ましいシステム構成に関連しているためですUTCタイムスタンプ。このトリックは、imperfectの質問に使用できます。

time.mktimeを使用すると、utc_mktimeを作成できます。

def utc_mktime(utc_Tuple):
    """Returns number of seconds elapsed since Epoch

    Note that no timezone are taken into consideration.

    utc Tuple must be: (year, month, day, hour, minute, second)

    """

    if len(utc_Tuple) == 6:
        utc_Tuple += (0, 0, 0)
    return time.mktime(utc_Tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))

def datetime_to_timestamp(dt):
    """Converts a datetime object to UTC timestamp"""

    return int(utc_mktime(dt.timetuple()))

datetimeオブジェクトが、datetimeを作成したタイムゾーンと同じタイムゾーンで作成されていることを確認する必要があります。

この最後の解決策は、今からのUTCオフセットがエポックからのUTCオフセットと同じであるという仮定を立てているため、正しくありません。多くのタイムゾーン(夏時間(DST)オフセットの特定の年の瞬間)。

76
vaab

別の可能性は次のとおりです。

d = datetime.datetime.utcnow()
Epoch = datetime.datetime(1970,1,1)
t = (d - Epoch).total_seconds()

これは、「d」と「Epoch」の両方が単純な日付時刻であるため、「-」演算子が有効になり、間隔が返されます。 total_seconds()は、間隔を秒に変換します。 total_seconds()d.microsecond == 0であってもfloatを返すことに注意してください

23
Chris Cogdon

this ブログエントリで説明されている calendar.timegm() 関数にも注意してください。

import calendar
calendar.timegm(utc_timetuple)

出力は、vaabの解と一致する必要があります。

19
Mr. Mr.

入力日時オブジェクトがUTCの場合:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

注:浮動小数点数を返します。つまり、マイクロ秒は秒の小数部として表されます。

入力日付オブジェクトがUTCの場合:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

詳細は datetime.dateをPythonのUTCタイムスタンプに変換する でご覧ください。

12
jfs

実際、utcfromtimestampの使用とタイムゾーンの指定には問題があります。素敵な例/説明は、次の質問で利用できます。

nix時間に変換するときにタイムゾーン(UTC)を指定する方法(Python)

1
CamilleLDN

受け入れられた答えは私にとってはうまくいかないようです。私の解決策:

import time
utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple()))
def datetime2ts(dt):
    """Converts a datetime object to UTC timestamp"""
    return int(time.mktime(dt.utctimetuple())) - utc_0
0
dreamingcloud