Come ottenere il numero della settimana in Python?


339

Come scoprire quale numero di settimana è l'anno corrente il 16 giugno (settimana 24) con Python?


1
@Donal: uno guarda il 16 giugno, l'altro il 26 giugno.
Interjay

5
Definire la settimana 1. isocalendar () non è l'unico modo per farlo.
Mark Tolonen,

3
Si noti che l'output di strftime("%U", d)potrebbe differire da isocalendar(). Ad esempio, se cambi l'anno in 2004, otterrai la settimana 24 in uso strftime()e la settimana 25 in uso isocalendar().
Moooeeeep,

Risposte:


409

datetime.dateha un isocalendar()metodo, che restituisce una tupla contenente la settimana di calendario:

>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar()[1]
24

datetime.date.isocalendar () è un metodo di istanza che restituisce una tupla contenente anno, numero di settimana e giorno della settimana nell'ordine corrispondente per l'istanza di data specificata.


7
Sarebbe di aiuto se spiegassi " [1]" o fornissi un puntatore dove cercare le informazioni.
Jonathan Leffler

5
Immagino che il più semplice sia estrarre il numero della settimana usando strftime, migliore importazione datetime oggi = datetime.now () settimana = today.strftime ("% W")
bipsa

7
Questo è un po 'tardi. Ma sulla mia macchina, date(2010, 1, 1).isocalendar()[1]ritorna 53. Dai documenti: "Ad esempio, il 2004 inizia di giovedì, quindi la prima settimana dell'anno ISO 2004 inizia lunedì 29 dicembre 2003 e termina domenica 4 gennaio 2004, quindi date(2003, 12, 29).isocalendar() == (2004, 1, 1)e così date(2004, 1, 4).isocalendar() == (2004, 1, 7)".
jclancy,

17
isocalendar()è fantastico, ma assicurati che sia quello che vuoi. Oggi è un esempio perfetto. 01/01/2016 è uguale a (2015, 53, 5). now.strftime("%W")e now.strftime("%U")sono uguali a ciò 00che spesso è ciò che si desidera. Esempi di STRFTIME
DaveL17

bello, ho appena aggiunto il giorno in cui penso che sarà utile, era quello che cercavo: D
Vitaliy Terziev

124

È possibile ottenere il numero della settimana direttamente da datetime come stringa.

>>> import datetime
>>> datetime.date(2010, 6, 16).strftime("%V")
'24'

Inoltre puoi ottenere diversi "tipi" del numero di settimana dell'anno modificando il strftimeparametro per:

%U- Numero della settimana dell'anno (domenica come primo giorno della settimana) come numero decimale con riempimento zero. Tutti i giorni di un nuovo anno precedente la prima domenica sono considerati nella settimana 0. Esempi: 00 , 01,…, 53

%W- Numero della settimana dell'anno ( lunedì come primo giorno della settimana) come numero decimale. Tutti i giorni di un nuovo anno precedente il primo lunedì sono considerati nella settimana 0. Esempi: 00 , 01,…, 53

[...]

( Aggiunto in Python 3.6, backportato su alcuni Python 2.7 di distribuzione ) Per comodità sono incluse diverse direttive aggiuntive non richieste dallo standard C89. Tutti questi parametri corrispondono ai valori di data ISO 8601. Questi potrebbero non essere disponibili su tutte le piattaforme se utilizzati con il strftime()metodo.

[...]

%V- ISO 8601 settimana come numero decimale con lunedì come primo giorno della settimana. La settimana 01 è la settimana contenente il 4 gennaio. Esempi: 01 , 02,…, 53

da: datetime - Tipi di data e ora di base - Documentazione di Python 3.7.3

L'ho scoperto da qui . Ha funzionato per me in Python 2.7.6


Cosa stai citando, qualche manuale di Linux? Python 2.7.5 e 3.3.2 dicono Invalid format stringa questo modello. I loro documenti non menzionano %Vneanche.
Vsevolod Golovanov,

3
Scusa se non l'ho menzionato, ho da qui . Ha funzionato per me in Python 2.7.6.
jotacor,

2
Bella risposta! Vorrei aggiungere che se sei interessato a una rappresentazione "<ANNO> - <ISOWEEK>" delle tue date, utilizza %G-%Vinvece di %Y-%V. %Gè l'equivalente dell'anno ISO di%Y
KenHBS il

Ho dovuto scriverlo in questo modo per farlo funzionare: datetime.datetime (2010, 6, 16) .strftime ("% V"), o come questo datetime.datetime (2010, 6, 16) .date (). Strftime ("% V")
Einar il

77

Credo date.isocalendar()che sarà la risposta. Questo articolo spiega la matematica alla base del calendario ISO 8601. Dai un'occhiata alla parte date.isocalendar () della pagina datetime della documentazione di Python.

>>> dt = datetime.date(2010, 6, 16) 
>>> wk = dt.isocalendar()[1]
24

.isocalendar () restituisce una 3 tupla con (anno, numero di sett, giorno di sett.). dt.isocalendar()[0]restituisce l'anno, dt.isocalendar()[1]restituisce il numero della settimana, dt.isocalendar()[2]restituisce il giorno della settimana. Semplice come può essere.


4
+1 per il collegamento che spiega la natura non intuitiva delle settimane ISO.
Mark Ransom,

27

Ecco un'altra opzione:

import time
from time import gmtime, strftime
d = time.strptime("16 Jun 2010", "%d %b %Y")
print(strftime("%U", d))

quale stampa 24.

Vedi: http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior


9
o% W se le tue settimane iniziano il lunedì.
ZeWaren,

1
Questo approccio è migliore nei casi in cui non si desidera dividere o convertire una data che arriva come una stringa ... basta passare la stringa in tempo reale in formato stringa così com'è e specificare il formato nel secondo argomento. Buona soluzione Ricorda:% W se la settimana inizia di lunedì.
TheCuriousOne,

22

La settimana ISO suggerita da altri è buona, ma potrebbe non essere adatta alle tue esigenze. Presuppone che ogni settimana inizi con un lunedì, il che porta ad alcune anomalie interessanti all'inizio e alla fine dell'anno.

Se preferisci utilizzare una definizione che indica che la settimana 1 è sempre dal 1 ° gennaio al 7 gennaio, indipendentemente dal giorno della settimana, utilizza una derivazione come questa:

>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24

3
Dire che isocalendar ha "alcune anomalie interessanti" all'inizio e alla fine dell'anno sembra essere un eufemismo. I risultati di isocalendar sono molto fuorvianti (anche se non effettivamente errati secondo la specifica ISO) per alcuni valori di data e ora, come il 29 dicembre 2014, 00:00:00, che secondo isocalendar ha un valore di anno 2015 e una settimanaNumero di 1 (vedi la mia voce di seguito).
Kevin,

3
@ Kevin, non è sbagliato, è solo che le loro definizioni non corrispondono alle tue. L'ISO ha deciso due cose: prima che l'intera settimana dal lunedì alla domenica fosse nello stesso anno, in secondo luogo che l'anno contenente la maggior parte dei giorni sarebbe quello assegnato. Ciò porta a giorni della settimana intorno all'inizio e alla fine dell'anno che si spostano nell'anno adiacente.
Mark Ransom,

6
Concordato. Ma per definizione della maggior parte delle persone, il 29 dicembre 2014 non sarà sicuramente la prima settimana dell'anno 2015. Volevo solo attirare l'attenzione su questa potenziale fonte di confusione.
Kevin,

Questo e 'esattamente quello che stavo cercando. Non su come farlo, ma sulle informazioni relative all'ISO e a partire dal lunedì.
Amit Amola,

19

Generalmente per ottenere il numero della settimana corrente (inizia da domenica):

from datetime import *
today = datetime.today()
print today.strftime("%U")

4
Dalla documentazione di strftime ('% U'): "Numero della settimana dell'anno (domenica come primo giorno della settimana) come un numero decimale [00,53]. Vengono considerati tutti i giorni di un nuovo anno precedente la prima domenica essere nella settimana 0. "
Dolan Antenucci,

14

Per il valore intero della settimana istantanea dell'anno provare:

import datetime
datetime.datetime.utcnow().isocalendar()[1]

10

Esistono molti sistemi per la numerazione delle settimane . I seguenti sono i sistemi più comuni semplicemente inseriti con esempi di codice:

  • ISO : la prima settimana inizia con lunedì e deve contenere il 4 gennaio. Il calendario ISO è già implementato in Python:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
  • Nord America : la prima settimana inizia con domenica e deve contenere il 1 ° gennaio. Il codice seguente è la mia versione modificata dell'implementazione del calendario ISO di Python per il sistema nordamericano:

    from datetime import date
    
    def week_from_date(date_object):
        date_ordinal = date_object.toordinal()
        year = date_object.year
        week = ((date_ordinal - _week1_start_ordinal(year)) // 7) + 1
        if week >= 52:
            if date_ordinal >= _week1_start_ordinal(year + 1):
                year += 1
                week = 1
        return year, week
    
    def _week1_start_ordinal(year):
        jan1 = date(year, 1, 1)
        jan1_ordinal = jan1.toordinal()
        jan1_weekday = jan1.weekday()
        week1_start_ordinal = jan1_ordinal - ((jan1_weekday + 1) % 7)
        return week1_start_ordinal
    >>> from datetime import date
    >>> week_from_date(date(2014, 12, 29))
    (2015, 1)
  • MMWR (CDC) : la prima settimana inizia con domenica e deve contenere il 4 gennaio. Ho creato il pacchetto epiweeks appositamente per questo sistema di numerazione (ha anche il supporto per il sistema ISO). Ecco un esempio:
    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)

8

Se si utilizza solo il numero della settimana isocalendar su tutta la linea, dovrebbe essere sufficiente quanto segue:

import datetime
week = date(year=2014, month=1, day=1).isocalendar()[1]

Questo recupera il secondo membro della tupla restituito da Isocalendar per il nostro numero di settimana.

Tuttavia, se stai per utilizzare le funzioni di data che si occupano del calendario gregoriano, l'isocalendar da solo non funzionerà! Prendi il seguente esempio:

import datetime
date = datetime.datetime.strptime("2014-1-1", "%Y-%W-%w")
week = date.isocalendar()[1]

La stringa qui dice di restituire il lunedì della prima settimana del 2014 come nostra data. Quando usiamo isocalendar per recuperare il numero della settimana qui, ci aspetteremmo di recuperare lo stesso numero della settimana, ma non lo facciamo. Invece otteniamo un numero settimanale di 2. Perché?

La settimana 1 nel calendario gregoriano è la prima settimana contenente un lunedì. La settimana 1 nell'isocalendar è la prima settimana contenente un giovedì. La settimana parziale all'inizio del 2014 contiene un giovedì, quindi questa è la settimana 1 dell'isocalendar e fa la datesettimana 2.

Se vogliamo ottenere la settimana gregoriana, dovremo convertirci dall'isocalendar al gregoriano. Ecco una semplice funzione che fa il trucco.

import datetime

def gregorian_week(date):
    # The isocalendar week for this date
    iso_week = date.isocalendar()[1]

    # The baseline Gregorian date for the beginning of our date's year
    base_greg = datetime.datetime.strptime('%d-1-1' % date.year, "%Y-%W-%w")

    # If the isocalendar week for this date is not 1, we need to 
    # decrement the iso_week by 1 to get the Gregorian week number
    return iso_week if base_greg.isocalendar()[1] == 1 else iso_week - 1

6

Puoi provare la direttiva% W come di seguito:

d = datetime.datetime.strptime('2016-06-16','%Y-%m-%d')
print(datetime.datetime.strftime(d,'%W'))

'% W': numero della settimana dell'anno (lunedì come primo giorno della settimana) come numero decimale. Tutti i giorni di un nuovo anno precedente il primo lunedì sono considerati nella settimana 0. (00, 01, ..., 53)


2

isocalendar () restituisce valori anno e numero di settimana errati per alcune date:

Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime as dt
>>> myDateTime = dt.datetime.strptime("20141229T000000.000Z",'%Y%m%dT%H%M%S.%fZ')
>>> yr,weekNumber,weekDay = myDateTime.isocalendar()
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2015, weekNumber is 1

Confronta con l'approccio di Mark Ransom:

>>> yr = myDateTime.year
>>> weekNumber = ((myDateTime - dt.datetime(yr,1,1)).days/7) + 1
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2014, weekNumber is 52

3
Osservando alcuni link sul calendario iso8601 (ad es. Staff.science.uu.nl/~gent0113/calendar/isocalendar.htm ), vedo che i valori di anno e numero di settimana restituiti da isocalendar () non sono "errati" in quanto tali. Secondo ISO8601, ad esempio, l'anno 2004 è iniziato il 29 dicembre 2003. Quindi isocalendar () potrebbe essere corretto nel ritornare un anno del 2015 per il 29 dicembre 2014, ma per molti scopi delle persone, questo sarà piuttosto fuorviante .
Kevin,

2

Riassumo la discussione in due fasi:

  1. Converti il ​​formato non elaborato in un datetimeoggetto.
  2. Utilizzare la funzione di un datetimeoggetto o un dateoggetto per calcolare il numero della settimana.

Riscaldamento

`` `Python

from datetime import datetime, date, time
d = date(2005, 7, 14)
t = time(12, 30)
dt = datetime.combine(d, t)
print(dt)

`` `

1 ° passo

Per generare manualmente un datetimeoggetto, possiamo usare datetime.datetime(2017,5,3)o datetime.datetime.now().

Ma in realtà, di solito abbiamo bisogno di analizzare una stringa esistente. possiamo usare la strptimefunzione, ad esempio datetime.strptime('2017-5-3','%Y-%m-%d')in cui devi specificare il formato. I dettagli di codici di formato diverso sono disponibili nella documentazione ufficiale .

In alternativa, un modo più conveniente è usare il modulo dateparse . Esempi sono dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12')odateparser.parse('2017-5-3')

I due approcci precedenti restituiranno un datetimeoggetto.

2 ° passo

Utilizzare l' datetimeoggetto ottenuto per chiamare strptime(format). Per esempio,

`` `Python

dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object. This day is Sunday
print(dt.strftime("%W")) # '00' Monday as the 1st day of the week. All days in a new year preceding the 1st Monday are considered to be in week 0.
print(dt.strftime("%U")) # '01' Sunday as the 1st day of the week. All days in a new year preceding the 1st Sunday are considered to be in week 0.
print(dt.strftime("%V")) # '52' Monday as the 1st day of the week. Week 01 is the week containing Jan 4.

`` `

È molto difficile decidere quale formato utilizzare. Un modo migliore è ottenere un dateoggetto da chiamare isocalendar(). Per esempio,

`` `Python

dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object
d = dt.date() # convert to a date object. equivalent to d = date(2017,1,1), but date.strptime() don't have the parse function
year, week, weekday = d.isocalendar() 
print(year, week, weekday) # (2016,52,7) in the ISO standard

`` `

In realtà, sarà più probabile che utilizzerai date.isocalendar()per preparare un rapporto settimanale, specialmente nella stagione dello shopping "Natale-Capodanno".


0
userInput = input ("Please enter project deadline date (dd/mm/yyyy/): ")

import datetime

currentDate = datetime.datetime.today()

testVar = datetime.datetime.strptime(userInput ,"%d/%b/%Y").date()

remainDays = testVar - currentDate.date()

remainWeeks = (remainDays.days / 7.0) + 1


print ("Please pay attention for deadline of project X in days and weeks are  : " ,(remainDays) , "and" ,(remainWeeks) , "Weeks ,\nSo  hurryup.............!!!") 

-1

Sono state fornite molte risposte, ma mi piacerebbe aggiungere ad esse.

Se devi visualizzare la settimana come stile anno / settimana (es. 1953 - settimana 53 del 2019, 2001 - settimana 1 del 2020 ecc.), Puoi fare questo:

import datetime

year = datetime.datetime.now()
week_num = datetime.date(year.year, year.month, year.day).strftime("%V")
long_week_num = str(year.year)[0:2] + str(week_num)

Ci vorranno l'anno e la settimana attuali e long_week_num nel giorno in cui scriverò sarà:

>>> 2006

Perché creare un date()da zero? datetime.datetime()le istanze hanno un .date()metodo per quel lavoro.
Martijn Pieters

Tuttavia, più preoccupante è che la tua risposta sceglie il secolo , non l'anno in corso. E se hai intenzione di utilizzare la formattazione delle stringhe per il numero della settimana, perché non utilizzarlo anche per includere l'anno?
Martijn Pieters
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.