Quelle est la meilleure façon de trouver l'inverse de type datetime.isocalendar ()?

Le Python datetime.isocalendar() méthode retourne un tuple (ISO_year, ISO_week_number, ISO_weekday) pour le datetime objet. Y a-t-il une fonction inverse correspondante? Dans la négative, y a-t-il un moyen facile de calculer une date donnée par année, par semaine et par jour de la semaine?

39
demandé sur Joe Doyle 2008-11-20 06:38:52

7 réponses

j'ai dû récemment résoudre ce problème moi-mê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 d'essai:

>>> 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)
60
répondu Ben James 2011-05-04 12:23:01
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)

adapté de la très bonne réponse de @BenJames. Vous n'avez pas à savoir le premier jour de l'année. Vous avez juste à connaître un exemple d'une date qui est certainement dans la même année ISO, et le calendrier ISO semaine et le jour de cette date.

le 4 Janvier est simplement un exemple, parce que, comme Ben l'a souligné, le 4 janvier appartient toujours à la même année ISO et année Grégorienne, et est le premier jour de l'année pour le faire.

Puisque 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 sur ce nombre de jours et de semaines. (Peu importe que ces chiffres soient positifs ou négatifs, vous pouvez donc choisir un autre "jour fixe" comme le 28 décembre.)

Modifier

j'ai corrigé cela parce que, comme l'a souligné avec aide @JoSo, le premier jour de l'année Grégorienne qui appartient également à L'année ISO est le 4 janvier 4 pas le 5 janvier. Comme le dit l'explication, peu importe la date choisie comme point de référence, mais choisir le 4 janvier rend ce choix moins "magique".

8
répondu jwg 2016-07-11 14:03:42

à partir de Python 3.6 (actuellement en développement ), vous pouvez utiliser les nouvelles directives %G , %u et %V . Voir numéro 12006 et la mise à jour de la documentation :

%G

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

%u

ISO 8601 jour de semaine en nombre décimal où 1 est lundi.

%V

ISO 8601 semaine en nombre décimal avec le lundi comme premier jour de la semaine. La semaine 01 est celle du 4 janvier.

étant donné une chaîne avec l'année, le nombre de semaines et le nombre de jours de semaine, il est facile de séparer ceux à une date avec:

from datetime import date

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

ou en tant que fonction avec 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')
4
répondu Martijn Pieters 2018-08-08 03:23:47

pour les prochains venus ici, une version plus courte et simple de 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)
3
répondu Jo So 2016-07-09 16:02:46

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

1
répondu Erik Cederstrand 2016-02-03 02:23:42

noter 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 extrêmes où %W ne fonctionnera pas.

0
répondu 2008-12-19 23:21:07

EDIT: ignorer cela, les cas de bord sont une douleur. Suis la solution de Ben.

Ok, sur une inspection plus étroite, j'ai 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")

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

-1
répondu Tom 2010-02-11 06:30:28