803

RFC 3339文字列"2008-09-03T20:56:35.450686Z"を Python のdatetime型のように解析する必要があります。

Python 標準ライブラリで見つけstrptimeたのですが、あまり便利ではありません。

これを行う最善の方法は何ですか?

4

28 に答える 28

592

isoparsepython-dateutil の関数

python-dateutilパッケージは、問題のdateutil.parser.isoparseような RFC 3339 日時文字列だけでなく、RFC 3339 に準拠していない他のISO 8601日時文字列 (UTC オフセットがないものや、日付のみを表します)。

>>> import dateutil.parser
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903T205635.450686') # ISO 8601 basic format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903') # ISO 8601 basic format, date only
datetime.datetime(2008, 9, 3, 0, 0)

python-dateutilパッケージにもdateutil.parser.parse. と比べるとisoparse、おそらくそれほど厳密ではありませんが、どちらも非常に寛容で、渡された文字列を解釈しようとします。読み間違いの可能性を排除したい場合は、これらの関数のいずれよりも厳密なものを使用する必要があります。 .

Python 3.7+ のビルトインとの比較datetime.datetime.fromisoformat

dateutil.parser.isoparseは完全な ISO-8601 形式のパーサーですが、fromisoformat意図的にそうではありません。この注意事項については、後者の関数のドキュメントを参照してください。(この回答を参照してください)。

于 2013-03-05T15:44:16.223 に答える
212

Python 2.6以降およびPy3Kでは、%f文字がマイクロ秒をキャッチすることに注意してください。

>>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")

ここで問題を参照してください

于 2008-09-24T15:45:02.013 に答える
181

ここでのいくつかの回答 は、質問に示されているように、タイムゾーンを使用して RFC 3339 または ISO 8601 の日時を解析するために使用することを提案しています。 datetime.datetime.strptime

2008-09-03T20:56:35.450686Z

これは悪い考えです。

ゼロ以外の UTC オフセットのサポートを含む完全な RFC 3339 形式をサポートすると仮定すると、これらの回答が示唆するコードは機能しません。実際、RFC 3339 構文を使用して解析することは不可能であるため、機能しませんstrptime。Python の datetime モジュールで使用されるフォーマット文字列は、RFC 3339 構文を記述できません。

問題は UTC オフセットです。RFC 3339 Internet Date/Time Formatでは、すべての日時に UTC オフセットが含まれている必要があり、これらのオフセットはZ(「ズールー時間」の略) または inまたは+HH:MM-HH:MMような形式にすることができます。+05:00-10:30

したがって、これらはすべて有効な RFC 3339 日時です。

  • 2008-09-03T20:56:35.450686Z
  • 2008-09-03T20:56:35.450686+05:00
  • 2008-09-03T20:56:35.450686-10:30

残念ながら、 とで使用されるフォーマット文字列には、RFC 3339 フォーマットの UTC オフセットに対応するディレクティブがstrptimeありstrftimeません。それらがサポートするディレクティブの完全なリストはhttps://docs.python.org/3/library/datetime.html#strftime-and-strptime-behaviorで見つけることができ、リストに含まれる唯一の UTC オフセット ディレクティブは次のとおりです%z

%z

+HHMM または -HHMM 形式の UTC オフセット (オブジェクトが単純な場合は空の文字列)。

例: (空)、+0000、-0400、+1030

これは RFC 3339 オフセットの形式と一致しません。実際%z、形式文字列で使用して RFC 3339 日付を解析しようとすると、失敗します。

>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
    (data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
    (data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'

(実際には、上記は Python 3 で表示されるものにすぎません。Python 2 では、さらに単純な理由で失敗します。それは、Python 2 でディレクティブをまったくstrptime実装していない%zということです。)

ここで推奨する複数の回答は、フォーマット文字列にstrptimeリテラルを含めることでこれを回避することを推奨しています。これは、質問者の例の日時文字列と一致します (そしてそれを破棄し、タイムゾーンのないオブジェクトを生成します)。ZZdatetime

>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)

これは元の日時文字列に含まれていたタイムゾーン情報を破棄するため、この結果でも正しいと見なすかどうかは疑問です。しかし、もっと重要なことは、このアプローチでは特定の UTC オフセットをフォーマット文字列にハードコーディングする必要があるため、別の UTC オフセットを使用して RFC 3339 日時を解析しようとした瞬間に停止することです。

>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
    (data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'

ズールー時間で RFC 3339 の日付時刻のみをサポートする必要があり、他のタイムゾーン オフセットの日付時刻をサポートする必要がないことが確実でない限り、 strptime. 代わりに、こちらの回答で説明されている他の多くのアプローチのいずれかを使用してください。

于 2015-06-07T17:53:25.920 に答える
80

iso8601モジュールを試してください。それはまさにこれを行います。

python.org wiki のWorkingWithTimeページには、他にもいくつかのオプションが記載されています。

于 2008-09-24T15:38:17.147 に答える
36

あなたが得る正確なエラーは何ですか?以下のようなものでしょうか?

>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format:  data=2008-08-12T12:20:30.656234Z  fmt=%Y-%m-%dT%H:%M:%S.Z

はいの場合は、入力文字列を「.」で分割し、取得した日時にマイクロ秒を追加できます。

これを試して:

>>> def gt(dt_str):
        dt, _, us= dt_str.partition(".")
        dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
        us= int(us.rstrip("Z"), 10)
        return dt + datetime.timedelta(microseconds=us)

>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
于 2008-09-24T15:19:27.817 に答える
32
import re
import datetime
s = "2008-09-03T20:56:35.450686Z"
d = datetime.datetime(*map(int, re.split(r'[^\d]', s)[:-1]))
于 2008-09-24T15:27:24.380 に答える
22

最近では、Arrowはサードパーティのソリューションとしても使用できます。

>>> import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")
>>> date.datetime
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
于 2015-02-15T16:47:44.013 に答える
13

Django を使用している場合は、タイム ゾーンを含む、ISO 形式に似た一連の形式を受け入れるdateparse モジュールが提供されます。

Django を使用しておらず、ここに記載されている他のライブラリのいずれも使用したくない場合は、おそらくdateparse の Django ソース コードをプロジェクトに適合させることができます。

于 2015-09-30T21:42:22.070 に答える
13

dateutil を使用したくない場合は、次の関数を試すことができます。

def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):
    """
    Convert UTC time string to time.struct_time
    """
    # change datetime.datetime to time, return time.struct_time type
    return datetime.datetime.strptime(utcTime, fmt)

テスト:

from_utc("2007-03-04T21:08:12.123Z")

結果:

datetime.datetime(2007, 3, 4, 21, 8, 12, 123000)
于 2014-03-27T22:50:16.067 に答える
9

ISO 8601 標準のパーサーをコード化し、GitHub に配置しました: https://github.com/boxed/iso8601。この実装は、期間、間隔、定期的な間隔、および Python の datetime モジュールでサポートされている日付範囲外の日付を除いて、仕様のすべてをサポートしています。

テストが含まれています!:P

于 2013-03-02T13:31:49.793 に答える
8

私は iso8601utils の作成者です。GitHubまたはPyPIで見つけることができます。例を解析する方法は次のとおりです。

>>> from iso8601utils import parsers
>>> parsers.datetime('2008-09-03T20:56:35.450686Z')
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
于 2016-10-26T05:20:18.800 に答える
7

datetime.datetimeサードパーティ モジュールをインストールせずに、サポートされているすべての Python バージョンでISO 8601 のような日付文字列を UNIX タイムスタンプまたはオブジェクトに変換する簡単な方法の 1 つは、SQLite の日付パーサーを使用することです。

#!/usr/bin/env python
from __future__ import with_statement, division, print_function
import sqlite3
import datetime

testtimes = [
    "2016-08-25T16:01:26.123456Z",
    "2016-08-25T16:01:29",
]
db = sqlite3.connect(":memory:")
c = db.cursor()
for timestring in testtimes:
    c.execute("SELECT strftime('%s', ?)", (timestring,))
    converted = c.fetchone()[0]
    print("%s is %s after epoch" % (timestring, converted))
    dt = datetime.datetime.fromtimestamp(int(converted))
    print("datetime is %s" % dt)

出力:

2016-08-25T16:01:26.123456Z is 1472140886 after epoch
datetime is 2016-08-25 12:01:26
2016-08-25T16:01:29 is 1472140889 after epoch
datetime is 2016-08-25 12:01:29
于 2016-08-25T16:16:26.243 に答える
6

ISO-8601 専用のパーサーを使用する別の方法は、dateutil パーサーのisoparse関数を使用することです。

from dateutil import parser

date = parser.isoparse("2008-09-03T20:56:35.450686+01:00")
print(date)

出力:

2008-09-03 20:56:35.450686+01:00

この関数は、標準の Python 関数datetime.fromisoformatのドキュメントにも記載されています。

より完全な機能を備えた ISO 8601 パーサーである dateutil.parser.isoparse は、サードパーティ パッケージ dateutil で利用できます。

于 2019-09-24T12:32:41.400 に答える
4

ISO 8601 では、オプションのコロンとダッシュのさまざまなバリエーションが存在することが許可されているため、基本的にCCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. strptime を使用する場合は、最初にそれらのバリエーションを削除する必要があります。

目標は、utc 日時オブジェクトを生成することです。


次のような Z サフィックスが付いた UTC で機能する基本的なケースが必要な場合2016-06-29T19:36:29.3453Z:

datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")


タイムゾーンオフセットを次のように処理する2016-06-29T19:36:29.3453-04002008-09-03T20:56:35.450686+05:00、次を使用する場合。これらは、すべてのバリエーションを変数区切り文字のないものに変換し 20080903T205635.450686+0500、より一貫性があり、解析しやすくします。

import re
# this regex removes all colons and all 
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)
datetime.datetime.strptime(conformed_timestamp, "%Y%m%dT%H%M%S.%f%z" )


お使いのシステムが strptime ディレクティブをサポートしていない場合%z(次のように表示されます)、 (UTC)ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'から手動で時刻をオフセットする必要があります。Z注記%zは、システム/Python ビルド タイプ (Jython、Cython など) によって異なる c ライブラリ サポートに依存するため、Python バージョン < 3 のシステムでは機能しない可能性があります。

import re
import datetime

# this regex removes all colons and all 
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)

# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]
if len(split_timestamp) == 3:
    sign = split_timestamp[1]
    offset = split_timestamp[2]
else:
    sign = None
    offset = None

# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z", "%Y%m%dT%H%M%S.%fZ" )
if offset:
    # create timedelta based on offset
    offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))
    # offset datetime with timedelta
    output_datetime = output_datetime + offset_delta
于 2016-06-28T19:54:18.820 に答える
2

2.X標準ライブラリで動作するものについては、次を試してください。

calendar.timegm(time.strptime(date.split(".")[0]+"UTC", "%Y-%m-%dT%H:%M:%S%Z"))

calendar.timegmは、time.mktimeの欠落しているgmバージョンです。

于 2011-07-21T06:47:19.800 に答える
2

python-dateutil は、無効な日付文字列を解析すると例外をスローするため、例外をキャッチすることをお勧めします。

from dateutil import parser
ds = '2012-60-31'
try:
  dt = parser.parse(ds)
except ValueError, e:
  print '"%s" is an invalid date' % ds
于 2013-08-09T15:53:22.103 に答える
-1
def parseISO8601DateTime(datetimeStr):
    import time
    from datetime import datetime, timedelta

    def log_date_string(when):
        gmt = time.gmtime(when)
        if time.daylight and gmt[8]:
            tz = time.altzone
        else:
            tz = time.timezone
        if tz > 0:
            neg = 1
        else:
            neg = 0
            tz = -tz
        h, rem = divmod(tz, 3600)
        m, rem = divmod(rem, 60)
        if neg:
            offset = '-%02d%02d' % (h, m)
        else:
            offset = '+%02d%02d' % (h, m)

        return time.strftime('%d/%b/%Y:%H:%M:%S ', gmt) + offset

    dt = datetime.strptime(datetimeStr, '%Y-%m-%dT%H:%M:%S.%fZ')
    timestamp = dt.timestamp()
    return dt + timedelta(hours=dt.hour-time.gmtime(timestamp).tm_hour)

文字列が で終わらない場合はZ、 を使用して解析できることに注意してください%z

于 2016-08-09T10:17:22.723 に答える