Pythonでparsedatetimeを使って日付の文字列を解析する

このチュートリアルでは、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はパースに失敗したことを意味し、1dateへのパースが成功したことを、2timeへのパースが成功したことを、3datetime` へのパースが成功したことを意味します。

この出力を解析してみましょう。

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


これで、 parsedatetimepytz パッケージをスクリプトにインポートして、標準の 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', ...]


この中から最初のようなものを選んで、 CalendarparseDT() 関数の 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オブジェクトを介してアクセスすることができます。

ここでは、BirthdayEpoch80` に設定している。

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つが localeIDuserPyICU です。

試しに、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 やロケールを使用してタイムゾーンを処理する方法について説明しました。

タイトルとURLをコピーしました