このチュートリアルでは、Pythonで parsedatetime
を使ってDatetimeをパースする方法について見ていきます。
parsedatetime`パッケージを使用するには、まずpipでインストールする必要があります。
$ pip install parsedatetime
pip install parsedatetime` に失敗した場合、このパッケージはオープンソースでGithubから入手することもできます。
parsedatetimeで文字列をPythonのDatetimeオブジェクトに変換する
最初の、そして最も一般的な parsedatetime
の使い方は、文字列をパースして datetime
オブジェクトに変換することです。
まず、 parsedatetime
ライブラリをインポートして、 Calendar
オブジェクトのインスタンスを作成します。
このオブジェクトは、実際の入力、パース、日付の操作を行うものです。
import parsedatetime
calendar = parsedatetime.Calendar()
ここで、文字列を引数として calendar
インスタンスの parse()
メソッドを呼び出すことができます。
1-1-2021のような通常の datetime フォーマットの文字列や、
tomorrow,
yesterday,
next year,
last week,
lunch tomorrowなどの人間が読みやすい値を入力することができる... また、
tomorrow eodを使用して、
‘End of Day’` 構造体を使用することもできる。
それでは、 parsedatetime
を用いて、日付と人間が読み取れる文字列を datetime
オブジェクトに変換してみよう。
import parsedatetime
from datetime import datetime
calendar = parsedatetime.Calendar()
print(calendar.parse('tomorrow'))
print(calendar.parse('1-1-2021'))
この結果、2つのタプルが出力されます。
(time.struct_time(tm_year=2021, tm_mon=3, tm_mday=19, tm_hour=9, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=78, tm_isdst=-1), 1)
(time.struct_time(tm_year=2021, tm_mon=1, tm_mday=1, tm_hour=18, tm_min=5, tm_sec=14, tm_wday=3, tm_yday=77, tm_isdst=0), 1)
これはあまり人間には読めませんね…。
それぞれの変換で返されるタプルは struct_time
オブジェクトからなり、年、月、日などの情報が含まれています。
2 番目の値はステータスコードで、変換がどのように行われたかを表す整数値である。
0はパースに失敗したことを意味し、
1は
dateへのパースが成功したことを、
2は
timeへのパースが成功したことを、
3は
datetime` へのパースが成功したことを意味します。
この出力を解析してみましょう。
print(calendar.parse('tomorrow')[0].tm_mday)
print(calendar.parse('1-1-2021')[0].tm_mday)
このコードの結果は
19
1
しかし、ここでは月の日数しか表示されていません。
通常は、YYYY-mm-dd HH:mm:ss
のような形式か、そのバリエーションを出力したいと思うでしょう。
ありがたいことに、 time.struct_time
の結果を使用して、通常のPythonの datetime
を簡単に生成することができます。
import parsedatetime
from datetime import datetime
calendar = parsedatetime.Calendar()
time_structure_tomorrow, parse_status_tomorrow = calendar.parse('tomorrow')
time_structure_2021, parse_status_2021 = calendar.parse('1-1-2021')
print(datetime(*time_structure_tomorrow[:6]))
print(datetime(*time_structure_2021[:6]))
datetime()コンストラクタは、
parsedatetime` が提供する時間構造からすべての情報を必要としないので、それをスライスしています。
このコードの結果は
2021-03-19 09:00:00
2021-01-01 18:11:06
1月1日の datetime
は実行時刻を考慮したものであることに注意してください。
タイムゾーンの扱い
時には、アプリケーションがエンドユーザーのタイムゾーンを考慮する必要があるかもしれません。
タイムゾーンをサポートするために、私たちは通常Pytzパッケージを使用しますが、他のパッケージを使用することも可能です。
それでは、pip
を使ってPytzをインストールしましょう。
$ pip install pytz
これで、 parsedatetime
と pytz
パッケージをスクリプトにインポートして、標準の Calendar
インスタンスを作成することができます。
import parsedatetime
import pytz
from pytz import timezone
calendar = parsedatetime.Calendar()
all_timezones`を出力して、サポートされているタイムゾーンを確認しましょう。
print(pytz.all_timezones)
このコードでは、利用可能なすべてのタイムゾーンの巨大なリストが生成されます。
['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', ...]
この中から最初のようなものを選んで、 Calendar
の parseDT()
関数の tzinfo
引数として渡します。
その他に、 datetimeString
引数を指定します。
これは、実際にパースしたい文字列を指定します。
datetime_object, status = calendar.parseDT(datetimeString='tomorrow', tzinfo=timezone('Africa/Abidjan'))
このメソッドは、 Datetime
オブジェクトと、変換のステータスコード (整数値) – 1
は “成功”、 0
は “失敗” を意味します – をタプルで返します。
それでは、 datetime_object
を表示してみましょう。
print(datetime_object)
このコードの結果は
2021-03-16 09:00:00+00:00
Calendar.parseDate()
Calendar.parse()が一般的なレベルのパースメソッドで、ステータスコードと
time.struct_timeを含むタプルを返すのに対し、
parseDate()` メソッドは短い形式の日付文字列専用のメソッドで、単に人間が読める結果を返します。
import parsedatetime
calendar = parsedatetime.Calendar()
result = calendar.parseDate('5/5/91')
print(result)
結果 result
には、渡された日付の struct_time
値が格納されています。
(1991, 5, 5, 14, 31, 18, 0, 74, 0)
しかし、2077年5月5日をパースしたい場合はどうすればいいのでしょうか?次のようなコードを実行してみてください。
import parsedatetime
calendar = parsedatetime.Calendar()
result = calendar.parseDate('5/5/77')
print(result)
しかし、このコードでは、次のような結果になります。
(1977, 5, 5, 14, 36, 21, 0, 74, 0)
Calendar.parseDate()が短い形式の日付と、より現実的な
1977` を間違えたのです。
これを解決するには、2つの方法があります。
- 単純に完全な年号を指定する –
2077
:
import parsedatetime
calendar = parsedatetime.Calendar()
result = calendar.parseDate('5/5/2077')
print(result)
- 誕生日エポック(BirthdayEpoch)を使用する。
import parsedatetime
constants = parsedatetime.Constants()
constants.BirthdayEpoch = 80
# Pass our new constants to the Calendar
calendar = parsedatetime.Calendar(constants)
result = calendar.parseDate('5/5/77')
print(result)
このコードは次のようになります。
(2077, 5, 5, 14, 39, 47, 0, 74, 0)
parsedatetimeライブラリの定数には、
Constantsオブジェクトを介してアクセスすることができます。
ここでは、BirthdayEpochを
80` に設定している。
BirthdayEpochはパッケージが二桁の年、例えば
77をどのように扱うかをコントロールします。
もし、解析された値がBirthdayEpochに設定した値よりも小さければ、解析された値は
2000に追加されます。
BirthdayEpoch を 80
に設定し、77
をパースしたので、2077
に変換されます。
そうでなければ、解析された値を 1900
に追加します。
Calendar.parseDateText()
短い形式の日付の間違いに対処するもうひとつの方法は、長い形式の日付を使用することです。
長い形式の日付の場合は、 parseDateText()
メソッドを使用します。
import parsedatetime
result2 = calendar.parseDateText('May 5th, 1991')
print(result2)
このコードは次のようになります。
(1991, 5, 5, 14, 31, 46, 0, 74, 0)
ロケールの使用
最後に、 parsedatetime
をロケール情報とともに使用することができます。
ロケール情報は PyICU か、以前に使用した Constants
クラスから取得します。
内部クラスの Constants
は、 BirthdayEpoch
属性と同じように多くの属性を持っています。
そのうちの2つが localeID
と userPyICU
です。
試しに、localeId
をSpanishにして、usePyICU
は使わないのでFalse
に設定してみましょう。
import parsedatetime
constants = parsedatetime.Constants(localeID='es', usePyICU=False)
calendar = parsedatetime.Calendar(constants)
result, code = calendar.parse('Marzo 28')
print(result)
この結果、次のようになります。
(time.struct_time(tm_year=2021, tm_mon=3, tm_mday=28, tm_hour=15, tm_min=0, tm_sec=5, tm_wday=0, tm_yday=74, tm_isdst=0), 1)
このメソッドは struct_time
を返すので、これを簡単に datetime
に変換することができます。
print(datetime(*result[:6]))
この結果は次のようになります。
2021-03-28 22:08:40
結論
このチュートリアルでは、Python の parsedatetime
パッケージを使用して日時をパースするいくつかの方法について説明しました。
文字列と parsedatetime
オブジェクトの変換、そして parsedatetime
ライブラリの Constants
インスタンスを使用して、 pytz
やロケールを使用してタイムゾーンを処理する方法について説明しました。