Convertir Année / Mois / Jour en Jour de l'année en Python

127

J'utilise le module datetime Python , c'est-à-dire:

>>> import datetime
>>> today = datetime.datetime.now()
>>> print today
2009-03-06 13:24:58.857946

et je voudrais calculer le jour de l'année qui est sensible aux années bissextiles. Par exemple, aujourd'hui (6 mars 2009) est le 65e jour de 2009. Voici la calculatrice DateTime basée sur le Web .

Quoi qu'il en soit, je vois deux options:

A. Créez un tableau number_of_days_in_month = [31, 28, ...], décidez si c'est une année bissextile, additionnez manuellement les jours.

B. Utilisez datetime.timedeltapour faire une estimation puis une recherche binaire pour le jour correct de l'année:

>>> import datetime
>>> YEAR = 2009
>>> DAY_OF_YEAR = 62
>>> d = datetime.date(YEAR, 1, 1) + datetime.timedelta(DAY_OF_YEAR - 1)

Celles-ci sont toutes les deux assez maladroites et j'ai le sentiment instinctif qu'il existe une manière plus "pythonique" de calculer le jour de l'année. Des idées / suggestions?

Pete
la source

Réponses:

256

Il existe une solution très simple:

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday
DzinX
la source
13
Un ajout très mineur et sans doute pédant, mais qui utilise date.today()plutôt que datetime.now()fonctionne aussi et souligne un peu plus la nature de l'opération.
Jeremy
5
Mieux encore: time.localtime().tm_yday pas besoin de convertir un datetime en un multiplicateur de temps puisque c'est ce que produit localtime ().
Mike Ellis
14
@MikeEllis Mais cette solution illustre ce qu'il faut faire lorsque la date / heure ne correspond pas à aujourd'hui.
gerrit
2
note: cela commence à compter à 1
Mehdi Nellen
1
que faire si je veux faire l'inverse, j'ai le numéro disons "26e jour de l'année 2020", et je veux le faire convertir en une date "26-01-2020"?
Sankar le
43

Ne pourriez-vous pas utiliser strftime?

>>> import datetime
>>> today = datetime.datetime.now()
>>> print today
2009-03-06 15:37:02.484000
>>> today.strftime('%j')
'065'

Éditer

Comme indiqué dans les commentaires, si vous souhaitez effectuer des comparaisons ou des calculs avec ce nombre, vous devrez le convertir en int()car strftime()renvoie une chaîne. Si tel est le cas, il vaut mieux utiliser la réponse de DzinX .

Paolo Bergantino
la source
1
-1: dégoûtant. Mieux vaut l'algorithme "aujourd'hui moins 1er janvier". Beaucoup plus propre et parfaitement évident sans chercher un élément trivial sur le '% j' de strftime.
S.Lott
12
Sérieusement? Comment est-ce que ce 1er janvier dégueulasse et soustrait ne l'est pas? strftime est là pour une raison. Je ne suis tout simplement pas d'accord. C'est beaucoup plus propre à mon avis.
Paolo Bergantino
1
L'utilisation de strftime est indirecte, car elle produit une chaîne à partir d'un nombre: le membre timeuple.tm_yday. Lisez la source. La chaîne produite doit être convertie en un nombre avant tout calcul / comparaison, alors pourquoi s'embêter?
tzot
2
Si l'on avait besoin du jour de l'année dans une chaîne, par exemple pour une utilisation dans un nom de fichier, strftime est une solution beaucoup plus propre.
captain_M
13

La réponse de DZinX est une excellente réponse à la question. J'ai trouvé cette question en cherchant la fonction inverse. J'ai trouvé que cela fonctionnait:

import datetime
datetime.datetime.strptime('1936-077T13:14:15','%Y-%jT%H:%M:%S')

>>>> datetime.datetime(1936, 3, 17, 13, 14, 15)

datetime.datetime.strptime('1936-077T13:14:15','%Y-%jT%H:%M:%S').timetuple().tm_yday

>>>> 77

Je ne suis pas sûr de l'étiquette ici, mais j'ai pensé qu'un pointeur vers la fonction inverse pourrait être utile pour d'autres comme moi.

Dave X
la source
6

Je souhaite présenter les performances de différentes approches, sur Python 3.4, Linux x64. Extrait du profileur de ligne:

      Line #      Hits         Time  Per Hit   % Time  Line Contents
      ==============================================================
         (...)
         823      1508        11334      7.5     41.6          yday = int(period_end.strftime('%j'))
         824      1508         2492      1.7      9.1          yday = period_end.toordinal() - date(period_end.year, 1, 1).toordinal() + 1
         825      1508         1852      1.2      6.8          yday = (period_end - date(period_end.year, 1, 1)).days + 1
         826      1508         5078      3.4     18.6          yday = period_end.timetuple().tm_yday
         (...)

Le plus efficace est donc

yday = (period_end - date(period_end.year, 1, 1)).days
Omikron
la source
1
Comment avez-vous calculé la performance? J'ai essayé d'utiliser time.time et voici mes résultats: def f (): (today - datetime.datetime (today.year, 1, 1)). Days + 1 start = time.time (); F(); print ('Lapsed {}'. format (time.time () - start)); Désactivé 5.221366882324219e-05 def f (): int (today.strftime ('% j')); début = heure.heure (); F(); print ('Lapsed {}'. format (time.time () - start)); Période de 7.462501525878906e-05
ssoto
5

Il suffit de soustraire le 1er janvier de la date:

import datetime
today = datetime.datetime.now()
day_of_year = (today - datetime.datetime(today.year, 1, 1)).days + 1
zweiterlinde
la source
1
Rien contre Paolo, mais datetime.timedelta est libellé en jours (ainsi qu'en secondes et en microsecondes, bien sûr), c'est donc un choix naturel - certainement plus direct que le formatage de chaîne
zweiterlinde
1
d.toordinal () - date (d.year, 1, 1) .toordinal () + 1 est plus standard selon la documentation. Elle équivaut à la réponse acceptée sans produire le tuple de temps entier.
Dingle
5

Si vous avez des raisons d'éviter l'utilisation du datetimemodule, ces fonctions fonctionneront.

def is_leap_year(year):
    """ if year is a leap year return True
        else return False """
    if year % 100 == 0:
        return year % 400 == 0
    return year % 4 == 0

def doy(Y,M,D):
    """ given year, month, day return day of year
        Astronomical Algorithms, Jean Meeus, 2d ed, 1998, chap 7 """
    if is_leap_year(Y):
        K = 1
    else:
        K = 2
    N = int((275 * M) / 9.0) - K * int((M + 9) / 12.0) + D - 30
    return N

def ymd(Y,N):
    """ given year = Y and day of year = N, return year, month, day
        Astronomical Algorithms, Jean Meeus, 2d ed, 1998, chap 7 """    
    if is_leap_year(Y):
        K = 1
    else:
        K = 2
    M = int((9 * (K + N)) / 275.0 + 0.98)
    if N < 32:
        M = 1
    D = N - int((275 * M) / 9.0) + K * int((M + 9) / 12.0) + 30
    return Y, M, D
Barry Andersen
la source
1

Ce code prend une date comme argument d'entrée et renvoie le jour de l'année.

from datetime import datetime
date = raw_input("Enter date: ")  ## format is 02-02-2016
adate = datetime.datetime.strptime(date,"%d-%m-%Y")
day_of_year = adate.timetuple().tm_yday
day_of_year
Gajanan Kothawade
la source