200 votes

Conversion année/mois/jour en jour de l'année en Python

J'utilise le datetime module, 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 en tenant compte des années bissextiles. Par exemple, aujourd'hui (6 mars 2009) est le 65e jour de 2009.

Je vois deux options :

  1. Créer un number_of_days_in_month = [31, 28, ...] array, décider si c'est une année bissextile et additionner manuellement les jours.

  2. Utilisez datetime.timedelta pour faire une supposition et ensuite 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)

Ces deux méthodes sont plutôt maladroites et j'ai l'impression qu'il existe une méthode plus "pythonique" pour calculer le jour de l'année. Des idées/suggestions ?

378voto

DzinX Points 13452

Utilisez datetime.timetuple() pour convertir votre datetime à un objet time.struct_time puis obtenir son tm_yday propriété :

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday  # returns 1 for January 1st

20 votes

Il s'agit d'un ajout très mineur et sans doute pédant, mais l'utilisation de date.today() plutôt que datetime.now() fonctionne également et souligne un peu plus la nature de l'opération.

8 votes

note : cela commence à compter à 1

3 votes

Et si je veux faire l'inverse, j'ai le nombre disons "26ème jour de l'année 2020", et je veux qu'il soit converti en une date "26-01-2020" ?

71voto

Paolo Bergantino Points 199336

Vous pourriez utiliser strftime avec un %j chaîne de format :

>>> import datetime
>>> today = datetime.datetime.now()
>>> today.strftime('%j')
'065'

mais si vous souhaitez effectuer des comparaisons ou des calculs avec ce nombre, vous devrez le convertir en int() parce que strftime() renvoie une chaîne de caractères. Si c'est le cas, il est préférable d'utiliser DzinX's réponse.

3 votes

L'utilisation de strftime est indirecte, car elle produit une chaîne de caractères à partir d'un nombre : le membre timetuple.tm_yday. Lisez la source. La chaîne produite devrait être convertie en nombre avant tout calcul/comparaison, alors pourquoi s'en préoccuper ?

4 votes

Si l'on avait besoin du jour de l'année dans une chaîne, par exemple pour l'utiliser dans un nom de fichier, strftime est une solution beaucoup plus propre.

17voto

Dave X Points 169

La réponse de DZinX est une excellente réponse à la question. J'ai trouvé cette question et utilisé La réponse de DZinX en cherchant la fonction inverse : convertir les dates avec le jour de l'année julienne en datetimes.

J'ai trouvé ceci pour fonctionner :

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

Ou numériquement :

import datetime
year,julian = [1936,77]
datetime.datetime(year, 1, 1)+datetime.timedelta(days=julian -1)

>>>> datetime.datetime(1936, 3, 17, 0, 0)

Ou avec des dates fractionnaires basées sur 1, populaires dans certains domaines :

jdate_frac = (datetime.datetime(1936, 3, 17, 13, 14, 15)-datetime.datetime(1936, 1, 1)).total_seconds()/86400+1
display(jdate_frac)

>>>> 77.5515625

year,julian = [1936,jdate_frac]
display(datetime.datetime(year, 1, 1)+datetime.timedelta(days=julian -1))

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

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

12voto

Barry Andersen Points 42

Si vous avez des raisons d'éviter l'utilisation du datetime alors 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

0 votes

Vous pouvez aussi simplement copier/coller le code source de datetime github.com/python/cpython/blob/ mais pourquoi le ferais-tu quand tu peux juste import datetime ?

9voto

omikron Points 381

Je veux 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

1 votes

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)) ; écoulé 5.221366882324219e-05 def f() : int(today.strftime('%j')) ; start = time.time() ; f() ; print('Lapsed {}'.format( time.time() - start)) ; écoulé 7.462501525878906e-05

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X