Python data poprzedniego miesiąca

131

Próbuję uzyskać datę poprzedniego miesiąca za pomocą Pythona. Oto, czego próbowałem:

str( time.strftime('%Y') ) + str( int(time.strftime('%m'))-1 )

Jednak ten sposób jest zły z 2 powodów: po pierwsze zwraca 20122 dla lutego 2012 (zamiast 201202), a po drugie zwraca 0 zamiast 12 w styczniu.

Rozwiązałem ten problem w bash z

echo $(date -d"3 month ago" "+%G%m%d")

Myślę, że jeśli bash ma wbudowany sposób do tego celu, to znacznie lepiej wyposażony python powinien zapewnić coś lepszego niż zmuszanie do pisania własnego skryptu, aby osiągnąć ten cel. Oczywiście mógłbym zrobić coś takiego:

if int(time.strftime('%m')) == 1:
    return '12'
else:
    if int(time.strftime('%m')) < 10:
        return '0'+str(time.strftime('%m')-1)
    else:
        return str(time.strftime('%m') -1)

Nie testowałem tego kodu i i tak nie chcę go używać (chyba że nie mogę znaleźć innego sposobu: /)

Dzięki za pomoc!

philippe
źródło

Odpowiedzi:

299

datetime i datetime.timedelta są Twoimi przyjaciółmi.

  1. znaleźć dzisiaj.
  2. użyj go, aby znaleźć pierwszy dzień tego miesiąca.
  3. użyj timedelta, aby wykonać kopię zapasową od jednego dnia do ostatniego dnia poprzedniego miesiąca.
  4. wydrukuj ciąg YYYYMM, którego szukasz.

Lubię to:

 import datetime
 today = datetime.date.today()
 first = today.replace(day=1)
 lastMonth = first - datetime.timedelta(days=1)
 print(lastMonth.strftime("%Y%m"))

201202 jest drukowane.

bgporter
źródło
31
możesz użyć .replace()metody:datetime.utcnow().replace(day=1) - timedelta(days=1)
jfs
1
Chłodny! Brakowało mi metody wymiany.
bgporter
Możesz także połączyć .replace()funkcję. Zrób to raz, aby uzyskać ostatni miesiąc, a następnie zrób to ponownie, aby uzyskać żądany dzień. Najpierw: d = date.today() potemone_month_ago = (d.replace(day=1) - timedelta(days=1)).replace(day=d.day)
Thane Plummer
@JFSebastian Masz rację - dziękuję za zwrócenie uwagi. Wydaje się, że nie ma w tym przypadku eleganckiej, jednoliniowej treści, ponieważ „miesiąc” nie jest stałym okresem. Możesz zrobić coś brzydkiego, importując calendari używając calendar.mdays[d.month-1]więcej brzydoty w min()funkcji drugiej replace, ale wydaje się nie-Pythonic i nie uwzględnia przypadków narożnych. Zaktualizowałem moją odpowiedź poniżej, używając try - exceptkont we wszystkich przypadkach, chociaż nienawidzę używać wyjątków jako części algorytmu.
Thane Plummer
zobacz odpowiedź Iwana i dodaj: min (date.today (). day, last_day_of_previous_month.day)
michel.iamit
70

Powinieneś użyć dateutil . Dzięki temu możesz użyć relativedelta, jest to ulepszona wersja timedelta.

>>> import datetime 
>>> import dateutil.relativedelta
>>> now = datetime.datetime.now()
>>> print now
2012-03-15 12:33:04.281248
>>> print now + dateutil.relativedelta.relativedelta(months=-1)
2012-02-15 12:33:04.281248
Dave Butler
źródło
Nie działa przez pierwszy miesiąc roku: >>> IllegalMonthError: zły numer miesiąca -1; musi być 1-12
mtoloo
@mtoloo Jaka wersja dateutil? Nie mam tego problemu, ale dodam alternatywną składnię
Dave Butler
1
Wolę ten, ponieważ chociaż @bgporter ma bardzo fajne rozwiązanie, jego jedno nie działa tak dobrze, gdy patrzy się na następny miesiąc.
Daniel F
3
@mtoloo Prawdopodobnie błędnie wpisałeś miesiące / miesiące
r_black
2
@r_black Tak, masz rację. To była moja wina. Podane tutaj rozwiązanie jest poprawne i nie ma potrzeby dalszej kontroli przez pierwszy miesiąc roku.
mtoloo
45
from datetime import date, timedelta

first_day_of_current_month = date.today().replace(day=1)
last_day_of_previous_month = first_day_of_current_month - timedelta(days=1)

print "Previous month:", last_day_of_previous_month.month

Lub:

from datetime import date, timedelta

prev = date.today().replace(day=1) - timedelta(days=1)
print prev.month
Ivan
źródło
część rozwiązania ... aby znaleźć dzień z ostatniego miesiąca, dodaj coś takiego: day_previous_month = min (Today.day, last_day_of_previous_month.day), aby uniknąć przekroczenia liczby dni.
michel.iamit
9

Opierając się na odpowiedzi bgporter .

def prev_month_range(when = None): 
    """Return (previous month's start date, previous month's end date)."""
    if not when:
        # Default to today.
        when = datetime.datetime.today()
    # Find previous month: https://stackoverflow.com/a/9725093/564514
    # Find today.
    first = datetime.date(day=1, month=when.month, year=when.year)
    # Use that to find the first day of this month.
    prev_month_end = first - datetime.timedelta(days=1)
    prev_month_start = datetime.date(day=1, month= prev_month_end.month, year= prev_month_end.year)
    # Return previous month's start and end dates in YY-MM-DD format.
    return (prev_month_start.strftime('%Y-%m-%d'), prev_month_end.strftime('%Y-%m-%d'))
paragbaxi
źródło
5

Jest to bardzo łatwe i proste. Zrób to

from dateutil.relativedelta import relativedelta
from datetime import datetime

today_date = datetime.today()
print "todays date time: %s" %today_date

one_month_ago = today_date - relativedelta(months=1)
print "one month ago date time: %s" % one_month_ago
print "one month ago date: %s" % one_month_ago.date()

Oto wynik: $ python2.7 main.py

todays date time: 2016-09-06 02:13:01.937121
one month ago date time: 2016-08-06 02:13:01.937121
one month ago date: 2016-08-06
Mahfuz
źródło
4

Dla kogoś, kto tu dotarł i chce uzyskać zarówno pierwszy, jak i ostatni dzień poprzedniego miesiąca:

from datetime import date, timedelta

last_day_of_prev_month = date.today().replace(day=1) - timedelta(days=1)

start_day_of_prev_month = date.today().replace(day=1) - timedelta(days=last_day_of_prev_month.day)

# For printing results
print("First day of prev month:", start_day_of_prev_month)
print("Last day of prev month:", last_day_of_prev_month)

Wynik:

First day of prev month: 2019-02-01
Last day of prev month: 2019-02-28
Robin Carlo Catacutan
źródło
Jeśli chcesz poznać początek i koniec miesiąca (i więcej) zajrzyj do Calendarmodułu: stackabuse.com/introduction-to-the-python-calendar-module
toast38coza
Czy chcemy, aby drugi poprzedni miesiąc zaczynał się i kończył?
gracz
3
def prev_month(date=datetime.datetime.today()):
    if date.month == 1:
        return date.replace(month=12,year=date.year-1)
    else:
        try:
            return date.replace(month=date.month-1)
        except ValueError:
            return prev_month(date=date.replace(day=date.day-1))
steve
źródło
Przerwy 31 marca
Mike
1

Dla zabawy, czysta matematyka za pomocą divmod. Całkiem nieefektywny ze względu na mnożenie, mógłby równie dobrze sprawdzić liczbę miesięcy (jeśli jest równa 12, zwiększyć rok itp.)

year = today.year
month = today.month

nm = list(divmod(year * 12 + month + 1, 12))
if nm[1] == 0:
    nm[1] = 12
    nm[0] -= 1
pm = list(divmod(year * 12 + month - 1, 12))
if pm[1] == 0:
    pm[1] = 12
    pm[0] -= 1

next_month = nm
previous_month = pm
Tiberiu Ichim
źródło
1

W bardzo kompletnej bibliotece Pendulum mamy subtractmetodę (a nie „subStract”):

import pendulum
today = pendulum.datetime.today()  # 2020, january
lastmonth = today.subtract(months=1)
lastmonth.strftime('%Y%m')
# '201912'

Widzimy, że radzi sobie z latami skoków.

Odwrotny odpowiednik to add.

https://pendulum.eustace.io/docs/#addition-and-subtraction

Ehvince
źródło
0

Opierając się na komentarzu @JF Sebastian, możesz połączyć replace()funkcję, aby cofnąć się o jeden „miesiąc”. Ponieważ miesiąc nie jest stałym okresem czasu, rozwiązanie to stara się cofnąć do tej samej daty poprzedniego miesiąca, co oczywiście nie sprawdza się dla wszystkich miesięcy. W takim przypadku algorytm domyślnie przyjmuje ostatni dzień poprzedniego miesiąca.

from datetime import datetime, timedelta

d = datetime(2012, 3, 31) # A problem date as an example

# last day of last month
one_month_ago = (d.replace(day=1) - timedelta(days=1))
try:
    # try to go back to same day last month
    one_month_ago = one_month_ago.replace(day=d.day)
except ValueError:
    pass
print("one_month_ago: {0}".format(one_month_ago))

Wynik:

one_month_ago: 2012-02-29 00:00:00
Thane Plummer
źródło
0

Jeśli chcesz przyjrzeć się literom ASCII w pliku typu EXE w środowisku LINUX / UNIX, spróbuj "od -c 'nazwa_pliku' | więcej"

Prawdopodobnie otrzymasz wiele nierozpoznawalnych elementów, ale wszystkie zostaną zaprezentowane, a reprezentacje HEX zostaną wyświetlone, a znaki odpowiadające ASCII (jeśli są potrzebne) będą następować po linii kodów szesnastkowych. Wypróbuj go na skompilowanym fragmencie kodu, który znasz. Możesz zobaczyć w nim rzeczy, które rozpoznajesz.

Stóg
źródło
Czy możesz to zmienić, aby wyjaśnić, w jaki sposób odpowiada na pytanie.
AdrianHHH
0

Istnieje biblioteka wysokiego poziomu, dateparserktóra może określić datę przeszłą w języku naturalnym i zwrócić odpowiedni datetimeobiekt Pythona

from dateparser import parse
parse('4 months ago')
wesinat0r
źródło