Experimente isto:
def monthdelta(date, delta):
m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
if not m: m = 12
d = min(date.day, [31,
29 if y%4==0 and not y%400==0 else 28,31,30,31,30,31,31,30,31,30,31][m-1])
return date.replace(day=d,month=m, year=y)
>>> for m in range(-12, 12):
print(monthdelta(datetime.now(), m))
2009-08-06 16:12:27.823000
2009-09-06 16:12:27.855000
2009-10-06 16:12:27.870000
2009-11-06 16:12:27.870000
2009-12-06 16:12:27.870000
2010-01-06 16:12:27.870000
2010-02-06 16:12:27.870000
2010-03-06 16:12:27.886000
2010-04-06 16:12:27.886000
2010-05-06 16:12:27.886000
2010-06-06 16:12:27.886000
2010-07-06 16:12:27.886000
2010-08-06 16:12:27.901000
2010-09-06 16:12:27.901000
2010-10-06 16:12:27.901000
2010-11-06 16:12:27.901000
2010-12-06 16:12:27.901000
2011-01-06 16:12:27.917000
2011-02-06 16:12:27.917000
2011-03-06 16:12:27.917000
2011-04-06 16:12:27.917000
2011-05-06 16:12:27.917000
2011-06-06 16:12:27.933000
2011-07-06 16:12:27.933000
>>> monthdelta(datetime(2010,3,30), -1)
datetime.datetime(2010, 2, 28, 0, 0)
>>> monthdelta(datetime(2008,3,30), -1)
datetime.datetime(2008, 2, 29, 0, 0)
Editar corrigido para controlar o dia também.
Editar Veja também a resposta de perplexidade, que aponta um cálculo mais simples para d
:
d = min(date.day, calendar.monthrange(y, m)[1])
((date.month+delta-1) % 12)+1
funciona e significa queif not m: m = 12
pode ser removidodt - timedelta(days=dt.day)
As formulado originalmente, embora pareça que eles querem ser capazes de subtrair um número arbitrário de meses e isso é um pouco mais difícil.Você pode usar o
dateutil
módulo de terceiros (entrada PyPI aqui ).resultado:
fonte
month
emonths
no dateutil. Subtrair com parammonth
não funciona, masmonths
funcionaIn [23]: created_datetime__lt - relativedelta(months=1) Out[23]: datetime.datetime(2016, 11, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>) In [24]: created_datetime__lt - relativedelta(month=1) Out[24]: datetime.datetime(2016, 1, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/GMT-8'>)
months
fará uma diferença de 1 mês. Usarmonth
irá definir o mês como 1 (por exemplo, janeiro), independentemente do mês da entrada.Após a edição da pergunta original para "qualquer objeto datetime no mês anterior", você pode fazer isso facilmente subtraindo 1 dia do primeiro dia do mês.
fonte
dt.replace(day=1) - timedelta(1)
dt - timedelta(days=dt.day)
Uma variação da resposta de Duncan (não tenho reputação suficiente para comentar), que usa calendar.monthrange para simplificar drasticamente o cálculo do último dia do mês:
Informações sobre o intervalo do mês desde Obter o último dia do mês em Python
fonte
Uma solução vetorizada de pandas é muito simples:
df['date'] - pd.DateOffset(months=1)
fonte
pandas
. Obrigado!Qual você deseja que seja o resultado ao subtrair um mês de, digamos, uma data que é 30 de março? Esse é o problema de adicionar ou subtrair meses: os meses têm durações diferentes! Em alguns aplicativos, uma exceção é apropriada em tais casos, em outros, "o último dia do mês anterior" está OK para usar (mas isso é aritmética realmente maluca, quando subtrair um mês e depois adicionar um mês não é uma operação geral!) , em outros ainda, você desejará manter além da data alguma indicação sobre o fato, por exemplo, "Estou dizendo 28 de fevereiro, mas eu realmente gostaria de 30 de fevereiro se existisse", de modo que adicionar ou subtrair outro mês para que pode consertar as coisas novamente (e o último obviamente requer uma classe customizada contendo dados e outras coisas).
Não pode haver solução real que seja tolerável para todos os aplicativos, e você não nos disse quais são as necessidades específicas do seu aplicativo para a semântica desta operação miserável, então não há muito mais ajuda que possamos fornecer aqui.
fonte
datetime
modules assume que um dia é exatamente 24 horas (sem segundos bissextos)Acho que a maneira mais simples é usar DateOffset do Pandas assim:
O resultado será um objeto datetime
fonte
Se tudo o que você deseja é qualquer dia do último mês, a coisa mais simples que você pode fazer é subtrair o número de dias da data atual, o que lhe dará o último dia do mês anterior.
Por exemplo, começando com qualquer data:
Subtraindo os dias da data atual, obtemos:
Isso é o suficiente para sua necessidade simplificada de qualquer dia do último mês.
Mas agora que você o tem, também pode obter qualquer dia do mês, incluindo o mesmo dia em que começou (ou seja, mais ou menos o mesmo que subtrair um mês):
Claro, você precisa ter cuidado com o 31º em um mês de 30 dias ou os dias que faltam a partir de fevereiro (e cuidar dos anos bissextos), mas isso também é fácil de fazer:
fonte
Eu uso isso para os anos fiscais do governo em que o quarto trimestre começa em 1º de outubro. Observe que eu converto a data em trimestres e também desfaço.
fonte
Aqui está um código para fazer exatamente isso. Ainda não experimentei ...
fonte
Dada uma tupla (ano, mês), em que mês vai de 1 a 12, tente o seguinte:
Presume-se que haja 12 meses em cada ano.
fonte
fonte
Usei o seguinte código para voltar n meses a partir de uma data específica:
Por exemplo: data de entrada = 28/12/2015 Calcule 6 meses da data anterior.
I) CALCULAR MÊS: Esta etapa fornecerá a data_início como 30/06/2015.
Observe que, após a etapa de cálculo do mês, você obterá o último dia do mês necessário.
II) CALCULAR DIA: Condição if (start_date.day> your_date.day) verifica se o dia de input_date está presente no mês requerido. Isso lida com condições em que a data de entrada é 31 (ou 30) e o mês necessário tem menos de 31 (ou 30 no caso de fev) dias. Ele lida com casos de ano bissexto também (para fevereiro). Após esta etapa, você obterá o resultado 28/06/2015
Se esta condição não for satisfeita, a data_de_início permanece como a última data do mês anterior. Portanto, se você fornecer 31/12/2015 como data de entrada e quiser uma data de 6 meses anteriores, ele fornecerá 30/06/2015
fonte
Você pode usar a função fornecida abaixo para obter a data antes / depois de X meses.
fonte
Acho que esta resposta é bastante legível:
fonte
Um forro?
previous_month_date = (current_date - datetime.timedelta(days=current_date.day+1)).replace(day=current_date.day)
fonte
Maneira mais simples que tentei agora
fonte
Algum tempo atrás, encontrei o seguinte algoritmo que funciona muito bem para aumentar e diminuir meses em um
date
oudatetime
.AVISO : Isso falhará se
day
não estiver disponível no novo mês. Eu uso isso em objetos de data, ondeday == 1
sempre.Python 3.x:
Para Python 2.7, mude o
//12
para apenas/12
porque a divisão inteira está implícita.Recentemente, usei isso em um arquivo de padrões quando um script começou a obter esses globais úteis:
fonte
Solução simples, sem necessidade de bibliotecas especiais.
fonte
Você poderia fazer isso em duas linhas como esta:
lembre-se das importações
fonte