文字列を日時に変換する


2183

文字列として、次のような日時の膨大なリストがあります。

Jun 1 2005  1:33PM
Aug 28 1999 12:00AM

これらをデータベースの適切な日時フィールドに押し戻すので、実際の日時オブジェクトに魔法をかける必要があります。

これはDjangoのORMを経由しているため、SQLを使用して挿入時に変換を行うことはできません。


6
1つの形式がすべての日時を処理することが確実でない限り( ''、NaNなし、不完全なし、形式の不一致なし、末尾の文字なし、タイムゾーンなし、マイクロ秒のタイムスタンプ、またはその他のテキスト...)、例外の幸福度strptime()あなたがそれを包まない限り、あなたはナッツを運転します。これに対するOr Weisの回答に
smci

私が知っている最も遅く、最も広く使用可能なアプローチは、dateparserです(blog.scrapinghub.com/2015/11/09/…を確認してください)。すぐに使えるいくつかの言語の自然言語の時間表現でも動作します。遅いかもしれませんが。
アルマンド

ここに役立つリンクがあります:stackabuse.com/converting-strings-to-datetime-in-python
GoingMyWay

回答:


3461

datetime.strptime文字列を日付時刻に解析するためのメインルーチンです。与えられたフォーマット文字列によって決定されるフォーマットで、あらゆる種類のフォーマットを処理できます。

from datetime import datetime

datetime_object = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

結果のdatetimeオブジェクトはtimezone-naiveです。

リンク:

  • PythonドキュメントstrptimePython 2Python 3

  • strptime/ strftime形式文字列のPythonドキュメント:Python 2Python 3

  • strftime.orgは、strftimeの非常に優れたリファレンスでもあります。

ノート:

  • strptime = "文字列解析時間"
  • strftime = "文字列フォーマット時間"
  • 今日は大声で発音してください。6か月後にもう一度検索する必要はありません。

7
'%b'、 '%p'は英語以外のロケールで失敗する場合があります。
jfs 14

15
あなたはフォーマット文字列の一部を除外するために、事前に知っておく必要がありますが、あなたがしたい場合は@user dateの代わりにdatetime、経由するdatetime:うまくハンドルを datetime.strptime('Jun 1 2005', '%b %d %Y').date() == date(2005, 6, 1)
Izkata

14
あなたは文字列がUTCの日時を表しわかっている場合は、タイムゾーンを認識し得ることができますdatetimePythonの3にこの行を追加することにより、オブジェクトを:from datetime import timezone; datetime_object = datetime_object.replace(tzinfo=timezone.utc)
Flimm

111
私が探していた"%Y-%m-%d %H:%M:%S"
マーティン・トーマ2017

4
@AminahNuraini from datetime import datetimeだけでなく、同じような問題を回避しましたimport datetime
Max Strater 2018年

831

サードパーティのdateutilライブラリを使用します。

from dateutil import parser
parser.parse("Aug 28 1999 12:00AM")  # datetime.datetime(1999, 8, 28, 0, 0)

解析する必要があるものを含め、ほとんどの日付形式を処理できます。strptimeほとんどの場合、正しい形式を推測できるため、より便利です。

パフォーマンスよりも可読性が重要なテストの作成に非常に役立ちます。

次の方法でインストールできます。

pip install python-dateutil

86
データ量が多い場合、これは問題に対処するための最適な方法ではない可能性があることに注意してください。毎回フォーマットを推測することは恐ろしく遅いかもしれません。
パヴェルPolewicz

14
これはいいことですが、サードパーティに行く必要がなく、組み込みのソリューションがあればいいでしょう。
ブライアンバック

1
"32nd jan"を解析しようとすると、 "2032-01-06" ..が返されますが、これは正しくありません。文字列が有効な日付かどうかを確認する方法はありますか
Kartik Domadiya

6
@リーフ:私の速くて汚いベンチマークによると、5倍遅い。私が期待するほどひどく遅くはありません。
アントニーハッチキンズ2013

2
独自の問題があります-たとえば、タイムゾーン情報を時間から暗黙的に削除するなど:parser.parse('15:55EST ')を試して、例としてparser.parse('15 .55CST')と比較します
F1Rumors

490

timeモジュールのstrptimeをチェックしてください。これはstrftimeの逆です。

$ python
>>> import time
>>> my_time = time.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')
time.struct_time(tm_year=2005, tm_mon=6, tm_mday=1,
                 tm_hour=13, tm_min=33, tm_sec=0,
                 tm_wday=2, tm_yday=152, tm_isdst=-1)

timestamp = time.mktime(my_time)
# convert time object to datetime
from datetime import datetime
my_datetime = datetime.fromtimestamp(timestamp)
# convert time object to date
from datetime import date
my_date = date.fromtimestamp(timestamp)

16
私の理解から、この答えは日付オブジェクトではなく、時間オブジェクトのみを出力します。これが、パトリックの答えと比較して答えが埋もれてしまう理由です。
アレクサンダーバード

DateTimeFieldのデフォルトの日時フォーマットを設定する方法はありますか?
キングピン2013年

3
アレクサンダーが言ったように、これは日時ではなくstruct_timeを返します。もちろん、それを日時に変換することもできますが、最後に日時オブジェクトが必要な場合は、Patrickの答えはより簡単です。
Leandro Alves

標準のPythonライブラリにはstrtotimeのようなものはありませんが、dateutilには、多くのベストエフォートの日付形式を認識するパーサーがあります。
Geoff Gerrietts 2013年

1
@BenBlank:英語以外のロケールで '%b'、 '%p'が失敗する場合があります。
jfs 14

113

私はいくつかの本当にきちんとした表現を変換できるプロジェクトをまとめました。timestringを確認してください

以下にいくつかの例を示します。

pip install timestring
>>> import timestring
>>> timestring.Date('monday, aug 15th 2015 at 8:40 pm')
<timestring.Date 2015-08-15 20:40:00 4491909392>
>>> timestring.Date('monday, aug 15th 2015 at 8:40 pm').date
datetime.datetime(2015, 8, 15, 20, 40)
>>> timestring.Range('next week')
<timestring.Range From 03/10/14 00:00:00 to 03/03/14 00:00:00 4496004880>
>>> (timestring.Range('next week').start.date, timestring.Range('next week').end.date)
(datetime.datetime(2014, 3, 10, 0, 0), datetime.datetime(2014, 3, 14, 0, 0))

2
ワオ。ワオ。ワオ。ワオ。これはとても簡単です。日時文字列があり、年を引き出したいだけです。シンプル:import timestring timestring.Date('27 Mar 2014 12:32:29 GMT').yearこのlibはとても簡単になりました !ありがとうございました。
brandonjp 2014

どういたしまして。このパッケージを改善する上でのあなたのコメントとアイデアが欲しいです。お知らせください、githubの問題を使用してください。ありがとう!
スティーブピーク

こんにちは、モジュールは素晴らしいです。平日の文字列属性もあるとよいでしょう。それ以外の場合は、月曜日から開始するか日曜日から開始するかは不明
Anake

1
「2017年2月5日」や「2017年2月5日」などの形式は正しく変換されません(これらは一部のサークルで人気のある形式であり、IMOは明確さと読みやすさのために最良の日付形式の一部です)。として保存します2017-02-01。2017年2月5日も同じです(ただし、2017年2月5日は正しく行われます)。これらの最後の2つはどちらも、私の知る限り、これまでに見た形式ではありませんが、とにかく指摘したいと思いました。
Brōtsyorfuzthrāx

2
警告:このパッケージは過去5年間、どの時点でも維持または改善されていないようで、明らかに正しくない日付を定期的に解析しています。たとえば、インスタンス化はDate("20180912")何らかの方法での値を解析します2018-11-21。自己責任。
-bsplosion

54

これを覚えておけば、日時変換で混乱する必要はありませんでした。

文字列から日時オブジェクトへ= strptime

datetimeオブジェクトを他の形式に= strftime

Jun 1 2005 1:33PM

等しい

%b %d %Y %I:%M%p

%b月のロケールの省略名(6月)

%dゼロ詰めの10進数としての日(1)

%Y 10進数での世紀を含む年(2015)

%I時間(12時間時計)をゼロ詰め10進数として(01)

ゼロが埋め込まれた10進数としての%M分(33)

%pロケールのAMまたはPM(PM)のいずれかに相当

したがって、strptimeが必要です。つまりstring

>>> dates = []
>>> dates.append('Jun 1 2005  1:33PM')
>>> dates.append('Aug 28 1999 12:00AM')
>>> from datetime import datetime
>>> for d in dates:
...     date = datetime.strptime(d, '%b %d %Y %I:%M%p')
...     print type(date)
...     print date
... 

出力

<type 'datetime.datetime'>
2005-06-01 13:33:00
<type 'datetime.datetime'>
1999-08-28 00:00:00

日付の形式が異なる場合、パンダまたはdateutil.parseを使用できますか?

>>> import dateutil
>>> dates = []
>>> dates.append('12 1 2017')
>>> dates.append('1 1 2017')
>>> dates.append('1 12 2017')
>>> dates.append('June 1 2017 1:30:00AM')
>>> [parser.parse(x) for x in dates]

出力

[datetime.datetime(2017, 12, 1, 0, 0), datetime.datetime(2017, 1, 1, 0, 0), datetime.datetime(2017, 1, 12, 0, 0), datetime.datetime(2017, 6, 1, 1, 30)]

10進数としての秒の%S
オプティミスト

1
%b英語のロケールを持たないマシンで英語の日付を解析しても壊れませんか?
bfontaine 2018年

48

Python> = 3.7.0では、

変換するためにdatetime型のオブジェクトにYYYY-MM-DDの文字列をdatetime.fromisoformat使用することができます。

>>> from datetime import datetime

>>> date_string = "2012-12-12 10:10:10"
>>> print (datetime.fromisoformat(date_string))
>>> 2012-12-12 10:10:10

32

多くのタイムスタンプには暗黙のタイムゾーンがあります。コードがすべてのタイムゾーンで機能するようにするには、内部でUTCを使用し、外部オブジェクトがシステムに入るたびにタイムゾーンをアタッチする必要があります。

Python 3.2以降:

>>> datetime.datetime.strptime(
...     "March 5, 2014, 20:13:50", "%B %d, %Y, %H:%M:%S"
... ).replace(tzinfo=datetime.timezone(datetime.timedelta(hours=-3)))

3
mktime()2番目の方法(datetime.strptime())を知っているのに、なぜ(DST移行中に)醜く、時々間違っている1番目の方法を維持するのですか?あなたは(第二の方法が失敗した)うるう秒の間に例外を回避したいなら、あなたは使用することができますcalendar.timegm:代わりに(datetime(1970,1,1)+timedelta(seconds=timegm(time.strptime(..)))).replace(tzinfo=timezone(timedelta(-3)))
JFS

29

文字列としてフォーマットされた日付をPandasを使用してdatetime.dateオブジェクトに変換する2つのソリューションを次に示します。

import pandas as pd

dates = ['2015-12-25', '2015-12-26']

# 1) Use a list comprehension.
>>> [d.date() for d in pd.to_datetime(dates)]
[datetime.date(2015, 12, 25), datetime.date(2015, 12, 26)]

# 2) Convert the dates to a DatetimeIndex and extract the python dates.
>>> pd.DatetimeIndex(dates).date.tolist()
[datetime.date(2015, 12, 25), datetime.date(2015, 12, 26)]

タイミング

dates = pd.DatetimeIndex(start='2000-1-1', end='2010-1-1', freq='d').date.tolist()

>>> %timeit [d.date() for d in pd.to_datetime(dates)]
# 100 loops, best of 3: 3.11 ms per loop

>>> %timeit pd.DatetimeIndex(dates).date.tolist()
# 100 loops, best of 3: 6.85 ms per loop

OPの元の日時の例を変換する方法は次のとおりです。

datetimes = ['Jun 1 2005  1:33PM', 'Aug 28 1999 12:00AM']

>>> pd.to_datetime(datetimes).to_pydatetime().tolist()
[datetime.datetime(2005, 6, 1, 13, 33), 
 datetime.datetime(1999, 8, 28, 0, 0)]

を使用して文字列からPandasタイムスタンプに変換するための多くのオプションがあるためto_datetime、特別なものが必要な場合はドキュメントを確認してください。

同様に、タイムスタンプには、以下に加えてアクセスできる多くのプロパティとメソッドがあります。.date


26

私は個人的に、parserこの質問への2番目の回答であるモジュールを使用したソリューションを気に入っています。これを機能させるために文字列リテラルを作成する必要がないので、これは素晴らしいことです。しかし、1つの欠点は、で受け入れられた回答より90%遅いことですstrptime

from dateutil import parser
from datetime import datetime
import timeit

def dt():
    dt = parser.parse("Jun 1 2005  1:33PM")
def strptime():
    datetime_object = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

print(timeit.timeit(stmt=dt, number=10**5))
print(timeit.timeit(stmt=strptime, number=10**5))
>10.70296801342902
>1.3627995655316933

あなたがこれを何百万回も繰り返さない限り、私はまだparser方法がより便利で、ほとんどの時間フォーマットを自動的に処理すると思います。


24

ここで言及されていない便利なもの:接尾辞を日付に追加します。日付だけでなく、好きな数値に使用できるように、サフィックスロジックを分離しました。

import time

def num_suffix(n):
    '''
    Returns the suffix for any given int
    '''
    suf = ('th','st', 'nd', 'rd')
    n = abs(n) # wise guy
    tens = int(str(n)[-2:])
    units = n % 10
    if tens > 10 and tens < 20:
        return suf[0] # teens with 'th'
    elif units <= 3:
        return suf[units]
    else:
        return suf[0] # 'th'

def day_suffix(t):
    '''
    Returns the suffix of the given struct_time day
    '''
    return num_suffix(t.tm_mday)

# Examples
print num_suffix(123)
print num_suffix(3431)
print num_suffix(1234)
print ''
print day_suffix(time.strptime("1 Dec 00", "%d %b %y"))
print day_suffix(time.strptime("2 Nov 01", "%d %b %y"))
print day_suffix(time.strptime("3 Oct 02", "%d %b %y"))
print day_suffix(time.strptime("4 Sep 03", "%d %b %y"))
print day_suffix(time.strptime("13 Nov 90", "%d %b %y"))
print day_suffix(time.strptime("14 Oct 10", "%d %b %y"))​​​​​​​

17
In [34]: import datetime

In [35]: _now = datetime.datetime.now()

In [36]: _now
Out[36]: datetime.datetime(2016, 1, 19, 9, 47, 0, 432000)

In [37]: print _now
2016-01-19 09:47:00.432000

In [38]: _parsed = datetime.datetime.strptime(str(_now),"%Y-%m-%d %H:%M:%S.%f")

In [39]: _parsed
Out[39]: datetime.datetime(2016, 1, 19, 9, 47, 0, 432000)

In [40]: assert _now == _parsed

16

Django Timezone対応の日時オブジェクトの例。

import datetime
from django.utils.timezone import get_current_timezone
tz = get_current_timezone()

format = '%b %d %Y %I:%M%p'
date_object = datetime.datetime.strptime('Jun 1 2005  1:33PM', format)
date_obj = tz.localize(date_object)

この変換は、DjangoとPythonで非常に重要ですUSE_TZ = True

RuntimeWarning: DateTimeField MyModel.created received a naive datetime (2016-03-04 00:00:00) while time zone support is active.

12

次のような小さなユーティリティ関数を作成します。

def date(datestr="", format="%Y-%m-%d"):
    from datetime import datetime
    if not datestr:
        return datetime.today().date()
    return datetime.strptime(datestr, format).date()

これは十分に用途が広いです:

  • 引数を渡さない場合、今日の日付が返されます。
  • オーバーライドできるデフォルトの日付形式があります。
  • 日時を返すように簡単に変更できます。

2
formatPythonの予約語であり、変数名として使用しないでください。
2017年

12

文字列を日時に変換したり、タイムゾーンを使用したりするのに役立ちます

def convert_string_to_time(date_string, timezone):
    from datetime import datetime
    import pytz
    date_time_obj = datetime.strptime(date_string[:26], '%Y-%m-%d %H:%M:%S.%f')
    date_time_obj_timezone = pytz.timezone(timezone).localize(date_time_obj)

    return date_time_obj_timezone

date = '2018-08-14 13:09:24.543953+00:00'
TIME_ZONE = 'UTC'
date_time_obj_timezone = convert_string_to_time(date, TIME_ZONE)

9

矢印は、日付と時刻に多くの便利な機能を提供します。このコードは、質問に対する回答を提供し、矢印は日付を簡単にフォーマットし、他のロケールの情報を表示できることも示しています。

>>> import arrow
>>> dateStrings = [ 'Jun 1  2005 1:33PM', 'Aug 28 1999 12:00AM' ]
>>> for dateString in dateStrings:
...     dateString
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').datetime
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').format('ddd, Do MMM YYYY HH:mm')
...     arrow.get(dateString.replace('  ',' '), 'MMM D YYYY H:mmA').humanize(locale='de')
...
'Jun 1  2005 1:33PM'
datetime.datetime(2005, 6, 1, 13, 33, tzinfo=tzutc())
'Wed, 1st Jun 2005 13:33'
'vor 11 Jahren'
'Aug 28 1999 12:00AM'
datetime.datetime(1999, 8, 28, 0, 0, tzinfo=tzutc())
'Sat, 28th Aug 1999 00:00'
'vor 17 Jahren'

詳細については、http://arrow.readthedocs.io/en/latest/を参照してください



4

日付形式のみが必要な場合は、次のように個々のフィールドを渡して手動で変換できます。

>>> import datetime
>>> date = datetime.date(int('2017'),int('12'),int('21'))
>>> date
datetime.date(2017, 12, 21)
>>> type(date)
<type 'datetime.date'>

分割した文字列値を渡して、次のような日付型に変換できます。

selected_month_rec = '2017-09-01'
date_formate = datetime.date(int(selected_month_rec.split('-')[0]),int(selected_month_rec.split('-')[1]),int(selected_month_rec.split('-')[2]))

結果の値は日付形式で取得されます。


2

あなたもチェックすることができます dateparser

dateparser ローカライズされた日付を、Webページで一般的に見られるほとんどすべての文字列形式で簡単に解析するモジュールを提供します。

インストール:

$ pip install dateparser

これは、日付を解析する最も簡単な方法だと思います。

最も簡単な方法はdateparser.parse、モジュールのほとんどの機能をラップする関数を使用することです。

サンプルコード:

import dateparser

t1 = 'Jun 1 2005  1:33PM'
t2 = 'Aug 28 1999 12:00AM'

dt1 = dateparser.parse(t1)
dt2 = dateparser.parse(t2)

print(dt1)
print(dt2)

出力:

2005-06-01 13:33:00
1999-08-28 00:00:00

1

私の答えをください。

実世界のデータでは、これは本当の問題です。1つのデータセットで自由に混合されることが多い、複数の不一致、不完全、一貫性のない、多言語/地域の日付形式です。プロダクションコードが失敗しても問題はありません。キツネのように例外的にハッピーになることは言うまでもありません。

複数の日時形式fmt1、fmt2、...、fmtnをキャッチstrptime()して、不一致となるすべての例外を(から)抑制/処理する必要があります(特に、試行錯誤のn字下げインデントラダーが不要になるようにします) ..catch句)。私の解決策から

def try_strptime(s, fmts=['%d-%b-%y','%m/%d/%Y']):
    for fmt in fmts:
        try:
            return datetime.strptime(s, fmt)
        except:
            continue

    return None # or reraise the ValueError if no format matched, if you prefer

「複数の、不一致、不完全な、一貫性のない、多言語/地域の日付形式」などについての質問は何も述べていません。これは実際の問題である可能性がありますが、ここでは関係ありません。
RoGの

1
@RoG:それは、彼らがいないと述べたことはありません、それは彼らがいた暗示:「膨大なリスト...データベース」。私が取り組んだほとんどすべてのデータベース/ログファイル(小さいサイズであっても)には、複数の日付フォーマット、タイムゾーン識別子、MM-DDなどがありました。本番環境では、フォーマットでハードコードし、例外でクラッシュする脆弱なコードを書くことは受け入れられません。期待した形式を取得しません(Noneまたは ''を返すことも可能です)。したがって、複数のフォーマットが必要です。したがって、これは尋ねられた質問に対処するものであり、私は複数のフォーマットからのエラーを処理するための最もPython的な方法を理解するのに少し時間を費やしました。
smci '10 / 10/18

「巨大なリスト...データベース」は、それらがすべて異なる形式ではなく、それらの多くが存在することを意味します。入力に単一の形式があることがわかっている場合は、単一の形式を読み取るコードを記述することはまったく問題ありません。この場合、正しい形式でないものが渡されるとクラッシュするはずです。
RoG

@RoG:間違った形式/ Unicodeの破損/切り捨て/欠落/データ、NaN、M / D / Y対D / M / Y形式、YY対YYYYなどでクラッシュするプロダクションコードを書くことは受け入れられません。特にこれらの場合私が示したように、7行のソリューションで例外を回避できます。ほとんどの現実の「巨大なデータベース」はそのようなものです。OPが明示的にそれを言わなかったからといって、それが典型的なコンテキストではないという意味ではありません。私はあなたと口論するつもりはありません。どのようなデータセットに取り組んでいますか。また、これらの仮定が妥当だと思うのはなぜですか。私たちが常に介入を必要とするおもちゃのコードについて話しているのでない限り。
smci

1
OPに不整合のないデータが必要であると完全に確信して考えるのは少しばかげているように見えます。はい、そのようなデータを持つことは可能ですが、ここではそうではありません。私はこの回答が役立つと思いました。矛盾が間違いなく問題である非常に類似した質問に対する類似した回答を探す私にとっては、確かにそうです。
ポールミラー

1
emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv")
emp.info()

「開始日時」列と「最終ログイン時間」の両方がデータフレームの「オブジェクト=文字列」であることを示しています

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 8 columns):
First Name           933 non-null object
Gender               855 non-null object
Start Date           1000 non-null object

Last Login Time      1000 non-null object
Salary               1000 non-null int64
Bonus %              1000 non-null float64
Senior Management    933 non-null object
Team                 957 non-null object
dtypes: float64(1), int64(1), object(6)
memory usage: 62.6+ KB

言及のparse_datesオプションを使用することによりread_csv、文字列の日時をパンダの日時形式に変換できます。

emp = pd.read_csv("C:\\py\\programs\\pandas_2\\pandas\\employees.csv", parse_dates=["Start Date", "Last Login Time"])
emp.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 8 columns):
First Name           933 non-null object
Gender               855 non-null object
Start Date           1000 non-null datetime64[ns]
Last Login Time      1000 non-null datetime64[ns]
Salary               1000 non-null int64
Bonus %              1000 non-null float64
Senior Management    933 non-null object
Team                 957 non-null object
dtypes: datetime64[ns](2), float64(1), int64(1), object(4)
memory usage: 62.6+ KB
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.