Week Number for Actual Calendar Python - python

Can someone tell me how to get a week number in Python for actual calendar.
Ex: 2016-01-01 to 2016-01-07 = week 1
2016-01-08 to 2016-01-14 = week 2
I tried 2 ways but none of them are working
Using isocalendar()
But that does not work for year end and year start week. For ex:
datetime.date(2016,01,01).isocalendar()[1]
# should be: 1
# got 53
is the following:
dt = date(2016,01,02)
d = strftime("%U", time.strptime(str(dt),"%Y-%m-%d"))
print d
# 00
dt = date(2016,01,03)
d = strftime("%U", time.strptime(str(dt),"%Y-%m-%d"))
print d
# 01
Both the ways do not satisfy my requirement. Is there any other library I can use to get the week number in Actual Calendar ?

Are you talking about actual number of 7 day periods rather than which week number you're in? Keep in mind in 2016, Jan 3rd is the first day of the second week.
If you're looking at which 7 day period, you should simply count days since the beginning of the year and floor div by 7
dt = datetime.datetime(year=2016, month=1, day=2)
days = dt - datetime.datetime(year=dt.year, month=1, day=1).days
weeks = days // 7 + 1
The 29th should be the first day of week 5. Let's try it.
dt = datetime.datetime(year=2016, month=1, day=29)
days = dt - datetime.datetime(year=dt.year, month=1, day=1).days
weeks = days // 7 + 1
# 5

Related

First weekday of the year (without weekends)

Can anyone help me get the first weekday (as a date) of a given year in Python?
This gives me the first Monday of the current week:
test = datetime.today() - timedelta(days=datetime.today().isoweekday() % 7)
print(test)
This is easy once you break it down:
Let's define a function that takes an input yr and returns the first weekday of that year.
def first_weekday(yr: int) -> datetime.date:
What is the first day of the year yr?
first_day = datetime.date(yr, 1, 1)
Is that day a weekday? If so, it is the first weekday of the year.
day_of_week = first_day.isoweekday()
if day_of_week < 6: return first_day
datetime.date.isoweekday() returns 1 for Monday and 7 for Sunday.
Why did I use isoweekday instead of weekday? No reason
If not, find how many days until Monday. Subtracting the day_of_week from 8 should do the trick!
We would subtract from 7 for weekday().
days_to_monday = 8 - day_of_week
first_weekday = first_day + datetime.timedelta(days=days_to_monday)
return first_weekday
Put this all together, and test:
for yr in range(2019, 2025):
print(yr, first_weekday(yr))
prints:
2019 2019-01-01
2020 2020-01-01
2021 2021-01-01
2022 2022-01-03
2023 2023-01-02
2024 2024-01-01

Get last friday of each month in python

I want last friday of each month for upcoming three months.
Friday_date = datetime.date.today()
while Friday_date.weekday() != 4:
Friday_date += datetime.timedelta(1)
This gives me the nearest friday. I want to make sure this is the last friday of this month so that i can add 28 days to get next friday.
The easiest way to do this is to use the module dateutil:
>>> from dateutil.relativedelta import FR, relativedelta
>>> datetime.date.today()+relativedelta(day=31, weekday=FR(-1))
datetime.date(2021, 6, 25)
Don't assume you can get the last Friday of subsequent months just by adding 28 days. It won't always work. Adding 28 days to the last Friday of February 2024 gives you this:
>>> datetime.date(2024,2,1)+relativedelta(day=31, weekday=FR(-1), days=28)
datetime.date(2024, 3, 22)
but the last Friday of that month is 29 March. Let dateutil do that correctly for you:
>>> datetime.date(2024,2,1)+relativedelta(day=31, weekday=FR(-1), months=1)
datetime.date(2024, 3, 29)
If needed with standard library only, here is with calendar and datetime:
import calendar
from datetime import date
today = date.today()
year, month = today.year, today.month
n_months = 4
friday = calendar.FRIDAY
for _ in range(n_months):
# get last friday
c = calendar.monthcalendar(year, month)
day_number = c[-1][friday] or c[-2][friday]
# display the found date
print(date(year, month, day_number))
# refine year and month
if month < 12:
month += 1
else:
month = 1
year += 1
where the line c[-1][friday] or c[-2][friday] first checks the last week of the month: is Friday nonzero there? if so take it, else look at the week before where there must be a Friday.
This prints
2021-06-25
2021-07-30
2021-08-27
2021-09-24
This formula gets you the day of the last Friday of any given month:
import calendar
year = 2021
month = 6
last_day = calendar.monthrange(year, month)[1]
last_weekday = calendar.weekday(year, month, last_day)
last_friday = last_day - ((7 - (4 - last_weekday)) % 7)
# ^ ^
# | Friday
# days in a week
This is my first coffee, so this can probably be condensed a bit, but it illustrates the logic. last_day is the last calendar day (30 for June), last_weekday is what weekday it is (2 for Wednesday), and based on that we simply calculate how many days to subtract to land on the last Friday (25).
If you want to know the last friday you can do this :
from datetime import date
from datetime import timedelta
today = date.today()
offset = (today.weekday() - 4) % 7
last_wednesday = today - timedelta(days=offset)

How to set a get the date of the day of the week?

Basically what i want is to have the day of the week's date after saying next week or similar format and i though i found what i need in here:
Find the date for the first Monday after a given a date
However testing the code proved it's giving somewhat answers i'd want differently :
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(2017, 11, 30)
next_monday = next_weekday(d, 0) # 0 = Monday, 1=Tuesday, 2=Wednesday...
print(next_monday)
It worked as expected to give the date correctly for next_weekday(d,0), 1,2,3 then for next_weekday(d,4) i get 2017-12-01 which my system interprets as faulty because this friday equate 2017-12-01 while next friday equates 2017-12-08 same for saturday and Sunday, so basically what i want if the day of the week we're seeking is still in the same week to give the date of that day for the week after.
Could you not just always add 7 to days_ahead rather than only when the
"Target day has already happend this week" to get a day in next week every time:
import datetime
def next_weekday(d, weekday):
days_ahead = weekday - d.weekday() + 7
return d + datetime.timedelta(days_ahead)
d = datetime.date(2017, 11, 30)
next_friday = next_weekday(d, 4)
print(next_friday) # 2017-12-08 which is next week rather than the friday this week: 2017-12-01

Is there a simple way to increment a datetime object one month in Python? [duplicate]

This question already has answers here:
How do I calculate the date six months from the current date using the datetime Python module?
(47 answers)
Closed 7 years ago.
So I am trying to find a way to increment a datetime object by one month. However, it seems this is not so simple, according to this question.
I was hoping for something like:
import datetime as dt
now = dt.datetime.now()
later = now + dt.timedelta(months=1)
But that doesn't work. I was also hoping to be able to go to the same day (or the closest alternative) in the next month if possible. For example, a datetime object set at January 1st would increment to Feb 1st whereas a datetime object set at February 28th would increment to March 31st as opposed to March 28th or something.
To be clear, February 28th would (typically) map to March 31st because it is the last day of the month, and thus it should go to the last day of the month for the next month. Otherwise it would be a direct link: the increment should go to the day in the next month with the same numbered day.
Is there a simple way to do this in the current release of Python?
Check out from dateutil.relativedelta import *
for adding a specific amount of time to a date, you can continue to use timedelta for the simple stuff i.e.
import datetime
from dateutil.relativedelta import *
use_date = datetime.datetime.now()
use_date = use_date + datetime.timedelta(minutes=+10)
use_date = use_date + datetime.timedelta(hours=+1)
use_date = use_date + datetime.timedelta(days=+1)
use_date = use_date + datetime.timedelta(weeks=+1)
or you can start using relativedelta
use_date = use_date+relativedelta(months=+1)
use_date = use_date+relativedelta(years=+1)
for the last day of next month:
use_date = use_date+relativedelta(months=+1)
use_date = use_date+relativedelta(day=31)
Right now this will provide 29/02/2016
for the penultimate day of next month:
use_date = use_date+relativedelta(months=+1)
use_date = use_date+relativedelta(day=31)
use_date = use_date+relativedelta(days=-1)
last Friday of the next month:
use_date = use_date+relativedelta(months=+1, day=31, weekday=FR(-1))
2nd Tuesday of next month:
new_date = use_date+relativedelta(months=+1, day=1, weekday=TU(2))
As #mrroot5 points out dateutil's rrule functions can be applied, giving you an extra bang for your buck, if you require date occurences.
for example:
Calculating the last day of the month for 9 months from the last day of last month.
Then, calculate the 2nd Tuesday for each of those months.
from dateutil.relativedelta import *
from dateutil.rrule import *
from datetime import datetime
use_date = datetime(2020,11,21)
#Calculate the last day of last month
use_date = use_date+relativedelta(months=-1)
use_date = use_date+relativedelta(day=31)
#Generate a list of the last day for 9 months from the calculated date
x = list(rrule(freq=MONTHLY, count=9, dtstart=use_date, bymonthday=(-1,)))
print("Last day")
for ld in x:
print(ld)
#Generate a list of the 2nd Tuesday in each of the next 9 months from the calculated date
print("\n2nd Tuesday")
x = list(rrule(freq=MONTHLY, count=9, dtstart=use_date, byweekday=TU(2)))
for tuesday in x:
print(tuesday)
Last day
2020-10-31 00:00:00
2020-11-30 00:00:00
2020-12-31 00:00:00
2021-01-31 00:00:00
2021-02-28 00:00:00
2021-03-31 00:00:00
2021-04-30 00:00:00
2021-05-31 00:00:00
2021-06-30 00:00:00
2nd Tuesday
2020-11-10 00:00:00
2020-12-08 00:00:00
2021-01-12 00:00:00
2021-02-09 00:00:00
2021-03-09 00:00:00
2021-04-13 00:00:00
2021-05-11 00:00:00
2021-06-08 00:00:00
2021-07-13 00:00:00
rrule could be used to find the next date occurring on a particular day.
e.g. the next 1st of January occurring on a Monday (Given today is the 4th November 2021)
from dateutil.relativedelta import *
from dateutil.rrule import *
from datetime import *
year = rrule(YEARLY,dtstart=datetime.now(),bymonth=1,bymonthday=1,byweekday=MO)[0].year
year
2024
or the next 5 x 1st of January's occurring on a Monday
years = rrule(YEARLY,dtstart=datetime.now(),bymonth=1,bymonthday=1,byweekday=MO)[0:5]
for i in years:print(i.year)
...
2024
2029
2035
2046
2052
The first Month next Year that starts on a Monday:
>>> month = rrule(YEARLY,dtstart=datetime.date(2023, 1, 1),bymonthday=1,byweekday=MO)[0]
>>> month.strftime('%Y-%m-%d : %B')
'2023-05-01 : May'
If you need the months that start on a Monday between 2 dates:
months = rrule(YEARLY,dtstart=datetime.date(2025, 1, 1),until=datetime.date(2030, 1, 1),bymonthday=1,byweekday=MO)
>>> for m in months:
... print(m.strftime('%Y-%m-%d : %B'))
...
2025-09-01 : September
2025-12-01 : December
2026-06-01 : June
2027-02-01 : February
2027-03-01 : March
2027-11-01 : November
2028-05-01 : May
2029-01-01 : January
2029-10-01 : October
This is by no means an exhaustive list of what is available.
Documentation is available here: https://dateutil.readthedocs.org/en/latest/
Note: This answer shows how to achieve this using only the datetime and calendar standard library (stdlib) modules - which is what was explicitly asked for. The accepted answer shows how to better achieve this with one of the many dedicated non-stdlib libraries. If you can use non-stdlib libraries, by all means do so for these kinds of date/time manipulations!
How about this?
def add_one_month(orig_date):
# advance year and month by one month
new_year = orig_date.year
new_month = orig_date.month + 1
# note: in datetime.date, months go from 1 to 12
if new_month > 12:
new_year += 1
new_month -= 12
new_day = orig_date.day
# while day is out of range for month, reduce by one
while True:
try:
new_date = datetime.date(new_year, new_month, new_day)
except ValueError as e:
new_day -= 1
else:
break
return new_date
EDIT:
Improved version which:
keeps the time information if given a datetime.datetime object
doesn't use try/catch, instead using calendar.monthrange from the calendar module in the stdlib:
import datetime
import calendar
def add_one_month(orig_date):
# advance year and month by one month
new_year = orig_date.year
new_month = orig_date.month + 1
# note: in datetime.date, months go from 1 to 12
if new_month > 12:
new_year += 1
new_month -= 12
last_day_of_month = calendar.monthrange(new_year, new_month)[1]
new_day = min(orig_date.day, last_day_of_month)
return orig_date.replace(year=new_year, month=new_month, day=new_day)
Question: Is there a simple way to do this in the current release of Python?
Answer: There is no simple (direct) way to do this in the current release of Python.
Reference: Please refer to docs.python.org/2/library/datetime.html, section 8.1.2. timedelta Objects. As we may understand from that, we cannot increment month directly since it is not a uniform time unit.
Plus: If you want first day -> first day and last day -> last day mapping you should handle that separately for different months.
>>> now
datetime.datetime(2016, 1, 28, 18, 26, 12, 980861)
>>> later = now.replace(month=now.month+1)
>>> later
datetime.datetime(2016, 2, 28, 18, 26, 12, 980861)
EDIT: Fails on
y = datetime.date(2016, 1, 31); y.replace(month=2) results in ValueError: day is out of range for month
Ther is no simple way to do it, but you can use your own function like answered below.

How to calculate difference between two dates in weeks in python

I'm trying to calculate the difference between two dates in "weeks of year". I can get the datetime object and get the days etc but not week numbers. I can't, of course, subtract dates because weekends can't be ensured with that.
I tried getting the week number using d1.isocalendar()[1] and subtracting d2.isocalendar()[1] but the issue is that isocalendar()[1] returns December 31, 2012 as week 1 (which supposedly is correct) but that means my logic cannot span over this date.
For reference, here's my complete code:
def week_no(self):
ents = self.course.courselogentry_set.all().order_by('lecture_date')
l_no = 1
for e in ents:
if l_no == 1:
starting_week_of_year = e.lecture_date.isocalendar()[1] # get week of year
initial_year = e.lecture_date.year
if e == self:
this_year = e.lecture_date.year
offset_week = (this_year - initial_year) * 52
w_no = e.lecture_date.isocalendar()[1] - starting_week_of_year + 1 + offset_week
break
l_no += 1
return w_no
With this code, the lecture on Dec 31, 2012 ends up being -35.
How about calculating the difference in weeks between the Mondays within weeks of respective dates? In the following code, monday1 is the Monday on or before d1 (the same week):
from datetime import datetime, timedelta
monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))
print 'Weeks:', (monday2 - monday1).days / 7
Returns 0 if both dates fall withing one week, 1 if on two consecutive weeks, etc.
You may want to refer the Python CookBook (2005 edition) Recipe 3.3. The following code snippet is from the cookbook, does what you require.
from dateutil import rrule
import datetime
def weeks_between(start_date, end_date):
weeks = rrule.rrule(rrule.WEEKLY, dtstart=start_date, until=end_date)
return weeks.count()
This is a very simple solution with less coding everyone would understand.
from datetime import date
d1 = date(year, month, day)
d2 = date(year, month, day)
result = (d1-d2).days//7
The solution above has a bug (I can't add a comment due to low reputation). It doesn't account for hour differences.
# This code has a bug.
monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))
Counter example of 2 dates more than a week apart:
Timestamp1: 1490208193270795 (22 Mar 2017 18:43:13 GMT)
Monday1: 20 Mar 2017 18:43:13 GMT
Timestamp2: 1489528488744290 (14 Mar 2017 21:54:48 GMT)
Monday2: 13 Mar 2017 21:54:48 GMT
Using that code it returns 0 as week diff when it should be 1. Need to zero out the hours/minutes/seconds as well.
To determine how many weeks are spanned by two dates. eg From 3rd Oct to 13th Oct
October 2015
Mo 5 12 19 26
Tu 6 13 20 27
We 7 14 21 28
Th 1 8 15 22 29
Fr 2 9 16 23 30
Sa 3 10 17 24 31
Su 4 11 18 25
Code:
import math, datetime
start_date = datetime.date(2015, 10, 3)
start_date_monday = (start_date - datetime.timedelta(days=start_date.weekday()))
end_date = datetime.date(2015, 10, 13)
num_of_weeks = math.ceil((end_date - start_date_monday).days / 7.0)
Equals 3 weeks.
You're a bit vague on what 'difference in weeks' means exactly. Is 6 days difference one week or zero ? Is eight days difference one week or two ?
In any case, why can't you simply find the difference in another unit (seconds or days) and divide by the appropriate amount, with your prefered rounding for weeks?
Edited Best Answer
from datetime import timedelta
monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))
diff = monday2 - monday1
noWeeks = (diff.days / 7) + math.ceil(diff.seconds/86400)
print('Weeks:', noWeeks)`

Categories

Resources