Tenho a necessidade de encontrar com precisão os meses entre duas datas em python. Tenho uma solução que funciona, mas não é muito boa (como no elegante) ou rápida.
dateRange = [datetime.strptime(dateRanges[0], "%Y-%m-%d"), datetime.strptime(dateRanges[1], "%Y-%m-%d")]
months = []
tmpTime = dateRange[0]
oneWeek = timedelta(weeks=1)
tmpTime = tmpTime.replace(day=1)
dateRange[0] = tmpTime
dateRange[1] = dateRange[1].replace(day=1)
lastMonth = tmpTime.month
months.append(tmpTime)
while tmpTime < dateRange[1]:
if lastMonth != 12:
while tmpTime.month <= lastMonth:
tmpTime += oneWeek
tmpTime = tmpTime.replace(day=1)
months.append(tmpTime)
lastMonth = tmpTime.month
else:
while tmpTime.month >= lastMonth:
tmpTime += oneWeek
tmpTime = tmpTime.replace(day=1)
months.append(tmpTime)
lastMonth = tmpTime.month
Então, apenas para explicar, o que estou fazendo aqui é pegar as duas datas e convertê-las do formato iso em objetos datetime em Python. Em seguida, faço um loop adicionando uma semana ao objeto de data e hora de início e verifico se o valor numérico do mês é maior (a menos que o mês seja dezembro, então ele verifica se a data é menor). Se o valor for maior, eu o anexo à lista de meses e continuo repetindo até chegar à data de término.
Funciona perfeitamente, só não parece uma boa maneira de fazer ...
python
datetime
monthcalendar
date-math
Joshkunz
fonte
fonte
Respostas:
Atualização 20/04/2018: parece que OP @Joshkunz estava pedindo para descobrir quais meses estão entre duas datas, em vez de "quantos meses" estão entre duas datas. Portanto, não sei por que @JohnLaRooy recebeu votos positivos mais de 100 vezes. @Joshkunz indicou no comentário sob a pergunta original que queria as datas reais [ou os meses], em vez de calcular o número total de meses .
Então, parecia que a pergunta era desejada, por entre duas datas
2018-04-11
para2018-06-01
E se for entre
2014-04-11
a2018-06-01
? Então a resposta seriaÉ por isso que tenho o seguinte pseudocódigo há muitos anos. Ele apenas sugeriu usar os dois meses como pontos finais e fazer um loop através deles, incrementando em um mês de cada vez. @Joshkunz mencionou que queria os "meses" e também mencionou que queria as "datas", sem saber exatamente, era difícil escrever o código exato, mas a ideia é usar um loop simples para percorrer os pontos finais, e incrementando um mês de cada vez.
A resposta há 8 anos em 2010:
Se adicionar por uma semana, ele executará aproximadamente 4,35 vezes o trabalho necessário. Por que não apenas:
apenas código pseduo por enquanto, não testei, mas acho que a ideia na mesma linha funcionará.
fonte
1
para2
e de2
para3
mais tarde.Comece definindo alguns casos de teste, então você verá que a função é muito simples e não precisa de loops
Você deve adicionar alguns casos de teste à sua pergunta, pois há muitos casos potenciais para cobrir - há mais de uma maneira de definir o número de meses entre duas datas.
fonte
Uma linha para encontrar uma lista de datas e horas, incrementada por mês, entre duas datas.
fonte
[dt for dt in rrule(MONTHLY, bymonthday=10,dtstart=strt_dt, until=end_dt)]
start_date_first = start_date.replace(day=1), end_date_first = end_date.replace(day=1)
seguir, a regra conta os meses corretamente.Isso funcionou para mim -
fonte
str()
torno de literais de string.r.months
começará de 0Você pode calcular isso facilmente usando rrule do módulo dateutil :
Darei à você:
fonte
Obtenha o mês de término (em relação ao ano e mês do mês de início, ex: janeiro de 2011 = 13 se sua data de início começar em outubro de 2010) e, em seguida, gere os datetimes começando no mês de início e aquele mês final da seguinte forma:
se ambas as datas estiverem no mesmo ano, também pode ser simplesmente escrito como:
fonte
Este post acerta! Use
dateutil.relativedelta
.fonte
str()
elenco que fiz é completamente desnecessário.relativedelta.relativedelta(date2, date1).years * 12
delta.years*12 + delta.months
Minha solução simples:
fonte
Definir um "mês", como 1 / 12 ano, em seguida, faça o seguinte:
Você pode tentar definir um mês como "um período de 29, 28, 30 ou 31 dias (dependendo do ano)". Mas você faz isso, você tem um problema adicional para resolver.
Embora seja geralmente claro que 15 de junho th + 1 mês deve ser 15 de julho th , não é geralmente não está claro se 30 de janeiro th + 1 mês é em fevereiro ou março. Neste último caso, você pode ser obrigado a calcular a data como 30 de fevereiro th , em seguida, "correta" que a 2 de Março nd . Mas quando você faz isso, você verá que 02 de março nd - 1 mês é claramente 02 de fevereiro nd . Portanto, reductio ad absurdum (esta operação não está bem definida).
fonte
Existe uma solução simples baseada em anos de 360 dias, onde todos os meses têm 30 dias. Ele se encaixa na maioria dos casos de uso em que, dadas duas datas, você precisa calcular o número de meses completos mais os dias restantes.
fonte
Uma solução um pouco embelezada por @Vin-G.
fonte
Você também pode usar a biblioteca de setas . Este é um exemplo simples:
Isso irá imprimir:
Espero que isto ajude!
fonte
fonte
Experimente algo assim. Atualmente, inclui o mês se ambas as datas forem no mesmo mês.
A saída se parece com:
fonte
Você pode usar python-dateutil . Veja Python: diferença de 2 datetimes em meses
fonte
Veja como fazer isso com o Pandas FWIW:
Observe que ele começa com o mês após a data de início fornecida.
fonte
Isso pode ser feito usando datetime.timedelta, onde o número de dias para pular para o próximo mês pode ser obtido por calender.monthrange. monthrange retorna o dia da semana (0-6 ~ Seg-Dom) e o número de dias (28-31) para um determinado ano e mês.
Por exemplo: monthrange (2017, 1) retorna (6,31).
Aqui está o script usando essa lógica para iterar entre dois meses.
`
fonte
Muitas pessoas já lhe deram boas respostas para resolver isso, mas eu não li nenhuma usando compreensão de lista, então eu dou o que usei para um caso de uso semelhante:
fonte
fonte
assim como a
range
função, quando o mês for 13 , vá para o próximo anoexemplo em shell python
fonte
Normalmente 90 dias NÃO são 3 meses literalmente, apenas uma referência.
Então, finalmente, você precisa verificar se os dias são maiores que 15 para adicionar +1 ao contador do mês. ou melhor, adicione outro elif com contador de meio mês.
A partir dessa outra resposta stackoverflow, finalmente terminei com isso:
Resultado:
Percebi que isso não funciona se você adicionar mais do que dias restantes no ano atual, e isso é inesperado.
fonte
parece que as respostas são insatisfatórias e desde então uso meu próprio código, que é mais fácil de entender
fonte
fonte
Supondo que upperDate seja sempre posterior a lowerDate e ambos sejam objetos datetime.date:
Eu não testei isso completamente, mas parece que deve funcionar.
fonte
Aqui está um método:
Este é o primeiro cálculo do número total de meses entre as duas datas, inclusive. Em seguida, ele cria uma lista usando a primeira data como base e executa a aritmética de módulos para criar os objetos de data.
fonte
Na verdade, eu precisava fazer algo bem parecido agora
Acabei escrevendo uma função que retorna uma lista de tuplas indicando o
start
eend
de cada mês entre dois conjuntos de datas para que eu pudesse escrever algumas consultas SQL atrás dela para totais mensais de vendas etc.Tenho certeza que pode ser melhorado por alguém que sabe o que está fazendo, mas espero que ajude ...
O valor retornado é o seguinte (gerando para hoje - 365 dias até hoje como exemplo)
Código da seguinte forma (tem algumas coisas de depuração que podem ser removidas):
fonte
Supondo que você queira saber a "fração" do mês em que as datas estavam, o que eu fiz, você precisa trabalhar um pouco mais.
fornece um exemplo que calcula o número de meses entre duas datas inclusive, incluindo a fração de cada mês em que a data está. Isso significa que você pode calcular quantos meses estão entre 20/01/2015 e 14/02/2015 , onde a fração da data no mês de janeiro é determinada pelo número de dias em janeiro; ou tendo igualmente em conta que o número de dias em fevereiro pode mudar de ano para ano.
Para minha referência, este código também está no github - https://gist.github.com/andrewyager/6b9284a4f1cdb1779b10
fonte
Experimente isto:
Não importa a ordem em que você insere as datas e leva em consideração a diferença na duração dos meses.
fonte
Isso funciona...
fonte
fonte