2008-11-20 10 views

Répondre

57

J'ai récemment pour résoudre moi-même ce problème, et est venu avec cette solution:

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) 

Quelques cas de 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

Pouvez-vous clarifier la signification du 4 janvier? Existe-t-il une description de la norme de calendrier ISO quelque part? – Tom

+6

Tom: à partir de la définition ISO formelle de la semaine 1 (la semaine contenant le premier jeudi de l'année), il s'ensuit que le 4 janvier est le dernier jour que la semaine 1 peut commencer. –

+1

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

-1

EDIT: ignorez ceci, les cas de bord sont une douleur. Aller avec la solution de Ben.

Ok, regardant de plus près je remarqué que strptime a %W et %w paramètres, donc les travaux suivants:

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

Quelques gotchas: Le numéro de la semaine ISO commence à 1, tandis que %W commence à 0 . Le jour de la semaine ISO commence à 1 (lundi), qui est le même que celui %w, donc dimanche devrait probablement être 0, pas 7 ...

+0

Quelle version utilisez-vous?, Je testais sur 2.4.2 et ne fonctionnait pas pour moi, trouvé http://bugs.python.org/issue1045381 mais dit que c'est fait sur 2.3 –

+0

J'utilise 2.5. 2,% W fonctionne, pas sûr de% U. – Tom

+0

Cela ressemble à ce que vous avez répondu. Pourquoi ne pas accepter votre réponse? –

0

Notez que% W est la semaine # (0-53) qui N'EST PAS LA MÊME que la semaine ISO (1-53). Il y aura des cas limites où% W ne fonctionnera pas.

+0

J'ai en quelque sorte noté que dans ma réponse ci-dessus, une chance que vous pourriez développer sur ce que ces cas de bordure seraient? – Tom

+0

@Tom, années 2009 et 2013, par exemple. – 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) 

Cela a été adapté de @ BenJames est très bien répondre. Vous n'avez pas besoin de connaître le premier jour de l'année. Il suffit de connaître un exemple de date qui correspond certainement à la même année ISO, ainsi que la semaine et le jour du calendrier ISO de cette date.

Le 4 janvier est simplement un exemple, car, comme Ben l'a souligné, le 4 janvier appartient toujours à la même année ISO et à l'année grégorienne, et c'est le premier jour de l'année à le faire. Comme les semaines sont toutes de la même longueur, vous pouvez simplement soustraire les jours et les semaines entre l'ISO de la date que vous voulez, et l'ISO de la date que vous connaissez dans les deux formes, et ajouter ce nombre de jours et semaines. (Peu importe si ces chiffres sont positifs ou négatifs, vous pouvez donc choisir un autre « jour fixe », comme le 28 décembre.)

Modifier

Je corrigeais cela parce que, comme cela a été souligné par @ obligeamment JoSo, le premier jour de l'année grégorienne qui appartient également à l'année ISO est le 4 janvier et non le 5 janvier. Comme l'indique l'explication, peu importe la date choisie comme point de référence, mais choisir le 4 janvier rend ce choix moins «magique».

+1

Pourriez-vous s'il vous plaît me dire, si cela fonctionne vraiment sans faille dans chaque situation? – Geeocode

+3

@GeorgeSolymosi J'ai utilisé la bibliothèque de tests d'hypothèses Python pour rechercher des objets 'datetime' valides pour lesquels cette fonction n'est pas l'inverse de' isocalendar'. Il n'a pas trouvé de/See https://github.com/jwg4/qual/blob/master/qual/tests/test_iso.py Ce n'est pas une garantie bien sûr - je serais intéressé à entendre parler de bugs. Si vous travaillez selon la logique du code, vous pourriez ou non être convaincu qu'il fait la bonne chose. – jwg

+0

c'est plus compliqué que nécessaire. Regardez la réponse de Ben ou ou sur Wikipedia. Le 4 janvier fera également l'affaire et se situe toujours dans la première semaine ISO de son année ISO. –

1

À partir de Python 3.6, datetime.strptime() soutiendra les %G, %V et %u directives, de sorte que vous pouvez simplement faire datetime.strptime('2015 1 2', '%G %V %u').date(). Voir: https://hg.python.org/cpython/rev/acdebfbfbdcf

4

À partir de Python 3.6 (actuellement in development), vous pouvez utiliser les nouveaux %G, %u et %V directives.Voir issue 12006 et updated documentation:

%G
ISO 8601 année avec le siècle représentant l'année qui contient la plus grande partie de la semaine ISO (%V).

%u
ISO 8601 jour en nombre décimal où 1 est lundi.

%V
ISO 8601 semaine sous forme de nombre décimal avec lundi comme premier jour de la semaine. Semaine 01 est la semaine contenant Jan 4.

d'une chaîne à l'année, Semaine n ° et le numéro de la semaine, il est facile d'analyser les sortir à une date avec:

from datetime import date 

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

ou en fonction de entrées entières:

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

Pour les prochaines personnes qui viennent ici, une seule définition plus courte, la version, la bonne solution de 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) 
Questions connexes