Comment obtenir le numéro de semaine en Python?

339

Comment savoir quel numéro de semaine est l'année en cours le 16 juin (semaine 24) avec Python?

Gerry
la source
1
@Donal: L'un regarde le 16 juin, l'autre le 26 juin.
Interjay
5
Définir la semaine 1. isocalendar () n'est pas le seul moyen de le faire.
Mark Tolonen
3
Notez que la sortie de strftime("%U", d)peut différer de isocalendar(). Par exemple, si vous changez l'année en 2004, vous obtiendrez la semaine 24 en utilisant strftime()et la semaine 25 en utilisant isocalendar().
moooeeeep

Réponses:

409

datetime.datea une isocalendar()méthode, qui retourne un tuple contenant la semaine calendaire:

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

datetime.date.isocalendar () est une méthode d'instance renvoyant un tuple contenant l'année, le numéro de semaine et le jour de la semaine dans l'ordre respectif pour l'instance de date donnée.

Horst Gutmann
la source
7
Il serait utile que vous expliquiez le ' [1]' ou que vous indiquiez où chercher les informations.
Jonathan Leffler
5
Je suppose que le plus simple est d'extraire le numéro de semaine en utilisant strftime, le meilleur import datetime today = datetime.now () week = today.strftime ("% W")
bipsa
7
C'est un peu tard. Mais sur ma machine, date(2010, 1, 1).isocalendar()[1]revient 53. De la documentation: "Par exemple, 2004 commence un jeudi, donc la première semaine de l'année ISO 2004 commence le lundi 29 décembre 2003 et se termine le dimanche 4 janvier 2004, de sorte que date(2003, 12, 29).isocalendar() == (2004, 1, 1)et date(2004, 1, 4).isocalendar() == (2004, 1, 7)."
jclancy
17
isocalendar()est génial, mais assurez-vous que c'est ce que vous voulez. Aujourd'hui est un parfait exemple. 01/01/2016 est égal à (2015, 53, 5). now.strftime("%W")et now.strftime("%U")sont égaux à 00ce qui est souvent ce qui est recherché. Exemples STRFTIME
DaveL17
gentil, je viens d'ajouter le jour présent, je pense que ce sera utile, c'était pour ça que je cherchais: D
Vitaliy Terziev
124

Vous pouvez obtenir le numéro de semaine directement à partir de datetime sous forme de chaîne.

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

Vous pouvez également obtenir différents "types" du numéro de semaine de l'année en changeant le strftimeparamètre pour:

%U- Numéro de la semaine de l'année (le dimanche comme premier jour de la semaine) sous forme de nombre décimal à zéro. Tous les jours d'une nouvelle année précédant le premier dimanche sont considérés comme faisant partie de la semaine 0. Exemples: 00 , 01,…, 53

%W- Numéro de semaine de l'année ( lundi comme premier jour de la semaine) sous forme de nombre décimal. Tous les jours d'une nouvelle année précédant le premier lundi sont considérés comme étant dans la semaine 0. Exemples: 00 , 01,…, 53

[...]

( Ajouté dans Python 3.6, rétroporté sur certaines distributions Python 2.7 ) Plusieurs directives supplémentaires non requises par la norme C89 sont incluses pour plus de commodité. Ces paramètres correspondent tous aux valeurs de date ISO 8601. Ceux-ci peuvent ne pas être disponibles sur toutes les plates-formes lorsqu'ils sont utilisés avec la strftime()méthode.

[...]

%V- ISO 8601 semaine en nombre décimal avec lundi comme premier jour de la semaine. La semaine 01 est la semaine contenant le 4 janvier. Exemples: 01 , 02,…, 53

from: datetime - Types de date et d'heure de base - Documentation Python 3.7.3

Je l'ai découvert d' ici . Cela a fonctionné pour moi dans Python 2.7.6

jotacor
la source
Que citez-vous, un manuel Linux? Python 2.7.5 et 3.3.2 disent Invalid format stringà ce modèle. Leurs documents ne mentionnent pas non %Vplus.
Vsevolod Golovanov
3
Désolé, je ne l'ai pas mentionné, je l'ai d' ici . Cela a fonctionné pour moi dans Python 2.7.6.
jotacor
2
Très bonne réponse! Je voudrais ajouter que si vous êtes intéressé par une représentation '<YEAR> - <ISOWEEK>' de vos dates, utilisez à la %G-%Vplace de %Y-%V. %Gest l'équivalent ISO de l'année%Y
KenHBS
J'ai dû l'écrire comme ceci pour que cela fonctionne: datetime.datetime (2010, 6, 16) .strftime ("% V"), ou comme ceci datetime.datetime (2010, 6, 16) .date (). Strftime ("% V")
Einar
77

Je crois que ça date.isocalendar()va être la réponse. Cet article explique les mathématiques derrière le calendrier ISO 8601. Consultez la partie date.isocalendar () de la page datetime de la documentation Python.

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

.isocalendar () renvoie un triplet avec (année, semaine, jour, semaine). dt.isocalendar()[0]renvoie l'année, dt.isocalendar()[1]renvoie le numéro de la semaine, dt.isocalendar()[2]renvoie le jour de la semaine. Aussi simple que cela puisse être.

Byron Sommardahl
la source
4
+1 pour le lien qui explique la nature non intuitive des semaines ISO.
Mark Ransom
27

Voici une autre option:

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

qui imprime 24.

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

Bart Kiers
la source
9
ou% W si vos semaines commencent le lundi.
ZeWaren
1
Cette approche est meilleure dans les cas où vous ne voulez pas diviser ou convertir une date qui vient sous forme de chaîne ... passez simplement la chaîne dans strptime au format de chaîne telle qu'elle est et spécifiez le format dans le deuxième argument. Bonne solution. N'oubliez pas:% W si la semaine commence le lundi.
TheCuriousOne
22

La semaine ISO suggérée par d'autres est bonne, mais elle pourrait ne pas correspondre à vos besoins. Il suppose que chaque semaine commence par un lundi, ce qui conduit à des anomalies intéressantes en début et en fin d'année.

Si vous préférez utiliser une définition qui dit que la semaine 1 est toujours du 1er janvier au 7 janvier, quel que soit le jour de la semaine, utilisez une dérivation comme celle-ci:

>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24
Mark Ransom
la source
3
Dire que l'isocalendar a "quelques anomalies intéressantes" au début et à la fin de l'année semble être un peu un euphémisme. Les résultats d'isocalendar sont très trompeurs (même s'ils ne sont pas réellement incorrects sous la spécification ISO) pour certaines valeurs datetime, comme le 29 décembre 2014, 00:00:00, qui selon isocalendar a une valeur annuelle de 2015 et un numéro de semaine 1 (voir mon entrée ci-dessous).
Kevin
3
@Kevin, ce n'est pas faux, c'est juste que leurs définitions ne correspondent pas aux vôtres. L'ISO a décidé deux choses: premièrement, que toute la semaine du lundi au dimanche serait dans la même année, deuxièmement que l'année contenant la plupart des jours serait celle attribuée. Cela conduit à des jours de la semaine vers le début et la fin de l'année qui se déplacent dans l'année voisine.
Mark Ransom
6
D'accord. Mais selon la définition de la plupart des gens, le 29 décembre 2014 ne sera certainement pas la semaine 1 de l'année 2015. Je voulais simplement attirer l'attention sur cette source potentielle de confusion.
Kevin
Ceci est exactement ce que je cherchais. Pas sur la façon de le faire, mais sur les informations concernant l'ISO et en commençant par lundi.
Amit Amola
19

Généralement pour obtenir le numéro de la semaine en cours (commence à partir du dimanche):

from datetime import *
today = datetime.today()
print today.strftime("%U")
Chaggster
la source
4
D'après la documentation de strftime ('% U'): "Numéro de semaine de l'année (dimanche comme premier jour de la semaine) en nombre décimal [00,53]. Tous les jours d'une nouvelle année précédant le premier dimanche sont considérés être dans la semaine 0. "
Dolan Antenucci
14

Pour la valeur entière de la semaine instantanée de l'année, essayez:

import datetime
datetime.datetime.utcnow().isocalendar()[1]
user2099484
la source
10

Il existe de nombreux systèmes de numérotation des semaines . Voici les systèmes les plus courants simplement mis avec des exemples de code:

  • ISO : la première semaine commence le lundi et doit contenir le 4 janvier. Le calendrier ISO est déjà implémenté en Python:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
  • Amérique du Nord : la première semaine commence le dimanche et doit contenir le 1er janvier. Le code suivant est ma version modifiée de l'implémentation du calendrier ISO de Python pour le système nord-américain:

    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 première semaine commence avec le dimanche et doit contenir le 4 janvier. J'ai créé le package epiweeks spécifiquement pour ce système de numérotation (prend également en charge le système ISO). Voici un exemple:
    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)
dralshehri
la source
8

Si vous utilisez uniquement le numéro de semaine isocalendar dans tous les domaines, les éléments suivants devraient être suffisants:

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

Cela récupère le deuxième membre du tuple retourné par isocalendar pour notre numéro de semaine.

Cependant, si vous allez utiliser des fonctions de date qui traitent du calendrier grégorien, l'isocalendar seul ne fonctionnera pas! Prenons l'exemple suivant:

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

La chaîne indique ici de renvoyer le lundi de la première semaine de 2014 comme date. Lorsque nous utilisons isocalendar pour récupérer le numéro de semaine ici, nous nous attendons à récupérer le même numéro de semaine, mais ce n'est pas le cas. Au lieu de cela, nous obtenons un nombre de semaines de 2. Pourquoi?

La semaine 1 du calendrier grégorien est la première semaine contenant un lundi. La semaine 1 dans l'isocalendar est la première semaine contenant un jeudi. La semaine partielle au début de 2014 contient un jeudi, donc c'est la semaine 1 par l'isocalendar, et faisantdate semaine 2.

Si nous voulons obtenir la semaine grégorienne, nous devrons convertir l'isocalendar en grégorien. Voici une fonction simple qui fait l'affaire.

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
meesterguyperson
la source
6

Vous pouvez essayer la directive% W comme ci-dessous:

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

'% W': Numéro de semaine de l'année (lundi comme premier jour de la semaine) sous forme de nombre décimal. Tous les jours d'une nouvelle année précédant le premier lundi sont considérés comme faisant partie de la semaine 0. (00, 01, ..., 53)

Tung Nguyen
la source
2

isocalendar () renvoie des valeurs incorrectes d'année et de numéro de semaine pour certaines dates:

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

Comparez avec l'approche 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
Kevin
la source
3
En regardant certains liens sur le calendrier iso8601 (par exemple, staff.science.uu.nl/~gent0113/calendar/isocalendar.htm ), je constate que les valeurs de l'année et du numéro de semaine renvoyées par isocalendar () ne sont pas "incorrectes" en tant que telles. Sous ISO8601, par exemple, l'année 2004 a commencé le 29 décembre 2003. Donc isocalendar () peut être correct en renvoyant une année 2015 pour le 29 décembre 2014, mais pour beaucoup de gens, cela va être assez trompeur .
Kevin
2

Je résume la discussion en deux étapes:

  1. Convertissez le format brut en datetimeobjet.
  2. Utilisez la fonction d'un datetimeobjet ou d'un dateobjet pour calculer le numéro de semaine.

Réchauffer

`` `python

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

`` ''

1ère étape

Pour générer manuellement un datetimeobjet, nous pouvons utiliser datetime.datetime(2017,5,3)oudatetime.datetime.now() .

Mais en réalité, nous devons généralement analyser une chaîne existante. nous pouvons utiliser une strptimefonction, telle que celle datetime.strptime('2017-5-3','%Y-%m-%d')dans laquelle vous devez spécifier le format. Le détail du code de format différent peut être trouvé dans la documentation officielle .

Alternativement, un moyen plus pratique consiste à utiliser le module dateparse . Des exemples sont dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12')oudateparser.parse('2017-5-3')

Les deux approches ci-dessus renverront un datetimeobjet.

2ème étape

Utilisez l' datetimeobjet obtenu pour appeler strptime(format). Par exemple,

`` `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.

`` ''

Il est très difficile de décider du format à utiliser. Une meilleure façon est d'obtenir un dateobjet à appeler isocalendar(). Par exemple,

`` `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

`` ''

En réalité, vous serez plus susceptible de l'utiliser date.isocalendar()pour préparer un rapport hebdomadaire, en particulier pendant la saison de magasinage "Noël-Nouvel An".

Yuchao Jiang
la source
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.............!!!") 
Wael Abo Elhassan
la source
-1

Beaucoup de réponses ont été données, mais j'aimerais y ajouter.

Si vous avez besoin que la semaine s'affiche comme un style année / semaine (ex. 1953 - semaine 53 de 2019, 2001 - semaine 1 de 2020, etc.), vous pouvez le faire:

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)

Cela prendra l'année et la semaine en cours, et long_week_num au jour de l'écriture ce sera:

>>> 2006
Simo Todorov
la source
Pourquoi créer un à date()partir de zéro? datetime.datetime()les instances ont une .date()méthode pour ce travail.
Martijn Pieters
Cependant, plus inquiétant, c'est que votre réponse choisit le siècle , pas l'année en cours. Et si vous allez utiliser la mise en forme des chaînes pour le numéro de semaine, pourquoi ne pas l'utiliser également pour inclure l'année?
Martijn Pieters