ngày trăn của tháng trước


131

Tôi đang cố gắng để có được ngày của tháng trước với python. Đây là những gì tôi đã thử:

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

Tuy nhiên, cách này rất tệ vì 2 lý do: Đầu tiên, nó trả về 20122 cho tháng 2 năm 2012 (thay vì 201202) và thứ hai là nó sẽ trả về 0 thay vì 12 vào tháng 1.

Tôi đã giải quyết rắc rối này trong bash với

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

Tôi nghĩ rằng nếu bash có một cách tích hợp cho mục đích này, thì python, được trang bị nhiều hơn, sẽ cung cấp một cái gì đó tốt hơn là buộc viết kịch bản của chính mình để đạt được mục tiêu này. Tất nhiên tôi có thể làm một cái gì đó như:

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)

Tôi chưa kiểm tra mã này và tôi không muốn sử dụng mã này (trừ khi tôi không thể tìm thấy bất kỳ cách nào khác: /)

Cảm ơn bạn đã giúp đỡ!


Câu trả lời:


299

datetime và các lớp datetime.timedelta là bạn của bạn.

  1. tìm ngày hôm nay
  2. sử dụng để tìm ngày đầu tiên của tháng này
  3. sử dụng timedelta để sao lưu một ngày, đến ngày cuối cùng của tháng trước.
  4. in chuỗi YYYYMM bạn đang tìm kiếm.

Như thế này:

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

201202 được in.


31
bạn có thể sử dụng .replace()phương pháp:datetime.utcnow().replace(day=1) - timedelta(days=1)
jfs

1
Mát mẻ! Tôi đã bỏ lỡ phương pháp thay thế.
bgporter

Bạn cũng có thể chuỗi .replace()chức năng. Làm một lần để có được tháng cuối cùng, sau đó làm lại để có được ngày bạn muốn. Đầu tiên: d = date.today() sau đóone_month_ago = (d.replace(day=1) - timedelta(days=1)).replace(day=d.day)
Thane Plummer

@JFSebastian Bạn đúng - cảm ơn vì đã chỉ ra điều đó. Dường như không có một lớp lót thanh lịch nào cho điều này vì "tháng" không phải là khoảng thời gian không đổi. Bạn có thể làm điều gì đó xấu xí bằng cách nhập calendarvà sử dụng calendar.mdays[d.month-1]và xấu hơn trong một min()chức năng trong phần 2 replace, nhưng có vẻ như không phải là Pythonic và không tính đến các trường hợp góc. Tôi đã cập nhật câu trả lời của mình bên dưới bằng cách sử dụng try - excepttài khoản nào cho tất cả các trường hợp, mặc dù tôi ghét sử dụng ngoại lệ như một phần của thuật toán.
Thane Plummer

xem câu trả lời của Ivan và thêm: min (date.today (). day, last_day_of_preingly_month.day)
michel.iamit

70

Bạn nên sử dụng dateutil . Cùng với đó, bạn có thể sử dụng relativingelta, đây là phiên bản cải tiến của 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

Nó không hoạt động trong tháng đầu tiên của năm: >>> IllegalMonthError: số tháng xấu -1; phải là 1-12
mtoloo

@mtoloo Phiên bản nào của dateutil? Tôi không gặp phải vấn đề đó, nhưng tôi sẽ thêm một số cú pháp thay thế
Dave Butler

1
Tôi thích cái này vì trong khi @bgporter có một giải pháp rất hay, thì cái của anh ta không hoạt động tốt như vậy để tìm kiếm vào tháng tới.
Daniel F

3
@mtoloo Bạn có thể đã nhầm lẫn tháng / tháng
r_black

2
@r_black Có Bạn đúng. Đó là lỗi của tôi. Giải pháp đưa ra ở đây là chính xác và không cần kiểm tra thêm cho tháng đầu tiên của năm.
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

Hoặc là:

from datetime import date, timedelta

prev = date.today().replace(day=1) - timedelta(days=1)
print prev.month

một phần của giải pháp ... để tìm ngày của tháng trước, hãy thêm một cái gì đó như thế này: day_preingly_month = min (today.day, last_day_of_preingly_month.day) để tránh vượt quá số ngày.
michel.iamit

9

Xây dựng trên câu trả lời của 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

Nó rất dễ dàng và đơn giản. Làm cái này

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

Đây là đầu ra: $ 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

Đối với một người đã đến đây và mong muốn có được cả ngày đầu tiên và ngày cuối cùng của tháng trước:

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)

Đầu ra:

First day of prev month: 2019-02-01
Last day of prev month: 2019-02-28

Nếu bạn muốn bắt đầu và kết thúc một tháng (và hơn thế nữa), hãy xem Calendarmô-đun: stackabuse.com/int sinhtion
calWiki

Nếu chúng ta muốn 2 tháng trước bắt đầu và kết thúc?
game thủ

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

Nghỉ vào ngày 31 tháng 3
Mike

1

Chỉ để cho vui, một câu trả lời toán học thuần túy sử dụng divmod. Khá vô tư vì nhân, có thể làm một kiểm tra đơn giản về số tháng (nếu bằng 12, tăng năm, v.v.)

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

1

Với thư viện Pendulum rất hoàn chỉnh, chúng tôi có subtractphương thức (chứ không phải "subStract"):

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

Chúng tôi thấy rằng nó xử lý năm nhảy.

Tương đương ngược lại là add.

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


0

Dựa trên nhận xét của @JF Sebastian, bạn có thể xâu chuỗi replace()chức năng để quay lại một "tháng". Vì một tháng không phải là khoảng thời gian không đổi, giải pháp này cố gắng quay trở lại cùng ngày tháng trước, tất nhiên không hoạt động trong tất cả các tháng. Trong trường hợp như vậy, thuật toán này mặc định đến ngày cuối cùng của tháng trước.

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

Đầu ra:

one_month_ago: 2012-02-29 00:00:00

0

Nếu bạn muốn xem các chữ cái ASCII trong tệp loại EXE trong Môi trường LINUX / UNIX, hãy thử "od -c 'tên tệp' | more"

Bạn có thể sẽ nhận được rất nhiều mục không thể nhận ra, nhưng tất cả chúng sẽ được trình bày và các biểu diễn HEX sẽ được hiển thị và các ký tự tương đương ASCII (nếu phù hợp) sẽ tuân theo dòng mã hex. Hãy thử nó trên một đoạn mã được biên dịch mà bạn biết. Bạn có thể thấy những thứ trong đó bạn nhận ra.


Bạn có thể vui lòng chỉnh sửa điều này để giải thích làm thế nào nó trả lời câu hỏi.
AdrianHHH

0

Có một thư viện cấp cao dateparser có thể xác định ngày đã qua của ngôn ngữ tự nhiên và trả về datetimeđối tượng Python tương ứng

from dateparser import parse
parse('4 months ago')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.