This question already has answers here:
Previous weekday in Python
(4 answers)
Closed 1 year ago.
I need to find the last weekday (without considering holidays). Is there any more elegant/robust way of implementing this than the one I'm currently using?
from datetime import date
b = date.today() - timedelta(days=1)
while b.weekday()>=5:
b = b - timedelta(days=1)
Something like this might work (untested):
from datetime import date, timedelta
b = date.today() - timedelta(days=1)
current_day = b.weekday() # 0 for Monday, 6 for Sunday
# go back 1 day for Sat, 2 days for Sun, 0 for other days
days_to_go_back = max(current_day - 4, 0)
b -= timedelta(days=days_to_go_back)
Related
I've been making a forum as a learning experience. I have a timestamp for every post, which I convert to a timedelta (how much time ago it was). I want to output the time like so:
If it's < 1 minute display it in seconds
If it's >= 1 minute and < 1 hour display it in minutes
If it's >= 1 hour and < 1 day display it in hours
If it's >= 1 day and < 1 week display it in days
If it's >= 1 week and < 1 month display it in weeks
If it's >= 1 month and < 1 year display it in months
If it's >= 1 year display it in years
What is the best way to do this in python and datetime?
Use a third-party library. For example, readabledelta is a timedelta subclass which prints human-readable.
>>> from readabledelta import readabledelta
>>> from datetime import timedelta
>>> print(readabledelta(timedelta(seconds=1)))
1 second
>>> print(readabledelta(timedelta(seconds=60)))
1 minute
>>> print(readabledelta(timedelta(seconds=60*60)))
1 hour
>>> print(readabledelta(timedelta(seconds=60*60*24)))
1 day
>>> print(readabledelta(timedelta(seconds=60*60*24*7)))
1 week
You can not easily use months or years, because the length of the unit is not well defined (a month could be 28-31 days, and a year could be 365-366 days).
This question already has answers here:
calculate the difference between two datetime.date() dates in years and months
(3 answers)
Closed 4 years ago.
I have 2 person's birth information, I want to do some analysis on them.
Like, the difference between their age, seconds, years+months+days.
I tried this:
from datetime import date
a = date(1991, 07, 20)
b = date(1999, 06, 06)
print((a-b).days)
-2878
this gives me 2878 days, but i want to calculate years + months + days
i tried to divide 2878/365, but i want the exact calculations
How can i approach this?
Expected Output:
7 years x months x days
Use datetime and dateutil:
from datetime import datetime
from dateutil import relativedelta
date1 = datetime(1991, 7, 20)
date2 = datetime(1999, 6, 6)
diff = relativedelta.relativedelta(date2, date1)
years = diff.years
months = diff.months
days = diff.days
print('{} years {} months {} days'.format(years, months, days))
# 7 years 10 months 17 days
For strict differences, i.e. differences between years, months and days, you can use the attributes of timedelta objects.
from datetime import date
a = date(1991, 7, 20)
b = date(1999, 6, 6)
months = a.month - b.month
years = a.year - b.year
days = a.day - b.day
print('{0} years, {1} months, {2} days'.format(years, months, days))
-8 years, 1 months, 14 days
For time-aware differences, you can use 3rd party dateutil as per #Austin's solution.
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
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.
This question already has answers here:
How to get the last day of the month?
(44 answers)
Closed 8 years ago.
As every month have different days in it, so i can't apply timedelta=30.
I want to get three variables
month_start,
month_end ,
month_days = month_end - month_start
Which will be correspond to start date of month and end date of month. and their interval will be number of days in the month.
for instance , for march : month_days = 31, april : month_days = 30
Use calendar module to get days from months
>>> import datetime
>>> import calendar
>>> now = datetime.datetime.now()
>>> print calendar.monthrange(now.year, now.month)[1]
31
For 2015 Feb month
>>> calendar.monthrange(2015, 2)
(6, 28)
https://docs.python.org/2/library/calendar.html