web-dev-qa-db-ja.com

文字列に任意の形式の日付があるかどうかを確認します

文字列を日付に解析できるかどうかを確認するにはどうすればよいですか?

  • 1990年1月19日
  • 1990年1月19日
  • 1990年1月19日
  • 1990年1月19日
  • 90年1月19日
  • 1990
  • 1990年1月
  • 1990年1月

これらはすべて有効な日付です。アイテム#3のアイテムと上記の最後のアイテムの間にスペースがないことに懸念がある場合は、必要に応じて文字/文字と数字の間にスペースを自動的に挿入することで簡単に修正できます。

しかし、最初に、基本:

if statementに入れてみました:

if datetime.strptime(item, '%Y') or datetime.strptime(item, '%b %d %y') or datetime.strptime(item, '%b %d %Y')  or datetime.strptime(item, '%B %d %y') or datetime.strptime(item, '%B %d %Y'):

しかし、それはtry-exceptブロックにあり、次のようなものを返し続けます:

16343 time data 'JUNE1890' does not match format '%Y'

それ以外の場合、ifステートメントの最初の条件を満たしました。

明確にするために、私は実際に日付の値を必要としません-私はちょうどそれがそうであるかどうか知りたいです。理想的には、次のようなものになっているでしょう。

if item is date:
    print date
else:
    print "Not a date"

これを行う方法はありますか?

34
zack_falcon

parse_dateutils.parser_ の関数は、多くの日付文字列形式をdatetimeオブジェクトに解析できます。

特定の文字列couldが有効な日付を表すか含むかを単に知りたい場合は、次の簡単な関数を試してみてください。

_from dateutil.parser import parse

def is_date(string, fuzzy=False):
    """
    Return whether the string can be interpreted as a date.

    :param string: str, string to check for date
    :param fuzzy: bool, ignore unknown tokens in string if True
    """
    try: 
        parse(string, fuzzy=fuzzy)
        return True

    except ValueError:
        return False
_

次にあります:

_>>> is_date("1990-12-1")
True
>>> is_date("2005/3")
True
>>> is_date("Jan 19, 1990")
True
>>> is_date("today is 2019-03-27")
False
>>> is_date("today is 2019-03-27", fuzzy=True)
True
>>> is_date("Monday at 12:01am")
True
>>> is_date("xyz_not_a_date")
False
>>> is_date("yesterday")
False
_

カスタム解析

parseは、日付として処理したくない日付として一部の文字列を認識する場合があります。例えば:

  • _"12"_および_"1999"_を解析すると、文字列内の数値が日と年に置き換えられた現在の日付を表すdatetimeオブジェクトが返されます

  • _"23, 4"_および_"23 4"_は、datetime.datetime(2023, 4, 16, 0, 0)として解析されます。

  • _"Friday"_は、将来の最も近い金曜日の日付を返します。
  • 同様に、_"August"_は、月が8月に変更された現在の日付に対応します。

また、parseはロケールを認識しないため、英語以外の言語の月または曜日を認識しません。

これらの問題は両方とも、カスタムの parserinfo クラスを使用することで、ある程度対処できます。このクラスは、月と日の名前の認識方法を定義します。

_from dateutil.parser import parserinfo

class CustomParserInfo(parserinfo):

    # three months in Spanish for illustration
    MONTHS = [("Enero", "Enero"), ("Feb", "Febrero"), ("Marzo", "Marzo")]
_

このクラスのインスタンスは、parseで使用できます。

_>>> parse("Enero 1990")
# ValueError: Unknown string format
>>> parse("Enero 1990", parserinfo=CustomParserInfo())
datetime.datetime(1990, 1, 27, 0, 0)
_
67
Alex Riley

これらの特定の形式を解析する場合は、形式のリストと照合するだけで済みます。

txt='''\
Jan 19, 1990
January 19, 1990
Jan 19,1990
01/19/1990
01/19/90
1990
Jan 1990
January1990'''

import datetime as dt

fmts = ('%Y','%b %d, %Y','%b %d, %Y','%B %d, %Y','%B %d %Y','%m/%d/%Y','%m/%d/%y','%b %Y','%B%Y','%b %d,%Y')

parsed=[]
for e in txt.splitlines():
    for fmt in fmts:
        try:
           t = dt.datetime.strptime(e, fmt)
           parsed.append((e, fmt, t)) 
           break
        except ValueError as err:
           pass

# check that all the cases are handled        
success={t[0] for t in parsed}
for e in txt.splitlines():
    if e not in success:
        print e    

for t in parsed:
    print '"{:20}" => "{:20}" => {}'.format(*t) 

プリント:

"Jan 19, 1990        " => "%b %d, %Y           " => 1990-01-19 00:00:00
"January 19, 1990    " => "%B %d, %Y           " => 1990-01-19 00:00:00
"Jan 19,1990         " => "%b %d,%Y            " => 1990-01-19 00:00:00
"01/19/1990          " => "%m/%d/%Y            " => 1990-01-19 00:00:00
"01/19/90            " => "%m/%d/%y            " => 1990-01-19 00:00:00
"1990                " => "%Y                  " => 1990-01-01 00:00:00
"Jan 1990            " => "%b %Y               " => 1990-01-01 00:00:00
"January1990         " => "%B%Y                " => 1990-01-01 00:00:00
11
dawg