Get fourth to the last month? - python

I'm trying to find out fourth to the last month with a snippet.
Considering, september, fourth to the last month would be june.
I tried to get the required month and year like this
from datetime import date, datetime, timedelta
current_date = datetime.now()
last_4th_month = current_date.month - 3
year = current_date.year
if current_date.month == 3:
last_4th_month = 12
year = current_date.year - 1
if current_date.month == 2:
last_4th_month = 11
year = current_date.year - 1
if current_date.month == 1:
last_4th_month = 10
year = current_date.year - 1
print(last_4th_month, year)
Is there any efficient and better way to do this?
TYPO IN THE QUESTION:
Get fourth to the last month in python

Try this:
from datetime import date
from dateutil.relativedelta import relativedelta
four_months = date.today() + relativedelta(months=-3)
print(four_months.strftime("%B, %Y"))
Output: June, 2021

If 3rd party libraries can be used, dateutil's relativedelta module offers a simple solution:
from datetime import datetime
from dateutil.relativedelta import relativedelta
current_date = datetime.now()
target_date = current_date - relativedelta(months=3)
print(target_date.month, target_date.year)
Outputs 6 2021

You can compute the last_4th_month with the standard library:
from datetime import date
today = date.today()
month = today.month - 3 if today.month - 3 > 0 else 12 - today.month
year = today.year if today.month > month else today.year - 1
last_4th_month = date(year, month, today.day)
# today = date(2021, 9, 6)
>>> last_4th_month.strftime('%B, %Y')
'June, 2021'
# today = date(2021, 2, 18)
>>> last_4th_month.strftime('%B, %Y')
'October, 2020'

Related

How to check it's between Sunday 5:30PM and Friday 5:30PM?

How do I check if the current time is between Sunday 5:30 PM and Friday 5:30 PM?
I can find the day and time ranges separately but I think the time has to be combined with the day.
import datetime
import time
now = datetime.datetime.now()
if 0 <= now.weekday() <= 4:
print ("It's a weekday!")
if time(17, 30) <= now.time() <= time(17, 30):
print "and it's in range"
You can check the following 3 conditions:
The day is not Saturday
Either the day is not Friday, or the time is before 17:30
Either the day is not Sunday, or the time is after 17:30
In code, this is equivalent to:
from datetime import datetime, time
now = datetime.now()
if (now.weekday != 5
and (now.weekday != 4 or now.time() <= time(17, 30))
and (now.weekday != 6 or now.time() >= time(17, 30))):
print("In range!")
You can simply get the datetime of the most recent Sunday at 5:30pm, and then check if it's within exactly 5 days:
import datetime
now = datetime.datetime.now()
last_sunday = next((now - i * datetime.timedelta(days=1)) for i in range(7) if (now - i * datetime.timedelta(days=1)).weekday() == 6)
last_sunday_at_530 = datetime.datetime(year=last_sunday.year, month=last_sunday.month, day=last_sunday.day, hour=17, minute=30)
if (now - last_sunday_at_530) < datetime.timedelta(days=5):
print("now is between Sunday at 5:30pm and Friday at 5:30pm")
else:
print("Now is after 5:30pm on Friday but before Sunday at 5:30pm
If you want to check the reverse (after Friday but before Sunday) then you can simply start at last_friday and count forwards by only two days.
Which time of day is within the range depends on the day:
On Sunday, times after 5:30 PM are in.
From Monday to Thursday, the time does not matter.
On Friday, times before 5:30 are in.
This leads to the following code:
import datetime
now = datetime.datetime.now()
d = now.weekday()
t = now.time()
if (
d == 6 and t >= datetime.time(17, 30) # Sunday
or 0 <= d <= 3 # Monday–Thursday
or d == 4 and t <= datetime.time(17, 30) # Friday
):
print("In range")

Return number of weekdays for a specific date (Python)

I need to calculate a price based on a given date weekdays a month.
This is what im currently working with:
month = time.month
year = time.year
weekdays = 0
cal = calendar.Calendar()
for day in cal.itermonthdates(year, month):
if day.weekday() == 6 and day.month == month:
weekdays += 1
But this does not rely on a given date.
I want this to return 6 for the date 10.01.2020, or 6 for 03.01.2020 or 4 for 06.01.2020.
Any help would be very nice.
Following can be a dry approach:
import datetime
# ...
prev_day = time.day - datetime.timedelta(days=1)
month = time.month
year = time.year
cal = calendar.Calendar()
days_iterator = cal.itermonthdates(year, month)
while next(days_iterator) != prev_day:
pass
weekdays = 0
for d in days_iterator:
if d.weekday() == 6 and d.month == month:
weekdays += 1
Try this:
import datetime
d=datetime.date(2020, 1, 10) #Format YYYY, MM, DD
print(d.isoweekday())
Now this will print 5 not 6 as it is a Friday and the counting starts at Monday (using isoweekday instead of weekday will let the counting start by 1 instead of 0) but there should be an easy fix if you want your week begin on Sunday just add 1 and calculate modulo 7:
print((d.isoweekday()+1)%7)
https://docs.python.org/3/library/datetime.html

Week ending date with Sunday being the first day of the week

I am trying to get the week ending date for a list of dates. I found the below code and it works for a traditional Monday thru Sunday week but I need a Sunday thru Saturday week (Sunday being the first day of the week).
from datetime import datetime, timedelta
date_str = '2019-06-16'
date_obj = datetime.strptime(date_str, '%Y-%m-%d')
start_of_week = date_obj - timedelta(days=date_obj.weekday())
end_of_week = start_of_week + timedelta(days=6)
print(start_of_week)
print(end_of_week)
The above code returns:
2019-06-10 00:00:00
2019-06-16 00:00:00
and I need it to return this:
2019-06-16 00:00:00
2019-06-22 00:00:00
So weekday returns 0 for Monday and 6 for Sunday. To change that to 0 for Sunday and 6 for Saturday do
start_of_week = date_obj - timedelta((date_obj.weekday() + 1) % 7)
I think in python, Sunday is the start day of a week, LOL. Code below may help you.
from datetime import datetime, timedelta
# this may be the func you need.
def date_start_end(date):
"""
calc the start and end date for input date. Sunday is the start day for a week.
:param date: any date
:return: st: the start date(Sunday) for this week
:return: end: the end date(Saturday) for this week
"""
weekDate = int(date.strftime('%w'))
st = date + timedelta(-weekDate)
end = date + timedelta(6 - weekDate)
return st, end
date = datetime(2019, 6, 16)
st, end = date_start_end(date)
print(st)
print(end)
>>>2019-06-16 00:00:00
>>>2019-06-22 00:00:00
Adding in my two cents. Datetime also has an isoweekday method that has Monday at 1 and Sunday at 7. Similar to #Deepstop's answer but a bit shorter:
start_of_week = date_sample - timedelta(days=date_sample.isoweekday()%7)

Finding the date of the next Saturday

How would one go about finding the date of the next Saturday in Python? Preferably using datetime and in the format '2013-05-25'?
>>> from datetime import datetime, timedelta
>>> d = datetime.strptime('2013-05-27', '%Y-%m-%d') # Monday
>>> t = timedelta((12 - d.weekday()) % 7)
>>> d + t
datetime.datetime(2013, 6, 1, 0, 0)
>>> (d + t).strftime('%Y-%m-%d')
'2013-06-01'
I use (12 - d.weekday()) % 7 to compute the delta in days between given day and next Saturday because weekday is between 0 (Monday) and 6 (Sunday), so Saturday is 5. But:
5 and 12 are the same modulo 7 (yes, we have 7 days in a week :-) )
so 12 - d.weekday() is between 6 and 12 where 5 - d.weekday() would be between 5 and -1
so this allows me not to handle the negative case (-1 for Sunday).
Here is a very simple version (no check) for any weekday:
>>> def get_next_weekday(startdate, weekday):
"""
#startdate: given date, in format '2013-05-25'
#weekday: week day as a integer, between 0 (Monday) to 6 (Sunday)
"""
d = datetime.strptime(startdate, '%Y-%m-%d')
t = timedelta((7 + weekday - d.weekday()) % 7)
return (d + t).strftime('%Y-%m-%d')
>>> get_next_weekday('2013-05-27', 5) # 5 = Saturday
'2013-06-01'
I found this pendulum pretty useful. Just one line
In [4]: pendulum.now().next(pendulum.SATURDAY).strftime('%Y-%m-%d')
Out[4]: '2019-04-27'
See below for more details:
In [1]: import pendulum
In [2]: pendulum.now()
Out[2]: DateTime(2019, 4, 24, 17, 28, 13, 776007, tzinfo=Timezone('America/Los_Angeles'))
In [3]: pendulum.now().next(pendulum.SATURDAY)
Out[3]: DateTime(2019, 4, 27, 0, 0, 0, tzinfo=Timezone('America/Los_Angeles'))
In [4]: pendulum.now().next(pendulum.SATURDAY).strftime('%Y-%m-%d')
Out[4]: '2019-04-27'
You need two main packages,
import datetime
import calendar
Once you have those, you can simply get the desired date for the week by the following code,
today = datetime.date.today() #reference point.
saturday = today + datetime.timedelta((calendar.SATURDAY-today.weekday()) % 7 )
saturday
Bonus
Following the content, if you type
saturday.weekday()
It will result 5.
Therefore, you can also use 5 in place of calendar.SATURDAY and you will get same result.
saturday = today + datetime.timedelta((5-today.weekday()) % 7 )
if you just want the date from today (inspired from Emanuelle )
def get_next_weekday(weekday_number):
"""
#weekday: week day as a integer, between 0 (Monday) to 6 (Sunday)
"""
assert 0 <= weekday_number <= 6
today_date = datetime.today()
next_week_day = timedelta((7 + weekday_number - today_date.weekday()) % 7)
return (today_date + next_week_day).strftime('%d/%m/%Y')
Again, based on Emmanuel's example, but making 0-6 conform to your week:
ScheduleShift = -1 # make Saturday end of week
EndofWeekDay = lambda do : do + datetime.timedelta( ( ScheduleShift + (13 - do.weekday() ) %7 ) )
Which can be called with:
EndofWeekDay( datetime.date.today() )
returning a datetime.date object
Just wanted to share a code. With this, you will get a list of dates when Saturday days will be in the next 10 days.
from datetime import datetime, timedelta
target_day = 'Saturday'
now_ = datetime.today().date()
how_many_days = 10
next_date = [now_ + timedelta(days=x) for x in range(how_many_days) if (now_ + timedelta(days=x)).strftime("%A") == target_day]
print(next_date)

Find the date for the first Monday after a given date

Given a particular date, say 2011-07-02, how can I find the date of the next Monday (or any weekday day for that matter) after that date?
import datetime
def next_weekday(d, weekday):
days_ahead = weekday - d.weekday()
if days_ahead <= 0: # Target day already happened this week
days_ahead += 7
return d + datetime.timedelta(days_ahead)
d = datetime.date(2011, 7, 2)
next_monday = next_weekday(d, 0) # 0 = Monday, 1=Tuesday, 2=Wednesday...
print(next_monday)
Here's a succinct and generic alternative to the slightly weighty answers above.
def onDay(date, day):
"""
Returns the date of the next given weekday after
the given date. For example, the date of next Monday.
NB: if it IS the day we're looking for, this returns 0.
consider then doing onDay(foo, day + 1).
"""
days = (day - date.weekday() + 7) % 7
return date + datetime.timedelta(days=days)
Try
>>> dt = datetime(2011, 7, 2)
>>> dt + timedelta(days=(7 - dt.weekday()))
datetime.datetime(2011, 7, 4, 0, 0)
using, that the next monday is 7 days after the a monday, 6 days after a tuesday, and so on, and also using, that Python's datetime type reports monday as 0, ..., sunday as 6.
This is example of calculations within ring mod 7.
import datetime
def next_day(given_date, weekday):
day_shift = (weekday - given_date.weekday()) % 7
return given_date + datetime.timedelta(days=day_shift)
now = datetime.date(2018, 4, 15) # sunday
names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday',
'saturday', 'sunday']
for weekday in range(7):
print(names[weekday], next_day(now, weekday))
will print:
monday 2018-04-16
tuesday 2018-04-17
wednesday 2018-04-18
thursday 2018-04-19
friday 2018-04-20
saturday 2018-04-21
sunday 2018-04-15
As you see it's correctly give you next monday, tuesday, wednesday, thursday friday and saturday. And it also understood that 2018-04-15 is a sunday and returned current sunday instead of next one.
I'm sure you'll find this answer extremely helpful after 7 years ;-)
Another alternative uses rrule
from dateutil.rrule import rrule, WEEKLY, MO
from datetime import date
next_monday = rrule(freq=WEEKLY, dtstart=date.today(), byweekday=MO, count=1)[0]
rrule docs: https://dateutil.readthedocs.io/en/stable/rrule.html
Another simple elegant solution is to use pandas offsets.
I find it very helpful and robust when playing with dates.
If you want the first Sunday just modify the frequency to freq='W-SUN'.
If you want a couple of next Sundays, change the offsets.Day(days).
Using pandas offsets allow you to ignore holidays, work only with Business Days and more.
You can also apply this method easily on a whole DataFrame using the apply method.
import pandas as pd
import datetime
# 1. Getting the closest monday from a given date
date = datetime.date(2011, 7, 2)
closest_monday = pd.date_range(start=date, end=date + pd.offsets.Day(6), freq="W-MON")[
0
]
# 2. Adding a 'ClosestMonday' column with the closest monday for each row in
# a pandas df using apply. Requires you to have a 'Date' column in your df
def get_closest_monday(row):
return pd.date_range(
start=row.Date, end=row.Date + pd.offsets.Day(6), freq="W-MON"
)[0]
df = pd.DataFrame([datetime.date(2011, 7, 2)], columns=["Date"])
df["ClosestMonday"] = df.apply(lambda row: get_closest_monday(row), axis=1)
print(df)
You can start adding one day to date object and stop when it's monday.
>>> d = datetime.date(2011, 7, 2)
>>> while d.weekday() != 0: #0 for monday
... d += datetime.timedelta(days=1)
...
>>> d
datetime.date(2011, 7, 4)
import datetime
d = datetime.date(2011, 7, 2)
while d.weekday() != 0:
d += datetime.timedelta(1)
dateutil has a special feature for this kind of operation and it's the most elegant way I have ever seen yet.
from datetime import datetime
from dateutil.relativedelta import relativedelta, MO
first_monday_date = (datetime(2011,7,2) + relativedelta(weekday=MO(0))).date()
if you want datetime just
first_monday_date = datetime(2011,7,2) + relativedelta(weekday=MO(0))
weekday = 0 ## Monday
dt = datetime.datetime.now().replace(hour=0, minute=0, second=0) ## or any specific date
days_remaining = (weekday - dt.weekday() - 1) % 7 + 1
next_dt = dt + datetime.timedelta(days_remaining)
Generally to find any date from day of week from today:
def getDateFromDayOfWeek(dayOfWeek):
week_days = ["monday", "tuesday", "wednesday",
"thursday", "friday", "saturday", "sunday"]
today = datetime.datetime.today().weekday()
requiredDay = week_days.index(dayOfWeek)
if today>requiredDay:
noOfDays=7-(today-requiredDay)
print("noDays",noOfDays)
else:
noOfDays = requiredDay-today
print("noDays",noOfDays)
requiredDate = datetime.datetime.today()+datetime.timedelta(days=noOfDays)
return requiredDate
print(getDateFromDayOfWeek('sunday').strftime("%d/%m/%y"))
Gives output in format of Day/Month/Year
This will give the first next Monday after given date:
import datetime
def get_next_monday(year, month, day):
date0 = datetime.date(year, month, day)
next_monday = date0 + datetime.timedelta(7 - date0.weekday() or 7)
return next_monday
print get_next_monday(2011, 7, 2)
print get_next_monday(2015, 8, 31)
print get_next_monday(2015, 9, 1)
2011-07-04
2015-09-07
2015-09-07
via list comprehension?
from datetime import *
[datetime.today()+timedelta(days=x) for x in range(0,7) if (datetime.today()+timedelta(days=x)).weekday() % 7 == 0]
(0 at the end is for next monday, returns current date when run on monday)

Categories