Spróbuj tego:
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%100==0 or 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)
Edycja Poprawiona, aby obsłużyć również dzień.
Edytuj Zobacz także odpowiedź z zdziwienia, która wskazuje na prostsze obliczenie d
:
d = min(date.day, calendar.monthrange(y, m)[1])
((date.month+delta-1) % 12)+1
działa i oznacza, żeif not m: m = 12
puszka zostanie usuniętadt - timedelta(days=dt.day)
Jak pierwotnie sformułowano, chociaż brzmiało to tak, jakby chcieli mieć możliwość odjęcia dowolnej liczby miesięcy, a to jest nieco trudniejsze.29 if y%4==0 and (not y%100==0 or y%400 == 0) else 28
. np. 1600 to rok przestępny, a 1700 nieMożesz skorzystać z
dateutil
modułu strony trzeciej (wpis PyPI tutaj ).import datetime import dateutil.relativedelta d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d") d2 = d - dateutil.relativedelta.relativedelta(months=1) print d2
wynik:
2013-02-28 00:00:00
źródło
month
imonths
datutilem. Odejmowanie za pomocą parametrumonth
nie działa, alemonths
działaIn [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
będzie miało wpływ na 1 miesiąc. Użyciemonth
spowoduje ustawienie miesiąca na 1 (np. Styczeń), niezależnie od miesiąca wprowadzenia.Po edycji oryginalnego pytania na „dowolny obiekt daty i godziny w poprzednim miesiącu” możesz to zrobić dość łatwo, odejmując 1 dzień od pierwszego dnia miesiąca.
from datetime import datetime, timedelta def a_day_in_previous_month(dt): return dt.replace(day=1) - timedelta(days=1)
źródło
dt.replace(day=1) - timedelta(1)
dt - timedelta(days=dt.day)
Wektoryzowane rozwiązanie pandy jest bardzo proste:
df['date'] - pd.DateOffset(months=1)
źródło
pandas
. Dzięki!Odmiana odpowiedzi Duncana (nie mam wystarczającej reputacji, aby komentować), która wykorzystuje calendar.monthrange do radykalnego uproszczenia obliczeń ostatniego dnia miesiąca:
import calendar 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, calendar.monthrange(y, m)[1]) return date.replace(day=d,month=m, year=y)
Informacje o przedziale miesięcznym z Pobierz ostatni dzień miesiąca w Pythonie
źródło
Jaki ma być wynik, jeśli odejmiemy miesiąc od, powiedzmy, 30 marca? Na tym polega problem z dodawaniem lub odejmowaniem miesięcy: miesiące mają różną długość! W niektórych aplikacjach wyjątek jest odpowiedni w takich przypadkach, w innych można użyć „ostatniego dnia poprzedniego miesiąca” (ale to naprawdę szalona arytmetyka, gdy odejmowanie miesiąca to dodanie miesiąca nie oznacza ogólnie braku działania!) , w innych zechcesz oprócz daty zachować pewne wskazówki dotyczące faktu, np. „Mówię o 28 lutego, ale naprawdę chciałbym, aby 30 lutego istniał”, aby dodać lub odjąć kolejny miesiąc do które mogą ponownie naprawić sytuację (a ta ostatnia oczywiście wymaga niestandardowej klasy przechowującej dane i inne elementy).
Nie może istnieć żadne prawdziwe rozwiązanie, które byłoby tolerowane dla wszystkich aplikacji, a nie powiedziałeś nam, jakie są potrzeby Twojej aplikacji w zakresie semantyki tej nieszczęsnej operacji, więc nie możemy tutaj zapewnić dużo więcej pomocy.
źródło
datetime
moduły zakładają, że doba ma dokładnie 24 godziny (bez sekund przestępnych)Myślę, że najprostszym sposobem jest użycie DateOffset z Pandas w następujący sposób:
import pandas as pd date_1 = pd.to_datetime("2013-03-31", format="%Y-%m-%d") - pd.DateOffset(months=1)
Rezultatem będzie obiekt datetime
źródło
Jeśli chcesz tylko dowolnego dnia w ostatnim miesiącu, najprostszą rzeczą, jaką możesz zrobić, jest odjęcie liczby dni od bieżącej daty, co da ci ostatni dzień poprzedniego miesiąca.
Na przykład zaczynając od dowolnej daty:
>>> import datetime >>> today = datetime.date.today() >>> today datetime.date(2016, 5, 24)
Odejmując dni z bieżącej daty otrzymujemy:
>>> last_day_previous_month = today - datetime.timedelta(days=today.day) >>> last_day_previous_month datetime.date(2016, 4, 30)
To wystarczy na uproszczoną potrzebę dowolnego dnia w ostatnim miesiącu.
Ale teraz, gdy go masz, możesz również otrzymać dowolny dzień w miesiącu, w tym ten sam dzień, od którego zacząłeś (czyli mniej więcej to samo, co odejmowanie miesiąca):
>>> same_day_last_month = last_day_previous_month.replace(day=today.day) >>> same_day_last_month datetime.date(2016, 4, 24)
Oczywiście musisz uważać na 31. dnia 30-dniowego miesiąca lub dni brakujące od lutego (i zadbać o lata przestępne), ale to też jest łatwe:
>>> a_date = datetime.date(2016, 3, 31) >>> last_day_previous_month = a_date - datetime.timedelta(days=a_date.day) >>> a_date_minus_month = ( ... last_day_previous_month.replace(day=a_date.day) ... if a_date.day < last_day_previous_month.day ... else last_day_previous_month ... ) >>> a_date_minus_month datetime.date(2016, 2, 29)
źródło
Używam tego w rządowych latach budżetowych, w których czwarty kwartał rozpoczyna się 1 października. Uwaga: Konwertuję datę na kwartały i również ją cofam.
import pandas as pd df['Date'] = '1/1/2020' df['Date'] = pd.to_datetime(df['Date']) #returns 2020-01-01 df['NewDate'] = df.Date - pd.DateOffset(months=3) #returns 2019-10-01 <---- answer # For fun, change it to FY Quarter '2019Q4' df['NewDate'] = df['NewDate'].dt.year.astype(str) + 'Q' + df['NewDate'].dt.quarter.astype(str) # Convert '2019Q4' back to 2019-10-01 df['NewDate'] = pd.to_datetime(df.NewDate)
źródło
Zwraca ostatni dzień ostatniego miesiąca:
>>> import datetime >>> datetime.datetime.now() - datetime.timedelta(days=datetime.datetime.now().day) datetime.datetime(2020, 9, 30, 14, 13, 15, 67582)
Zwraca ten sam dzień w zeszłym miesiącu:
>>> x = datetime.datetime.now() - datetime.timedelta(days=datetime.datetime.now().day) >>> x.replace(day=datetime.datetime.now().day) datetime.datetime(2020, 9, 7, 14, 22, 14, 362421)
źródło
Oto kod, który to robi. Sam tego nie wypróbowałem ...
def add_one_month(t): """Return a `datetime.date` or `datetime.datetime` (as given) that is one month earlier. Note that the resultant day of the month might change if the following month has fewer days: >>> add_one_month(datetime.date(2010, 1, 31)) datetime.date(2010, 2, 28) """ import datetime one_day = datetime.timedelta(days=1) one_month_later = t + one_day while one_month_later.month == t.month: # advance to start of next month one_month_later += one_day target_month = one_month_later.month while one_month_later.day < t.day: # advance to appropriate day one_month_later += one_day if one_month_later.month != target_month: # gone too far one_month_later -= one_day break return one_month_later def subtract_one_month(t): """Return a `datetime.date` or `datetime.datetime` (as given) that is one month later. Note that the resultant day of the month might change if the following month has fewer days: >>> subtract_one_month(datetime.date(2010, 3, 31)) datetime.date(2010, 2, 28) """ import datetime one_day = datetime.timedelta(days=1) one_month_earlier = t - one_day while one_month_earlier.month == t.month or one_month_earlier.day > t.day: one_month_earlier -= one_day return one_month_earlier
źródło
Biorąc pod uwagę krotkę (rok, miesiąc), w której miesiąc trwa od 1 do 12, spróbuj tego:
>>> from datetime import datetime >>> today = datetime.today() >>> today datetime.datetime(2010, 8, 6, 10, 15, 21, 310000) >>> thismonth = today.year, today.month >>> thismonth (2010, 8) >>> lastmonth = lambda (yr,mo): [(y,m+1) for y,m in (divmod((yr*12+mo-2), 12),)][0] >>> lastmonth(thismonth) (2010, 7) >>> lastmonth( (2010,1) ) (2009, 12)
Zakłada się, że w każdym roku jest 12 miesięcy.
źródło
def month_sub(year, month, sub_month): result_month = 0 result_year = 0 if month > (sub_month % 12): result_month = month - (sub_month % 12) result_year = year - (sub_month / 12) else: result_month = 12 - (sub_month % 12) + month result_year = year - (sub_month / 12 + 1) return (result_year, result_month) >>> month_sub(2015, 7, 1) (2015, 6) >>> month_sub(2015, 7, -1) (2015, 8) >>> month_sub(2015, 7, 13) (2014, 6) >>> month_sub(2015, 7, -14) (2016, 9)
źródło
Użyłem następującego kodu, aby cofnąć się n miesięcy od określonej daty:
your_date = datetime.strptime(input_date, "%Y-%m-%d") #to convert date(2016-01-01) to timestamp start_date=your_date #start from current date #Calculate Month for i in range(0,n): #n = number of months you need to go back start_date=start_date.replace(day=1) #1st day of current month start_date=start_date-timedelta(days=1) #last day of previous month #Calculate Day if(start_date.day>your_date.day): start_date=start_date.replace(day=your_date.day) print start_date
Na przykład: data wprowadzenia = 28/12/2015 Oblicz 6 miesięcy poprzednią datę.
I) OBLICZ MIESIĄC: W tym kroku podana zostanie data_początkowa jako 30/06/2015.
Zwróć uwagę, że po kroku obliczania miesiąca otrzymasz ostatni dzień wymaganego miesiąca.
II) KALKULUJ DZIEŃ: Warunek, jeśli (data_początkowa.dzień> twoja_data.dzień) sprawdza, czy dzień z input_date występuje w wymaganym miesiącu. Dotyczy to warunku, w którym data wprowadzenia to 31 (lub 30), a wymagany miesiąc ma mniej niż 31 (lub 30 w przypadku lutego) dni. Obsługuje również przypadek roku przestępnego (dla lutego). Po tym kroku otrzymasz wynik jako 28/06/2015
Jeśli ten warunek nie jest spełniony, data_początkowa pozostaje ostatnią datą poprzedniego miesiąca. Więc jeśli podasz 31/12/2015 jako datę wejściową i chcesz 6 miesięcy wcześniejszą datę, otrzymasz 30/06/2015
źródło
Możesz użyć poniższej funkcji, aby uzyskać datę przed / po X miesiącu.
źródło
Myślę, że ta odpowiedź jest całkiem czytelna:
def month_delta(dt, delta): year_delta, month = divmod(dt.month + delta, 12) if month == 0: # convert a 0 to december month = 12 if delta < 0: # if moving backwards, then it's december of last year year_delta -= 1 year = dt.year + year_delta return dt.replace(month=month, year=year) for delta in range(-20, 21): print(delta, "->", month_delta(datetime(2011, 1, 1), delta)) -20 -> 2009-05-01 00:00:00 -19 -> 2009-06-01 00:00:00 -18 -> 2009-07-01 00:00:00 -17 -> 2009-08-01 00:00:00 -16 -> 2009-09-01 00:00:00 -15 -> 2009-10-01 00:00:00 -14 -> 2009-11-01 00:00:00 -13 -> 2009-12-01 00:00:00 -12 -> 2010-01-01 00:00:00 -11 -> 2010-02-01 00:00:00 -10 -> 2010-03-01 00:00:00 -9 -> 2010-04-01 00:00:00 -8 -> 2010-05-01 00:00:00 -7 -> 2010-06-01 00:00:00 -6 -> 2010-07-01 00:00:00 -5 -> 2010-08-01 00:00:00 -4 -> 2010-09-01 00:00:00 -3 -> 2010-10-01 00:00:00 -2 -> 2010-11-01 00:00:00 -1 -> 2010-12-01 00:00:00 0 -> 2011-01-01 00:00:00 1 -> 2011-02-01 00:00:00 2 -> 2011-03-01 00:00:00 3 -> 2011-04-01 00:00:00 4 -> 2011-05-01 00:00:00 5 -> 2011-06-01 00:00:00 6 -> 2011-07-01 00:00:00 7 -> 2011-08-01 00:00:00 8 -> 2011-09-01 00:00:00 9 -> 2011-10-01 00:00:00 10 -> 2011-11-01 00:00:00 11 -> 2012-12-01 00:00:00 12 -> 2012-01-01 00:00:00 13 -> 2012-02-01 00:00:00 14 -> 2012-03-01 00:00:00 15 -> 2012-04-01 00:00:00 16 -> 2012-05-01 00:00:00 17 -> 2012-06-01 00:00:00 18 -> 2012-07-01 00:00:00 19 -> 2012-08-01 00:00:00 20 -> 2012-09-01 00:00:00
źródło
Jedna wkładka?
previous_month_date = (current_date - datetime.timedelta(days=current_date.day+1)).replace(day=current_date.day)
źródło
Najprostszy sposób, który wypróbowałem Właśnie teraz
from datetime import datetime from django.utils import timezone current = timezone.now() if current.month == 1: month = 12 else: month = current.month - 1 current = datetime(current.year, month, current.day)
źródło
Jakiś czas temu natknąłem się na następujący algorytm, który działa bardzo dobrze dla zwiększania i zmniejszania miesięcy albo na
date
lubdatetime
.UWAGA : To się nie powiedzie, jeśli
day
nie będzie dostępne w nowym miesiącu. Używam tego na obiektach daty, gdzieday == 1
zawsze.Python 3.x:
def increment_month(d, add=1): return date(d.year+(d.month+add-1)//12, (d.month+add-1) % 12+1, 1)
W przypadku Pythona 2.7 zmień wartość
//12
na,/12
ponieważ zakłada się dzielenie liczb całkowitych.Niedawno użyłem tego w pliku domyślnym, gdy skrypt zaczął pobierać te przydatne globale:
MONTH_THIS = datetime.date.today() MONTH_THIS = datetime.date(MONTH_THIS.year, MONTH_THIS.month, 1) MONTH_1AGO = datetime.date(MONTH_THIS.year+(MONTH_THIS.month-2)//12, (MONTH_THIS.month-2) % 12+1, 1) MONTH_2AGO = datetime.date(MONTH_THIS.year+(MONTH_THIS.month-3)//12, (MONTH_THIS.month-3) % 12+1, 1)
źródło
import datetime date_str = '08/01/2018' format_str = '%d/%m/%Y' datetime_obj = datetime.datetime.strptime(date_str, format_str) datetime_obj.replace(month=datetime_obj.month-1)
Proste rozwiązanie, bez specjalnych bibliotek.
źródło
Możesz to zrobić w dwóch wierszach w ten sposób:
now = datetime.now() last_month = datetime(now.year, now.month - 1, now.day)
pamiętaj import
from datetime import datetime
źródło