2008-11-20 13 views

Odpowiedz

57

Niedawno miałem rozwiązać ten problem się i wpadł na to rozwiązanie:

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) 

kilku przypadkach Test:

>>> 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) 
+0

Czy możesz wyjaśnić znaczenie 4 stycznia? Czy jest gdzieś odpowiedni opis normy kalendarza ISO? – Tom

+6

Tom: z oficjalnej definicji ISO z pierwszego tygodnia (tygodnia zawierającego pierwszy czwartek roku) wynika, że ​​4 stycznia jest najpóźniej w tym tygodniu, od którego można rozpocząć 1. –

+1

http://en.wikipedia.org/wiki/ISO_week_date – Tom

-1

EDYCJA: zignoruj ​​to, skrzynie brzegowe są uciążliwe. Idź z rozwiązaniem Bena.

Ok, po bliższym przyjrzeniu zauważyłem, że strptime ma %W i %w parametry, więc następujące prace:

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

Kilka pułapek: Numer ISO tydzień rozpoczyna się 1, natomiast %W rozpoczyna się 0 . Dzień tygodnia ISO rozpoczyna się 1 (poniedziałek), która jest taka sama jak %w, więc niedziela będzie prawdopodobnie musiał być 0 nie 7 ...

+0

Którą wersję używasz ?, testowałem w wersji 2.4.2 i nie działało dla mnie, znalazłem http://bugs.python.org/issue1045381, ale powiedziałem, że zrobiono to na 2.3 –

+0

Używam 2.5. 2,% W działa, nie jesteś pewien% U. – Tom

+0

Wygląda na to, że na niego odpowiedziałeś. Dlaczego nie przyjąć odpowiedzi? –

0

Należy pamiętać, że% W jest tydzień # (0,53), który NIE JEST TO SAMO jako tydzień ISO (1-53). Będą przypadki skrajne, w których% W nie będzie działać.

+0

W pewnym sensie zauważyłem, że w mojej odpowiedzi powyżej, jakąkolwiek szansę, mógłbyś rozwinąć na tym, czym byłyby te przypadki krańcowe? – Tom

+0

@ Tom, lata 2009 i 2013, na przykład. – akaihola

7
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) 

ten został zaadaptowany z @ BenJames bardzo dobra odpowiedź. Nie musisz znać pierwszego dnia w roku. Musisz tylko poznać przykład daty, która z pewnością jest w tym samym roku ISO, oraz kalendarz ISO tygodnia i dzień tej daty.

Czwarty stycznia jest po prostu jeden przykład, ponieważ, jak Ben wskazał, czwarty z Jan zawsze należy do tego samego roku ISO i roku gregoriańskiego, i jest pierwszym dniem w roku, aby to zrobić.

Ponieważ tygodnie są tej samej długości, można po prostu odjąć dni i tygodnie między ISO daty, która ma, a ISO daty, którą znasz w obu formach i dodać tę liczbę dni i tygodnie. (Nie ma znaczenia, czy te liczby są dodatnie lub ujemne, więc można wybrać inny dzień „stałe”, takich jak lis 28th.)

Edycja

poprawiłem tego powodu, jak to wskazał usłużnie przez @ JoSo, pierwszy dzień roku gregoriańskiego, który również należy do roku ISO, to 4 stycznia, a nie 5 stycznia. Jak wyjaśnia wyjaśnienie, nie ma znaczenia, która data zostanie wybrana jako punkt odniesienia, ale wybór czwartego stycznia sprawia, że ​​wybór ten jest mniej "magiczny".

+1

Czy możesz mi powiedzieć, czy naprawdę działa bez zarzutu w każdej sytuacji? – Geeocode

+3

@GeorgeSolymosi Użyłem biblioteki testów Pythona dla hipotez w celu wyszukania jakichkolwiek poprawnych obiektów 'datetime', dla których ta funkcja nie jest odwrotnością' isocalendar'. Nie znaleziono żadnych/Zobacz https://github.com/jwg4/qual/blob/master/qual/tests/test_iso.py Nie jest to oczywiście gwarancja - byłbym zainteresowany usłyszeniem o jakichkolwiek błędach. Jeśli pracujesz zgodnie z logiką kodu, możesz lub nie być przekonanym, że robi to dobrze. – jwg

+0

jest to bardziej skomplikowane niż to konieczne. Spójrz na odpowiedź Bena lub na Wikipedię. Czwarty dzień będzie równie dobry, a ponadto zawsze znajduje się w pierwszym tygodniu ISO roku ISO. –

4

Jak Pythona 3.6 (obecnie in development), można korzystać z nowych %G, %u i %V dyrektyw.Zobacz issue 12006 i updated documentation:

%G
ISO 8601 rok z wieku reprezentującą rok, który zawiera większą część tygodnia ISO (%V).

%u Dzień tygodnia ISO 8601 jako liczba dziesiętna, gdzie 1 oznacza poniedziałek.

%V
Tydzień ISO 8601 jako liczba dziesiętna z poniedziałkiem jako pierwszym dniem tygodnia. Tydzień 01 jest tydzień zawierający sty 4.

Podając łańcuch z roku, weeknumber i liczby dni tygodnia, to jest łatwe do analizowania tych się na bieżąco z:

from datetime import date 

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

lub jako funkcja z całkowite nakłady:

from datetime import date 

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

przez następne osób przybywających tutaj, krótszy, single-def, wersja dobrego rozwiązania Bena:

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) 
Powiązane problemy