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!


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.


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

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

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'))

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

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

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

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


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

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.


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')
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.