Converter ano / mês / dia em dia do ano em Python

127

Estou usando o módulo datetime do Python , ou seja:

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

e gostaria de calcular o dia do ano sensível aos anos bissextos. por exemplo, hoje (6 de março de 2009) é o 65º dia de 2009. Aqui está a calculadora DateTime baseada na Web .

Enfim, vejo duas opções:

A. Crie um número_de_dias_em_month array = [31, 28, ...], decida se é um ano bissexto, resuma manualmente os dias.

B. Use datetime.timedeltapara fazer um palpite e, em seguida, pesquisa binária para o dia correto do ano:

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

Ambos parecem muito desajeitados e eu sinto que há uma maneira mais "pitônica" de calcular o dia do ano. Alguma idéia / sugestão?

Pete
fonte

Respostas:

255

Existe uma solução muito simples:

from datetime import datetime
day_of_year = datetime.now().timetuple().tm_yday
DzinX
fonte
13
Uma adição muito menor e sem dúvida pedante, mas usar date.today()ao invés de datetime.now()também funciona e enfatiza a natureza da operação um pouco mais.
Jeremy
5
Melhor ainda: não time.localtime().tm_yday há necessidade de converter uma data e hora em um horário, pois é o que localtime () gera.
Mike Ellis
14
@ MikeEllis Mas esta solução ilustra o que fazer quando a data e hora não corresponde a hoje.
gerrit
2
Nota: isso começa a contar em 1
Mehdi Nellen
1
e se eu quiser fazer o inverso, tenho o número digamos "26º dia do ano 2020" e quero convertê-lo para uma data "26-01-2020"?
Sankar
43

Você não poderia usar strftime?

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

Editar

Conforme observado nos comentários, se você deseja fazer comparações ou cálculos com esse número, precisará convertê-lo para, int()porque strftime()retorna uma string. Se for esse o caso, é melhor usar a resposta do DzinX .

Paolo Bergantino
fonte
1
-1: nojento. Melhor é o algoritmo "hoje menos 1º de janeiro". Muito mais limpo e perfeitamente óbvio, sem procurar informações sobre o '% j' do strftime.
275/09 S.Lott
12
Seriamente? Como é este 1º de janeiro, nojento e subtraído, não é? strftime está lá por uma razão. Eu simplesmente não concordo. Isso é muito limpo na minha opinião.
Paolo Bergantino
1
O uso de strftime é indireto, porque produz uma sequência a partir de um número: o membro scheduple.tm_yday. Leia a fonte. A sequência produzida deve ser convertida em um número antes de qualquer cálculo / comparação; então, por que se preocupar?
tzot 8/03/09
2
Se alguém precisou do dia do ano em uma string, digamos para uso em um nome de arquivo, então strftime é uma solução muito mais limpa.
Capit_M
13

A resposta do DZinX é uma ótima resposta para a pergunta. Encontrei essa pergunta enquanto procurava a função inversa. Eu achei que isso funcionava:

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

Não tenho certeza da etiqueta por aqui, mas achei que um ponteiro para a função inversa poderia ser útil para outras pessoas como eu.

Dave X
fonte
6

Quero apresentar o desempenho de diferentes abordagens, no Python 3.4, Linux x64. Trecho do criador de perfil de linha:

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

Então, o mais eficiente é

yday = (period_end - date(period_end.year, 1, 1)).days
omikron
fonte
1
Como você calculou o desempenho? Eu tentei usar time.time e esses são os meus resultados: def f (): (today - datetime.datetime (today.year, 1, 1)). Days + 1 start = time.time (); f (); print ('Lapsed {}'. formato (time.time () - início)); 5.221366882324219e-05 defasado def f (): int (today.strftime ('% j')); start = time.time (); f (); print ('Lapsed {}'. formato (time.time () - início)); Caducado 7.462501525878906e-05
ssoto
5

Apenas subtraia 1 de janeiro da data:

import datetime
today = datetime.datetime.now()
day_of_year = (today - datetime.datetime(today.year, 1, 1)).days + 1
zweiterlinde
fonte
1
Nada contra Paolo, mas datetime.timedelta é denominada em dias (assim como segundos e microssegundos, é claro), por isso é uma escolha natural --- certamente mais direta do que seqüência de formatação
zweiterlinde
1
d.toordinal () - data (d.ano, 1, 1) .toordinal () + 1 é mais padrão de acordo com a documentação. É equivalente à resposta aceita sem produzir a tupla o tempo todo.
Dingle
5

Se você tiver motivos para evitar o uso do datetimemódulo, essas funções funcionarão.

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
fonte
1

Este código assume uma data como argumento de entrada e retorna o dia do ano.

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
fonte