Python UTC日時オブジェクトのISO形式にZ(ズールーまたはゼロオフセット)が含まれていません


120

JavaScriptとは異なり、Python 2.7がUTC日時オブジェクトのアイソフォーマット文字列の末尾にZ文字(Zuluまたはゼロオフセット)を含まないのはなぜですか?

>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'

一方、JavaScriptでは

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z

1
Pythonの日時値にはタイムゾーン情報がありません。タイムゾーン情報をタイムスタンプに保存したい場合は、pytzまたはBabelを試してください。
tnknepp 2013

67
datetime.datetime.utcnow().isoformat() + 'Z'
jfs 2014年


3
..そして欠落しているZにより、驚くべきことに、API呼び出しなどの一部の機能が動作しなくなります
カルダモン

さらに悪いことに、datetimeの最後の部分が0の場合は切り捨てられます...
ntg

回答:


52

Python datetimeオブジェクトにはデフォルトでタイムゾーン情報がありません。これがないと、Pythonは実際にはISO 8601仕様に違反します(タイムゾーン情報が指定されていない場合、現地時間と見なされます)。pytzパッケージを使用して、いくつかのデフォルトのタイムゾーンを取得するか、tzinfo自分で直接サブクラス化できます。

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)

次に、タイムゾーン情報を手動で追加できますutcnow()

>>> datetime.utcnow().replace(tzinfo=simple_utc()).isoformat()
'2014-05-16T22:51:53.015001+00:00'

これはISO 8601形式に準拠していることに注意してください。これにより、UTCのいずれかZまたは+00:00サフィックスとして使用できます。後者は実際にはタイムゾーンが一般的にどのように表されるかによって、より標準に準拠していることに注意してください(UTCは特殊なケースです)。


108
Z代わりにどのように含めるの+00:00ですか?
レオプードル2017

14
警告!!! pytzPythonのtzinfoプロトコルに違反しており、使用するのは危険です!blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.htmlを
ivan_pozdeev

@ivan_pozdeevリンクをありがとう、非常に興味深い。dateutil動作を許可する変更は、PEP 495をpytz使用したPython 3.6まで実装されなかったことに注意してください。つまり、インターフェイスが変更されたため、標準インターフェイスを使用しなかったのは不公平です。変更前は、それを機能させる唯一の方法pytzはそれを行う方法でした。
Mark Ransom

67

オプション: isoformat()

Python datetimeは、UTCの「Z」サフィックスのような軍事タイムゾーンサフィックスをサポートしていません。次の単純な文字列の置換でうまくいきます。

In [1]: import datetime

In [2]: d = datetime.datetime(2014, 12, 10, 12, 0, 0)

In [3]: str(d).replace('+00:00', 'Z')
Out[3]: '2014-12-10 12:00:00Z'

str(d) 本質的に同じです d.isoformat(sep=' ')

参照:日時、Python標準ライブラリ

オプション: strftime()

またはstrftime、同じ効果を達成するために使用できます。

In [4]: d.strftime('%Y-%m-%d %H:%M:%SZ')
Out[4]: '2014-12-10 12:00:00Z'

注:このオプションは、指定された日付がUTCであることがわかっている場合にのみ機能します。

参照:datetime.strftime()


追加:人間が読めるタイムゾーン

さらに行く、あなたは、人間が読めるタイムゾーン情報を表示するに興味がある可能性がありpytzstrftime %Zタイムゾーンフラグ:

In [5]: import pytz

In [6]: d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=pytz.utc)

In [7]: d
Out[7]: datetime.datetime(2014, 12, 10, 12, 0, tzinfo=<UTC>)

In [8]: d.strftime('%Y-%m-%d %H:%M:%S %Z')
Out[8]: '2014-12-10 12:00:00 UTC'

1
セパレータをT空白の代わりにすべきではありませんか?
Marcello Romani

1
それはd = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc)2行目にあるはずです。ところで、RFC3339では、スペースは( 'T'ではなく) 'ok'であると述べています。
MrFuppes

16

次のjavascriptおよびpythonスクリプトは、同じ出力を提供します。あなたが探しているものだと思います。

JavaScript

new Date().toISOString()

パイソン

import datetime

datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

彼らが与える出力は、3ミリ秒の有効数字とZが付加されたISO文字列としてフォーマットされたutc(zelda)時間です。

2019-01-19T23:20:25.459Z

12

Python> = 3.2では、これを単純に使用できます:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'

3
とても良い解決策です。彼らの質問についてZ:あなたは、オフセットクリッピングすることができます.isoformat()[:-6] + 'Z'
マクシミリアンBurszley

11

Pythonの日時は少し不格好です。を使用しarrowます。

> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'

Arrowは本質的にdatetimeと同じAPIを持っていますが、メインライブラリにあるはずのタイムゾーンといくつかの特別な機能を備えています。

JavaScriptと互換性のあるフォーマットは、次の方法で実現できます。

arrow.utcnow().isoformat().replace("+00:00", "Z")
'2018-11-30T02:46:40.714281Z'

JavaScript Date.parseは、タイムスタンプからマイクロ秒を静かに落とします。


7
文字列が「Z」で終わっていないため、これは質問に答えません。
kaleissin

3

投稿には多くの良い答えがありますが、JavaScriptの場合とまったく同じようにフォーマットを出力したかったのです。これは私が使っているもので、うまくいきます。

In [1]: import datetime

In [1]: now = datetime.datetime.utcnow()

In [1]: now.strftime('%Y-%m-%dT%H:%M:%S') + now.strftime('.%f')[:4] + 'Z'
Out[3]: '2018-10-16T13:18:34.856Z'

3
pip install python-dateutil
>>> a = "2019-06-27T02:14:49.443814497Z"
>>> dateutil.parser.parse(a)
datetime.datetime(2019, 6, 27, 2, 14, 49, 443814, tzinfo=tzutc())

2

私はいくつかの目標を持ってこの問題に取り組みました:

  • ISO 8601形式でUTC「対応」日時文字列を生成する
  • datetimeオブジェクトと文字列の作成に Python標準ライブラリ関数のみを使用します
  • Django timezoneユーティリティ関数とdateutilパーサーで日時オブジェクトと文字列を検証する
  • JavaScript関数を使用して、ISO 8601日時文字列がUTC対応であることを検証します

このアプローチに Zサフィックスが含まれておらず使用されていませんutcnow()、Pythonのドキュメントの推奨事項に基づいており、DjangoとJavaScriptでマスターを渡します。

datetime.now()を使用する代わりにUTCタイムゾーンオブジェクトを渡すことから始めましょうdatetime.utcnow()

from datetime import datetime, timezone

datetime.now(timezone.utc)
>>> datetime.datetime(2020, 1, 8, 6, 6, 24, 260810, tzinfo=datetime.timezone.utc)

datetime.now(timezone.utc).isoformat()
>>> '2020-01-08T06:07:04.492045+00:00'

それ良さそうなので、Djangoを見て、dateutil考えてみましょう。

from django.utils.timezone import is_aware

is_aware(datetime.now(timezone.utc))
>>> True

import dateutil.parser

is_aware(dateutil.parser.parse(datetime.now(timezone.utc).isoformat()))
>>> True

さて、PythonのdatetimeオブジェクトとISO 8601文字列はUTCに対応しています。次に、JavaScriptが日時文字列についてどのように考えているかを見てみましょう。この答えを借りると、次のようになります。

let date= '2020-01-08T06:07:04.492045+00:00';
const dateParsed = new Date(Date.parse(date))

document.write(dateParsed);
document.write("\n");
// Tue Jan 07 2020 22:07:04 GMT-0800 (Pacific Standard Time)

document.write(dateParsed.toISOString());
document.write("\n");
// 2020-01-08T06:07:04.492Z

document.write(dateParsed.toUTCString());
document.write("\n");
// Wed, 08 Jan 2020 06:07:04 GMT

また、このブログ投稿を読むこともできます。


1
ベースライブラリ関数に固執し、古い投稿をフォローアップするボーナス。
Victor Romeo

1

上記のすべての答えを組み合わせることにより、私は次の機能を備えました:

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)


def getdata(yy, mm, dd, h, m, s) :
    d = datetime(yy, mm, dd, h, m, s)
    d = d.replace(tzinfo=simple_utc()).isoformat()
    d = str(d).replace('+00:00', 'Z')
    return d


print getdata(2018, 02, 03, 15, 0, 14)

1

私は振り子を使用します:

import pendulum


d = pendulum.now("UTC").to_iso8601_string()
print(d)

>>> 2019-10-30T00:11:21.818265Z

0
>>> import arrow

>>> now = arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS')
>>> now
'2018-11-28T21:34:59.235'
>>> zulu = "{}Z".format(now)
>>> zulu
'2018-11-28T21:34:59.235Z'

または、一挙にそれを取得するには:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.