Converti Anno / Mese / Giorno in Giorno dell'anno in Python


127

Sto usando il modulo datetime Python , ovvero:

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

e vorrei calcolare il giorno dell'anno sensibile agli anni bisestili. ad es. oggi (6 marzo 2009) è il 65 ° giorno del 2009. Ecco il calcolatore DateTime basato sul web .

Ad ogni modo, vedo due opzioni:

A. Crea un array number_of_days_in_month = [31, 28, ...], decidi se è un anno bisestile, riassumi manualmente i giorni.

B. Usare datetime.timedeltaper fare un'ipotesi e quindi una ricerca binaria per il giorno dell'anno corretto:

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

Entrambi sembrano piuttosto goffi e ho la sensazione che ci sia un modo più "Pythonic" di calcolare il giorno dell'anno. Qualche idea / suggerimento?

Risposte:


256

C'è una soluzione molto semplice:

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday

13
Un'aggiunta molto minore e discutibilmente pedante, ma l'utilizzo date.today()piuttosto che datetime.now()anche funziona e sottolinea un po 'di più la natura dell'operazione.
Jeremy il

5
Meglio ancora: non time.localtime().tm_yday c'è bisogno di convertire un datetime in un orario poiché questo è ciò che rende localtime ().
Mike Ellis,

14
@MikeEllis Ma questa soluzione illustra cosa fare quando il datetime non corrisponde oggi.
Gerrit,

2
nota: questo inizia a contare da 1
Mehdi Nellen

1
cosa succede se voglio fare il contrario, ho il numero diciamo "26 ° giorno dell'anno 2020" e voglio che sia convertito in una data "26-01-2020"?
Sankar,

43

Non potresti usare strftime?

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

modificare

Come notato nei commenti, se si desidera effettuare confronti o calcoli con questo numero, è necessario convertirlo in int()perché strftime()restituisce una stringa. In tal caso, è meglio usare la risposta di DzinX .


1
-1: icky. Meglio è l'algoritmo "oggi meno il 1 ° gennaio". Molto più pulito e perfettamente ovvio senza cercare una curiosità sulla "% j" dello Strftime.
S.Lott

12
Sul serio? In che modo non è questo icky e sottrattivo il 1 ° gennaio? Strftime è lì per un motivo. Non sono d'accordo. Questo è MODO più pulito secondo me.
Paolo Bergantino,

1
L'uso di strftime è indiretto, perché produce una stringa da un numero: il membro timetuple.tm_yday. Leggi la fonte La stringa prodotta deve essere convertita in un numero prima di calcoli / confronti, quindi perché preoccuparsi?
martedì

2
Se uno ha bisogno del giorno dell'anno in una stringa, diciamo per l'uso in un nome di file, che strftime è una soluzione molto più pulita.
captain_M

13

La risposta di DZinX è un'ottima risposta alla domanda. Ho trovato questa domanda mentre cercavo la funzione inversa. Ho trovato che questo funziona:

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

Non sono sicuro dell'etichetta qui intorno, ma ho pensato che un puntatore alla funzione inversa potesse essere utile per altri come me.


6

Voglio presentare le prestazioni di diversi approcci, su Python 3.4, Linux x64. Estratto dal profiler di linea:

      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
         (...)

Quindi è più efficiente

yday = (period_end - date(period_end.year, 1, 1)).days

1
Come hai calcolato le prestazioni? Ho provato a usare time.time e questi sono i miei risultati: def f (): (oggi - datetime.datetime (today.year, 1, 1)). Giorni + 1 inizio = time.time (); f (); print ('Lapsed {}'. format (time.time () - start)); Girato 5.221366882324219e-05 def f (): int (today.strftime ('% j')); start = time.time (); f (); print ('Lapsed {}'. format (time.time () - start)); Girato 7.462501525878906e-05
ssoto

5

Sottrai solo il 1 ° gennaio dalla data:

import datetime
today = datetime.datetime.now()
day_of_year = (today - datetime.datetime(today.year, 1, 1)).days + 1

1
Nulla contro Paolo, ma datetime.timedelta è denominato in giorni (oltre a secondi e microsecondi, ovviamente), quindi è una scelta naturale --- sicuramente più diretta della formattazione delle stringhe
zweiterlinde

1
d.toordinal () - date (d.year, 1, 1) .toordinal () + 1 è più standard in base alla documentazione. È equivalente alla risposta accettata senza produrre la tupla per tutto il tempo.
Dingle,

5

Se hai motivo di evitare l'uso del datetimemodulo, queste funzioni funzioneranno.

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

1

Questo codice accetta una data come argomento di input e restituisce il giorno dell'anno.

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