¿Cómo obtener el número de semana en Python?


339

¿Cómo saber qué número de semana es el año actual el 16 de junio (wk24) con Python?


1
@Donal: Uno mira el 16 de junio, el otro el 26 de junio.
Interjay

55
Defina la semana 1. isocalendar () no es la única forma de hacerlo.
Mark Tolonen el

3
Tenga en cuenta que la salida de strftime("%U", d)puede diferir de la isocalendar(). Por ejemplo, si cambia el año a 2004, obtendría la semana 24 usando strftime()y la semana 25 usando isocalendar().
moooeeeep

Respuestas:


409

datetime.datetiene un isocalendar()método, que devuelve una tupla que contiene la semana calendario:

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

datetime.date.isocalendar () es un método de instancia que devuelve una tupla que contiene año, número de semana y día de la semana en el orden respectivo para la instancia de fecha dada.


77
Sería útil si explicara el ' [1]', o le diera un puntero donde buscar la información.
Jonathan Leffler

55
Supongo que lo más fácil es extraer el número de semana usando strftime, la mejor importación datetime today = datetime.now () week = today.strftime ("% W")
bipsa

77
Esto es un poco tarde. Pero en mi máquina, date(2010, 1, 1).isocalendar()[1]vuelve 53. De los documentos: "Por ejemplo, 2004 comienza un jueves, por lo que la primera semana del año ISO 2004 comienza el lunes 29 de diciembre de 2003 y termina el domingo 4 de enero de 2004, así que date(2003, 12, 29).isocalendar() == (2004, 1, 1)y date(2004, 1, 4).isocalendar() == (2004, 1, 7)".
jclancy

17
isocalendar()es genial, pero asegúrate de que sea lo que quieres. Hoy es un ejemplo perfecto. 01/01/2016 es igual a (2015, 53, 5). now.strftime("%W")y now.strftime("%U")son iguales a lo 00que a menudo es lo que se quiere. Ejemplos de STRFTIME
DaveL17

bueno, acabo de agregar el día de hoy, creo que será útil, era para lo que estaba buscando: D
Vitaliy Terziev

124

Puede obtener el número de semana directamente de datetime como cadena.

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

También puede obtener diferentes "tipos" del número de semana del año cambiando el strftimeparámetro para:

%U- Número de semana del año (domingo como primer día de la semana) como un número decimal rellenado con ceros. Todos los días en un nuevo año anterior al primer domingo se consideran en la semana 0. Ejemplos: 00 , 01,…, 53

%W- Número de semana del año ( lunes como primer día de la semana) como número decimal. Todos los días en un nuevo año anterior al primer lunes se consideran en la semana 0. Ejemplos: 00 , 01,…, 53

[...]

( Agregado en Python 3.6, respaldado en algunas distribuciones de Python 2.7 ). Para mayor comodidad, se incluyen varias directivas adicionales no requeridas por el estándar C89. Todos estos parámetros corresponden a valores de fecha ISO 8601. Es posible que no estén disponibles en todas las plataformas cuando se usan con el strftime()método.

[...]

%V- ISO 8601 semana como un número decimal con lunes como primer día de la semana. La semana 01 es la semana que contiene el 4 de enero. Ejemplos: 01 , 02,…, 53

from: datetime - Tipos básicos de fecha y hora - Documentación de Python 3.7.3

Me enteré de esto desde aquí . Funcionó para mí en Python 2.7.6


¿Qué estás citando, algún manual de Linux? Python 2.7.5 y 3.3.2 dicen Invalid format stringa este patrón. Sus documentos tampoco mencionan %V.
Vsevolod Golovanov

3
Lo siento, no lo mencioné, lo tengo desde aquí . Me funcionó en Python 2.7.6.
jotacor

2
¡Gran respuesta! Me gustaría agregar que si está interesado en una representación '<YEAR> - <ISOWEEK>' de sus fechas, use en %G-%Vlugar de %Y-%V. %Ges el equivalente en años ISO de%Y
KenHBS

Tuve que escribirlo así para que funcione: datetime.datetime (2010, 6, 16) .strftime ("% V"), o como datetime.datetime (2010, 6, 16) .date (). Strftime ("% V")
Einar

77

Creo que date.isocalendar()va a ser la respuesta. Este artículo explica las matemáticas detrás del calendario ISO 8601. Consulte la parte date.isocalendar () de la página datetime de la documentación de Python.

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

.isocalendar () devuelve una tupla de 3 con (año, número de semana, día de semana). dt.isocalendar()[0]devuelve el año, dt.isocalendar()[1]devuelve el número de semana, dt.isocalendar()[2]devuelve el día de la semana. Tan simple como puede ser.


44
+1 para el enlace que explica la naturaleza no intuitiva de las semanas ISO.
Mark Ransom

27

Aquí hay otra opción:

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

que imprime 24.

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


99
o% W si sus semanas comienzan los lunes.
ZeWaren

1
Este enfoque es mejor en casos en los que no desea dividir o convertir una fecha que viene como una cadena ... simplemente pase la cadena en strptime en formato de cadena como está y especifique el formato en el segundo argumento. Buena solución. Recuerde:% W si la semana comienza los lunes.
TheCuriousOne

22

La semana ISO sugerida por otros es buena, pero puede que no se ajuste a sus necesidades. Se supone que cada semana comienza con un lunes, lo que lleva a algunas anomalías interesantes al comienzo y al final del año.

Si prefiere usar una definición que dice que la semana 1 es siempre del 1 de enero al 7 de enero, independientemente del día de la semana, use una derivación como esta:

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

3
Decir que el isocalendario tiene "algunas anomalías interesantes" al principio y al final del año parece ser un eufemismo. Los resultados de isocalendar son muy engañosos (incluso si no son realmente incorrectos según la especificación ISO) para algunos valores de fecha y hora, como el 29 de diciembre de 2014, 00:00:00, que según isocalendar tiene un valor anual de 2015 y una semana Número de 1 (ver mi entrada a continuación).
Kevin

3
@ Kevin, no está mal, es solo que sus definiciones no coinciden con las tuyas. ISO decidió dos cosas: primero que toda la semana de lunes a domingo sería en el mismo año, segundo que el año que contenía la mayoría de los días sería el asignado. Esto lleva a días de la semana alrededor del comienzo y el final del año que pasan al año contiguo.
Mark Ransom

66
Convenido. Pero según la definición de la mayoría de las personas, el 29 de diciembre de 2014 definitivamente no será la semana 1 del año 2015. Solo quería llamar la atención sobre esta posible fuente de confusión.
Kevin

Esto es exactamente lo que estaba buscando. No se trata de cómo hacer esto, sino de la información sobre la ISO y comenzar con el lunes.
Amit Amola

19

Generalmente para obtener el número de semana actual (comienza el domingo):

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

44
De la documentación de strftime ('% U'): "Número de semana del año (domingo como primer día de la semana) como un número decimal [00,53]. Se consideran todos los días en un nuevo año anterior al primer domingo estar en la semana 0. "
Dolan Antenucci

14

Para el valor entero de la semana instantánea del año, intente:

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

10

Hay muchos sistemas para la numeración de semanas . Los siguientes son los sistemas más comunes simplemente puestos con ejemplos de código:

  • ISO : La primera semana comienza con el lunes y debe contener el 4 de enero. El calendario ISO ya está implementado en Python:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
  • Norteamérica : la primera semana comienza con el domingo y debe contener el 1 de enero. El siguiente código es mi versión modificada de la implementación del calendario ISO de Python para el sistema norteamericano:

    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 primera semana comienza con el domingo y debe contener el 4 de enero. Creé los epiweeks empaquetar específicamente para este sistema de numeración (también tiene soporte para el sistema ISO). Aquí hay un ejemplo:
    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)

8

Si solo usa el número de semana isocalendario en todos los ámbitos, lo siguiente debería ser suficiente:

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

Esto recupera el segundo miembro de la tupla devuelto por isocalendar para nuestro número de semana.

Sin embargo, si va a utilizar funciones de fecha que se ocupan en el calendario gregoriano, ¡isocalendar solo no funcionará! Tome el siguiente ejemplo:

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

La cadena aquí dice que regrese el lunes de la primera semana de 2014 como nuestra fecha. Cuando usamos isocalendar para recuperar el número de semana aquí, esperaríamos recuperar el mismo número de semana, pero no lo hacemos. En cambio, tenemos un número semanal de 2. ¿Por qué?

La semana 1 en el calendario gregoriano es la primera semana que contiene un lunes. La semana 1 en el isocalendario es la primera semana que contiene un jueves. La semana parcial a principios de 2014 contiene un jueves, por lo que esta es la semana 1 por el isocalendario y hace la datesemana 2.

Si queremos obtener la semana gregoriana, tendremos que convertir del isocalendario al gregoriano. Aquí hay una función simple que hace el truco.

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

Puede probar la directiva% W de la siguiente manera:

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

'% W': número de semana del año (lunes como primer día de la semana) como un número decimal. Todos los días en un nuevo año anterior al primer lunes se consideran en la semana 0. (00, 01, ..., 53)


2

isocalendar () devuelve valores incorrectos de año y número de semana para algunas fechas:

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

Compárese con el enfoque de 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
Al mirar algunos enlaces sobre el calendario iso8601 (p. Ej., Staff.science.uu.nl/~gent0113/calendar/isocalendar.htm ), veo que los valores de año y semana devueltos por isocalendar () no son "incorrectos" como tales. Bajo ISO8601, por ejemplo, el año 2004 comenzó el 29 de diciembre de 2003. Entonces isocalendar () puede ser correcto al regresar un año de 2015 para el 29 de diciembre de 2014, pero para los propósitos de muchas personas, esto será bastante engañoso .
Kevin

2

Resumo la discusión en dos pasos:

  1. Convierta el formato sin formato en un datetimeobjeto.
  2. Use la función de un datetimeobjeto o un dateobjeto para calcular el número de semana.

Calentar

`` `pitón

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

`` `

1er paso

Para generar un datetimeobjeto manualmente , podemos usar datetime.datetime(2017,5,3)odatetime.datetime.now() .

Pero en realidad, generalmente necesitamos analizar una cadena existente. podemos usar la strptimefunción, como datetime.strptime('2017-5-3','%Y-%m-%d')en la que debe especificar el formato. Se pueden encontrar detalles de diferentes formatos en la documentación oficial .

Alternativamente, una forma más conveniente es usar el módulo dateparse . Ejemplos son dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12')odateparser.parse('2017-5-3')

Los dos enfoques anteriores devolverán un datetimeobjeto.

2do paso

Usa el datetimeobjeto obtenido para llamar strptime(format). Por ejemplo,

`` `pitón

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.

`` `

Es muy difícil decidir qué formato usar. Una mejor manera es obtener un dateobjeto para llamar isocalendar(). Por ejemplo,

`` `pitón

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

`` `

En realidad, será más probable que lo use date.isocalendar()para preparar un informe semanal, especialmente en la temporada de compras "Navidad-Año Nuevo".


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

Se han dado muchas respuestas, pero me gustaría agregarlas.

Si necesita que la semana se muestre como un estilo año / semana (por ejemplo, 1953 - semana 53 de 2019, 2001 - semana 1 de 2020, etc.), puede hacer esto:

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)

Tomará el año y la semana actuales, y long_week_num en el día de la escritura será:

>>> 2006

¿Por qué crear una date()desde cero? datetime.datetime()las instancias tienen un .date()método para ese trabajo.
Martijn Pieters

Sin embargo, lo más preocupante es que su respuesta elige el siglo , no el año actual. Y si va a utilizar el formato de cadena para el número de semana, ¿por qué no utilizarlo también para incluir el año?
Martijn Pieters
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.