Domanda

The Python datetime.isocalendar () restituisce un tupla (ISO_year, ISO_week_number, ISO_weekday) per l'oggetto datetime specificato. Esiste una funzione inversa corrispondente? In caso contrario, esiste un modo semplice per calcolare una data data un anno, il numero della settimana e il giorno della settimana?

È stato utile?

Soluzione

Di recente ho dovuto risolvere questo problema da solo, e ho trovato questa soluzione:

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)

Alcuni casi di 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)

Altri suggerimenti

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)

Questo è stato adattato dall'ottima risposta di @ BenJames. Non devi conoscere il primo giorno dell'anno. Devi solo conoscere un esempio di una data che è certamente nello stesso anno ISO e la settimana e il giorno del calendario ISO di quella data.

Il 4 gennaio è semplicemente un esempio, perché, come ha sottolineato Ben, il 4 gennaio appartiene sempre allo stesso anno ISO e anno gregoriano, ed è il primo giorno dell'anno a farlo.

Poiché le settimane hanno tutte la stessa lunghezza, puoi semplicemente sottrarre i giorni e le settimane tra l'ISO della data desiderata e l'ISO della data che conosci in entrambi i moduli e aggiungere quel numero di giorni e settimane . (Non importa se questi numeri sono positivi o negativi, quindi puoi scegliere qualche altro "giorno fisso" come il 28 dicembre.)

Modifica

L'ho corretto perché, come è stato utile sottolineato da @JoSo, il primo giorno dell'anno gregoriano che appartiene anche all'anno ISO è il 4 gennaio e non il 5 gennaio. Come dice la spiegazione, non importa quale data sia stata scelta come punto di riferimento, ma la scelta del 4 gennaio rende questa scelta meno "magica".

A partire da Python 3.6, puoi usare le nuove direttive % G , % u e % V . Vedi numero 12006 e documentazione aggiornata :

  

% G
  ISO 8601 anno con secolo che rappresenta l'anno che contiene la maggior parte della settimana ISO (% V ).

     

% u
  ISO 8601 giorno della settimana come numero decimale dove 1 è lunedì.

     

% V
  Settimana ISO 8601 come numero decimale con lunedì come primo giorno della settimana. La settimana 01 è la settimana contenente il 4 gennaio.

Data una stringa con anno, numero della settimana e numero del giorno della settimana, è facile analizzarli fino a una data con:

from datetime import datetime

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

o come funzione con input interi:

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

A partire da Python 3.6, datetime.strptime () supporterà % G , % V e % u direttive, quindi puoi semplicemente fare datetime.strptime ('2015 1 2', '% G% V% u'). date () . Vedi: https://hg.python.org/cpython/rev/acdebfbfbdcf

Per le prossime persone che verranno qui, una versione più breve, a definizione singola, della buona soluzione di 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)

Nota che% W è la settimana # (0-53) che NON È LO STESSO della settimana ISO (1-53). Ci saranno casi limite in cui% W non funzionerà.

Ho trovato una soluzione simile a quella pubblicata da Ben James, ma usando una sola funzione:

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)

L'ho provato con valori limite come l'ultima settimana del 2020 e la prima settimana del 2021, e ha funzionato abbastanza bene.

EDIT: ignoralo, i casi limite sono un dolore. Vai con la soluzione di Ben.

Ok, a un esame più attento ho notato che strptime ha i parametri % W e % w , quindi i seguenti lavori:

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

Un paio di gotcha: il numero della settimana ISO inizia da 1 , mentre % W inizia da 0 . Il giorno della settimana ISO inizia a 1 (lunedì), che equivale a % w , quindi probabilmente domenica dovrebbe essere 0 , non 7 ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top