datetime.isocalendar()の逆を見つける最良の方法は何ですか?

StackOverflow https://stackoverflow.com/questions/304256

  •  08-07-2019
  •  | 
  •  

質問

Python datetime.isocalendar() メソッドは、指定された datetime オブジェクトのタプル(ISO_year、ISO_week_number、ISO_weekday)を返します。対応する逆関数はありますか?そうでない場合、年、週番号、曜日を指定して日付を計算する簡単な方法はありますか?

役に立ちましたか?

解決

最近、この問題を自分で解決する必要があり、この解決策を思いつきました:

import datetime

def iso_year_start(iso_year):
    "The gregorian calendar date of the first day of the given ISO year"
    fourth_jan = datetime.date(iso_year, 1, 4)
    delta = datetime.timedelta(fourth_jan.isoweekday()-1)
    return fourth_jan - delta 

def iso_to_gregorian(iso_year, iso_week, iso_day):
    "Gregorian calendar date for the given ISO year, week and day"
    year_start = iso_year_start(iso_year)
    return year_start + datetime.timedelta(days=iso_day-1, weeks=iso_week-1)

いくつかのテストケース:

>>> iso = datetime.date(2005, 1, 1).isocalendar()
>>> iso
(2004, 53, 6)
>>> iso_to_gregorian(*iso)
datetime.date(2005, 1, 1)

>>> iso = datetime.date(2010, 1, 4).isocalendar()    
>>> iso
(2010, 1, 1)
>>> iso_to_gregorian(*iso)
datetime.date(2010, 1, 4)

>>> iso = datetime.date(2010, 1, 3).isocalendar()
>>> iso
(2009, 53, 7)
>>> iso_to_gregorian(*iso)
datetime.date(2010, 1, 3)

他のヒント

import datetime

def iso_to_gregorian(iso_year, iso_week, iso_day):
    "Gregorian calendar date for the given ISO year, week and day"
    fourth_jan = datetime.date(iso_year, 1, 4)
    _, fourth_jan_week, fourth_jan_day = fourth_jan.isocalendar()
    return fourth_jan + datetime.timedelta(days=iso_day-fourth_jan_day, weeks=iso_week-fourth_jan_week)

これは、@ BenJamesの非常に良い回答から引用したものです。年の最初の日を知る必要はありません。確かに同じISO年にある日付の例と、その日付のISOカレンダーの週と日を知る必要があります。

1月4日は、Benが指摘したように、1月4日は常に同じISO年とグレゴリオ暦の年に属し、その年の最初の日であるため、単なる例です。

週はすべて同じ長さなので、必要な日付のISOと両方の形式で知っている日付のISOの間の日数と週数を単に減算し、その日数と週数を加算することができます。 (これらの数値が正か負かは関係ないので、12月28日など、他の「固定日」を選択できます。)

編集

これを修正しました。@ JoSoが有益に指摘したように、グレゴリオ暦年の最初の日はISO年にも属し、1月5日ではなく1月4日です。説明が示すように、基準点としてどの日付が選択されるかは問題ではありませんが、1月4日を選択すると、この選択は「魔法」ではなくなります。

Python 3.6では、新しい%G %u 、および%V ディレクティブを使用できます。 issue 12006 および更新されたドキュメント

  

%G
  ISO週の大部分を含む年を表す世紀を含むISO 8601年(%V )。

     

%u
  10進数としてのISO 8601の曜日(1は月曜日)。

     

%V
  月曜日を週の最初の日とする10進数としてのISO 8601週。週01は、1月4日を含む週です。

年、週番号、曜日番号を含む文字列を指定すると、それらを日付に簡単に解析できます。

from datetime import datetime

datetime.strptime('2002 01 1', '%G %V %u').date()

または整数入力の関数として:

from datetime import datetime

def date_from_isoweek(iso_year, iso_weeknumber, iso_weekday):
    return datetime.strptime(
        '{:04d} {:02d} {:d}'.format(iso_year, iso_weeknumber, iso_weekday),
        '%G %V %u').date()

Python 3.6以降、 datetime.strptime()%G %V 、および%u ディレクティブを使用して、 datetime.strptime( '2015 1 2'、 '%G%V%u')。date()を実行できます。参照: https://hg.python.org/cpython/rev/acdebfbfbdcf

次に来る人のために、Benの優れたソリューションのより短いシングル定義バージョン:

def iso_to_gregorian(iso_year, iso_week, iso_day):
    jan4 = datetime.date(iso_year, 1, 4)
    start = jan4 - datetime.timedelta(days=jan4.isoweekday()-1)
    return start + datetime.timedelta(weeks=iso_week-1, days=iso_day-1)

%Wは週#(0-53)であり、ISO週(1-53)とは異なることに注意してください。 %Wが機能しないエッジケースがあります。

Ben Jamesが投稿したものに似たソリューションを思いつきましたが、1つの関数を使用しました:

import datetime
def getDateFromWeek(year,week,day):
    """Method to retrieve the date from the specified week, year and weekday"""

    year_start = datetime.date(year,1,1)
    ys_weekday =  year_start.weekday()
    delta = (week*7)+(day-ys_weekday)
    if ys_weekday<4:
        delta -= 7

    return  year_start  + datetime.timedelta(days=delta)

2020年の最後の週や2021年の最初の週などの境界値でテストしましたが、かなりうまくいきました。

編集:これを無視してください。エッジケースは苦痛です。ベンのソリューションを使用してください。

OK、よく調べてみると、 strptime には%W %w のパラメーターがあるため、次のように動作します:

def fromisocalendar(y,w,d):
   return datetime.strptime( "%04dW%02d-%d"%(y,w-1,d), "%YW%W-%w")

いくつかの落とし穴:ISO週番号は 1 から始まり、%W 0 から始まります。 ISOの曜日は 1 (月曜日)から始まり、これは%w と同じです。したがって、日曜日はおそらく 0 である必要があります。 7 ...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top