0

I need to check if a given date is exactly a month ago from today, for example, if today is 01-Nov-2021 then exactly a month ago will be 01-Oct-2021 (not exactly 30 days.)

I wrote a code and it works fine

today = fields.Date.from_string(fields.Date.today())
if today.month == 1:
    one_month_ago = today.replace(year=today.year - 1, month=12)
else:
    extra_days = 0
    while True:
        try:
            one_month_ago = today.replace(month=today.month - 1, day=today.day - 
                      extra_days)
            break
        except ValueError:
            extra_days += 1
 


if one_month_ago == given_date:
    # do something
else:
    # do something

It handles well mostly all the cases but mishandles some cases. For example, the given date is 31-March-2021 and today date is 30-April-2021 and 31-April-2021 will not come to compare. I need my code to run daily and check something. It also mishandles cases of 29-31 January because 29-31 February will not come to compare.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Faizan Ahmad
  • 355
  • 3
  • 14
  • You’ll have to add some logic to handle all the months where the preceding month has fewer days, which will obviously depend on you deciding _how_ they should be handled. What do you want to happen for 29/30/31 march because there isn’t a 30/31 Feb and most years there isn’t a 29 Feb. – DisappointedByUnaccountableMod Nov 01 '21 at 07:26
  • 1
    What is "exactly a month ago"? On December 31st? On March 29th? On March 29th in a leap year? – Grismar Nov 01 '21 at 07:26
  • 1
    @Grismar exactly a month ago of December 31st will be 30 Nov, March 29th will be 28 Feb, and in a leap year, it will be Feb 29th. – Faizan Ahmad Nov 01 '21 at 07:30
  • @balmy that is exactly what I am trying to handle. I know all the missing dates that can happen and I don't want to handle every case individually, because I would still miss something. And even if one case is mishandled, this can cause problems. – Faizan Ahmad Nov 01 '21 at 07:34
  • 1
    So you have the logic, now add it to your code. Or are you hoping someone will write it for you? If so please note that StackOverflow is _not_ a code-writing service. You’re already handling January going back to previous year - keep writing similar tests and adjustments for the months you’ve got to tweak. – DisappointedByUnaccountableMod Nov 01 '21 at 07:35
  • Just making sure, whatever you use this for will be OK with the fact that 28 January, 29 January, 30 January and 31 January will all be "exactly one month ago" on 28 February 2022? Or will those dates never be exactly one month ago? – Grismar Nov 01 '21 at 07:36
  • @Grismar it will be one month ago, yes. – Faizan Ahmad Nov 01 '21 at 08:01
  • In that case, your question effectively is the exact same as this one https://stackoverflow.com/questions/2249956/how-to-get-the-same-day-of-next-month-of-a-given-day-in-python-using-datetime – Grismar Nov 01 '21 at 08:04
  • Does this answer your question? [how to get the same day of next month of a given day in python using datetime](https://stackoverflow.com/questions/2249956/how-to-get-the-same-day-of-next-month-of-a-given-day-in-python-using-datetime) – Grismar Nov 01 '21 at 08:04
  • No, it does not, it does not cover the cases like 29,30,31 January. – Faizan Ahmad Nov 01 '21 at 10:34

3 Answers3

1

From the given date, you can find the previous month and year and using these two obtained values, find the length of the previous month. The last thing to be done will be to compare the day of the given date with the length of the previous month and accordingly, return the desired date.

Demo:

from datetime import date
from calendar import monthrange


def date_a_month_ago(today):
    x = today.month - 1
    previous_month = 12 if x == 0 else x
    year = today.year - 1 if x == 0 else today.year
    last_day_of_previous_month = monthrange(year, previous_month)[1]
    day = last_day_of_previous_month if today.day > last_day_of_previous_month else today.day
    return date(year, previous_month, day)


# Tests
print(date_a_month_ago(date(2021, 11, 1)))
print(date_a_month_ago(date(2021, 1, 31)))
print(date_a_month_ago(date(2021, 12, 31)))
print(date_a_month_ago(date(2021, 3, 29)))
print(date_a_month_ago(date(2020, 3, 29)))
print(date_a_month_ago(date(2021, 3, 30)))
print(date_a_month_ago(date(2020, 3, 30)))

Output:

2021-10-01
2020-12-31
2021-11-30
2021-02-28
2020-02-29
2021-02-28
2020-02-29

ONLINE DEMO

Spectric
  • 30,714
  • 6
  • 20
  • 43
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
0

May be like this:

from typing import Tuple

def last_month(year: int, month: int) -> Tuple[int, int]:
    y, m = year, month - 1
    if m == 0:
        y, m = y - 1, 12
    return y, m

def one_month_ago(today: datetime) -> datetime:
    y, m = last_month(today.year, today.month)
    dt = today.replace(year=y, month=m)
    for day in range(today.day, 0, -1):
        try:
            return dt.replace(day=day)
        except ValueError:
            ...
Waket Zheng
  • 5,065
  • 2
  • 17
  • 30
0

I did this and it's giving me the required output:

from datetime import date
from calendar import monthrange


def is_one_month(given_date, today):
    x = today.month - 1
    previous_month = 12 if x == 0 else x
    year = today.year - 1 if x == 0 else today.year
    last_day_of_previous_month = monthrange(year, previous_month)[1]
    day = last_day_of_previous_month if today.day > last_day_of_previous_month else today.day
    one_month_ago = date(year, previous_month, day)
    if today.month == 2:
        if given_date.month == today.month-1 and given_date.year == today.year and given_date.day >= 28:
            return 'it is one month before'
    if today.month == 4 or today.month == 6 or today.month == 9 or today.month == 11:
        if given_date.month == today.month-1 and given_date.day == 31:
            return 'it is one month before'
    if one_month_ago == given_date:
        return 'it is one month before'
    else:
        return 'it is NOT one month before'

print(is_one_month(date(2021, 1, 30), date(2021, 2, 28)))

Output:

it is one month before
ouflak
  • 2,458
  • 10
  • 44
  • 49
Faizan Ahmad
  • 355
  • 3
  • 14