Date 6 months into the future - python

I am using the datetime Python module in django. I am looking to calculate the date if the expiry date is less than or equal to 6 months from the current date.
The reason I want to generate a date 6 months from the current date is to set an alert that will highlight the field/column in which that event occurs. I dont know if my question is clear. I have been reading about timedelta function but cant really get my head round it. I am trying to write an if statement to statisfy this condition. Anyone able to help me please? Am a newbie to django and python.

There are two approaches, one only slightly inaccurate, one inaccurate in a different way:
Add a datetime.timedelta() of 365.25 / 2 days (average year length divided by two):
import datetime
sixmonths = datetime.datetime.now() + datetime.timedelta(days=365.25/2)
This method will give you a datetime stamp 6 months into the future, where we define 6 monhs as exactly half a year (on average).
Use the external dateutil library, it has a excellent relativedelta class that will add 6 months based on calendar calculations to your current date:
import datetime
from dateutil.relativedelat import relativedelta
sixmonths = datetime.datetime.now() + relativedelta(months=6)
This method will give you a datetime stamp 6 months into the future, where the month component of the date has been forwarded by 6, and it'll take into account month boundaries, making sure not to cross them. August 30th plus 6 months becomes February 28th or 29th (leap years permitting), for example.
A demonstration could be helpful. In my timezone, at the time of posting, this translates to:
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2013, 2, 18, 12, 16, 0, 547567)
>>> now + datetime.timedelta(days=365.25/2)
datetime.datetime(2013, 8, 20, 3, 16, 0, 547567)
>>> now + relativedelta(months=6)
datetime.datetime(2013, 8, 18, 12, 16, 0, 547567)
So there is a 1 day and 15 hour difference between the two methods.
The same methods work fine with datetime.date objects too:
>>> today = datetime.date.today()
>>> today
datetime.date(2013, 2, 18)
>>> today + datetime.timedelta(days=365.25/2)
datetime.date(2013, 8, 19)
>>> today + relativedelta(months=6)
datetime.date(2013, 8, 18)
The half-year timedelta becomes a teensy less accurate when applied to dates only (the 5/8th day component of the delta is ignored now).

If by "6 months" you mean 180 days, you can use:
import datetime
d = datetime.date.today()
d + datetime.timedelta(6 * 30)
Alternatively if you, mean actual 6 months by calendar you'll have to lookup the calendar module and do some lookups on each month. For example:
import datetime
import calendar
def add_6_months(a_date):
month = a_date.month - 1 + 6
year = a_date.year + month / 12
month = month % 12 + 1
day = min(a_date.day,calendar.monthrange(year, month)[1])
return datetime.date(year, month, day)

I would give Delorean a look a serious look. It is built on top of dateutil and pytz to do what you asked would simply be the following.
>>> d = Delorean()
>>> d
Delorean(datetime=2013-02-21 06:00:21.195025+00:00, timezone=UTC)
>>> d.next_month(6)
Delorean(datetime=2013-08-21 06:00:21.195025+00:00, timezone=UTC)
It takes into account all the dateutil calculations as well as provide and interface for timezone shifts. to get the needed datetime simple .datetime on the Delorean object.

this might work for you in case you want to get an specfic date back:
from calendar import datetime
datetime.date(2019,1,1).strftime("%a %d")
#The arguments here are: year, month, day and the method is there to return a formated kind of date - in this case - day of the week and day of the month.
The outcome would be:
Tue 01
Hope it helps!

Related

Parse datetime when it comes in two different formats - Python

Depending on whether the item is over a week old or not, the date comes in the following formats:
Less than a week old comprised of day of the week and time:
date1 = "Monday 21:14"
More than a week old, is just the date:
date2 = "5 Apr '21"
I read them in as a string and need to parse them both to a consistent timestamp.
One way I tried is:
from dateutil.parser import parse
parse(date1)
# output: datetime.datetime(2021, 4, 23, 22, 18)
parse(date2)
# output: datetime.datetime(2021, 4, 5, 0, 0)
Using the dateutil package I can get it to easily parse date2, but it gives me the forward looking friday for date1 not the previous friday.
How would you suggest I parse the two dates, without knowing which will be received? and can I instruct the parser to take the last previous weekday (i.e. previous friday)
Many thanks
Setting a default for the parser might work. Since you want to take the last previous weekday in case the day of the month is not defined, you can use today's date one week ago.
Ex:
from datetime import datetime, timedelta
from dateutil import parser
date1 = "Monday 21:14"
date2 = "5 Apr '21"
# reference = date of today one week ago (as datetime object):
ref_date = datetime(*datetime.now().timetuple()[:3]) - timedelta(7)
for d in (date1, date2):
print(parser.parse(d, default=ref_date))
# 2021-04-12 21:14:00
# 2021-04-05 00:00:00
Note that today is Monday 2021-4-19 but this code gives you the previous Monday, 2021-4-12.

Find difference between two dates in years, with the remainder expressed in days, in Python

How does one find the difference between two dates, if the output should be expressed in years with the remainder expressed in days?
Example 1: if the two dates are June 1, 1981 and August 23, 2001, then the result should be 20 years and 83 days.
Example 2: if the two dates are January 1, 2002 and December 30, 2003, then the result should be 1 year and 363 days.
I'm not concerned with the formatting of the results; I just need to know the most Pythonic way of calculating the number of years and days.
Thank you!
Using datetime, a built-in module, you can get the number of days easily.
>>> import datetime
>>> foo = datetime.date(2001, 8, 23) - datetime.date(1981, 6, 1)
>>> foo
datetime.timedelta(days=7388)
>>> foo.days
7388
>>> bar = datetime.date(2003, 12, 30) - datetime.date(2002, 1, 1)
>>> bar
datetime.timedelta(days=728)
>>> bar.days
728
The dateutil module can give you the number of years, but the number of months is also thrown in.
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> relativedelta(datetime.date(2001, 8, 23), datetime.date(1981, 6, 1))
relativedelta(years=+20, months=+2, days=+22)
>>> relativedelta(datetime.date(2003, 12, 30), datetime.date(2002, 1, 1))
relativedelta(years=+1, months=+11, days=+29)
Be careful while using the number of months, though. A month is not defined as well as a day. The 11 months in the previous example are a mix of six 31-day months, four 30-day months and one 28-day month. So, in general, you cannot use it to obtain the number of days. I recommend writing a function to get the difference in the form you want.
import calendar
import datetime
from dateutil.relativedelta import relativedelta
def get_delta(date2, date1):
'''calculate the delta between two datetime.date objects (date2 the newer date)'''
number_of_leap_years = sum(1
for yr in range(date1.year, date2.year + 1)
if calendar.isleap(yr))
number_of_years = relativedelta(date2, date1).years
total_number_of_days = (date2 - date1).days
number_of_days = total_number_of_days
- 365 * number_of_years
- number_of_leap_years
return f'{number_of_years} years, {number_of_days} days'
You'll need to use the datetime and relativedelta modules.
import datetime
from dateutil.relativedelta import relativedelta
start_date = datetime.datetime(1981,6,1)
end_date = datetime.datetime(2002,1,1)
difference_in_years = relativedelta(end_date, start_date)
print(difference_in_years)

Using datetime.timedelta to add years

I am doing some time calculations in Python.
Goal:
Part of this is trying to :
Given a date, add time interval (X years, X months, X weeks), return date
ie
input args: input_time (datetime.date), interval (datetime.timedelta)
return: datetime.date
I looked at the datetime and datetime.timedelta docs
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)ΒΆ.
These seem to work well if I want to add a certain number of hours or weeks. However,
Problem:
I am trying to implement an operation such as date + 1 year and can't figure it out
E.g.
start = datetime.datetime(2000, 1, 1)
# expected output: datetime.datetime(2001, 1, 1)
# with the weeks, etc arguments given in timedelta, this fails unsurprisingly e.g
start + datetime.timedelta(weeks = 52)
# returns datetime.datetime(2000, 12, 30, 0, 0)
Question
Is this year-based operation possible with the basic tools of datetime - if so, how would I go about it?
I realize that for the year example, I could just do start.replace(year = 2001), but that approach will fail if I have months or weeks as input.
From my understanding, the dateutil library has more advanced features, but I was not clear how well it interacts with the in-built datetime objects.
I have reviewed this similar question but it did not help me with this.
Any help is much appreciated!
Running Python 3.6.5 on MacOs.
timedelta does not support years, because the duration of a year depends on which year (for example, leap years have Feb 29).
You could use a relativedelta instead (from PyPI package python-dateutil) which does support years and takes into account the baseline date for additions.
>>> from dateutil.relativedelta import relativedelta
>>> import datetime
>>> d = datetime.date(2020, 2, 29)
>>> d
datetime.date(2020, 2, 29)
>>> d + relativedelta(years=1)
datetime.date(2021, 2, 28)
You can hard code a new year value of the datetime using replace instead :)
This avoids leap years etc.
year_later = current.replace(year=current.year + 1)
Note that if the current date happens to be the 29th of February, this will raise a ValueError with the message: "Day is out of range for month". So you need to handle this special case, like this:
if current.month == 2 and current.day == 29:
year_later = current.replace(year=current.year + 1, day=28)
else:
year_later = current.replace(year=current.year + 1)
My quick and dirty method is to use
y = [number of years]
timedelta(days= y * 365)
I found this question looking for a more elegant solution. For my uses a precise answer wasn't necessary. I don't mind losing a day each leap year in this particular case.
My goal was very similar to yours. I wanted to have the same date, just on the next year. But i figured i can't avoid accounting for leap years. In the end it all boils down to what exactly is the requirement. Theoretically we can just add 365 days (and either loose a day when there was a Feb 29), or check in the next 365 days if there is a 29th of February, in which case add 1 more day.
But checking that would have been complex, and in the end i used a simple check for the new date's day if it is different from the original and then add 1 more day.
I understand with dateutil.relativedelta it is easier, but i wanted to do it without extra imports
demo:
from datetime import datetime, timedelta
dates = [datetime(1999, 1, 1),
datetime(1999, 12, 31),
datetime(2000, 1, 1),
datetime(2019, 3, 1),
datetime(2019, 1, 1),
datetime(2020, 1, 1),
datetime(2020, 3, 1),
datetime(2020, 2, 29)
]
for date in dates:
plus1year_date = date + timedelta(days=365)
print(date, "\t - original date")
print(plus1year_date, "\t - plus1year_date (+365 days)")
if date.day != plus1year_date.day:
plus1year_date = plus1year_date + timedelta(days=1)
print(plus1year_date, "\t - plus1year_date adjusted for leap year")
else:
print("No need to adjust for leap year")
print('--------------------------------------------------------------')
# Expected output:
# 1999-01-01 00:00:00 - original date
# 2000-01-01 00:00:00 - plus1year_date (+365 days)
# No need to adjust for leap year
# --------------------------------------------------------------
# 1999-12-31 00:00:00 - original date
# 2000-12-30 00:00:00 - plus1year_date (+365 days)
# 2000-12-31 00:00:00 - plus1year_date adjusted for leap year
# --------------------------------------------------------------
# 2000-01-01 00:00:00 - original date
# 2000-12-31 00:00:00 - plus1year_date (+365 days)
# 2001-01-01 00:00:00 - plus1year_date adjusted for leap year
# --------------------------------------------------------------
# ...
Edit: #MDoe - I forgot to mention that with the .year + 1 method one can end up with invalid dates if it is Feb 29 (ValueError).
Also if somebody wants to add an interval that could include more than one leap year, then my code won't be correct.
dateadding-yearpythondatetimetimedelta

Get date from week number

Please what's wrong with my code:
import datetime
d = "2013-W26"
r = datetime.datetime.strptime(d, "%Y-W%W")
print(r)
Display "2013-01-01 00:00:00", Thanks.
A week number is not enough to generate a date; you need a day of the week as well. Add a default:
import datetime
d = "2013-W26"
r = datetime.datetime.strptime(d + '-1', "%Y-W%W-%w")
print(r)
The -1 and -%w pattern tells the parser to pick the Monday in that week. This outputs:
2013-07-01 00:00:00
%W uses Monday as the first day of the week. While you can pick your own weekday, you may get unexpected results if you deviate from that.
See the strftime() and strptime() behaviour section in the documentation, footnote 4:
When used with the strptime() method, %U and %W are only used in calculations when the day of the week and the year are specified.
Note, if your week number is a ISO week date, you'll want to use %G-W%V-%u instead! Those directives require Python 3.6 or newer.
In Python 3.8 there is the handy datetime.date.fromisocalendar:
>>> from datetime import date
>>> date.fromisocalendar(2020, 1, 1) # (year, week, day of week)
datetime.date(2019, 12, 30, 0, 0)
In older Python versions (3.7-) the calculation can use the information from datetime.date.isocalendar to figure out the week ISO8601 compliant weeks:
from datetime import date, timedelta
def monday_of_calenderweek(year, week):
first = date(year, 1, 1)
base = 1 if first.isocalendar()[1] == 1 else 8
return first + timedelta(days=base - first.isocalendar()[2] + 7 * (week - 1))
Both works also with datetime.datetime.
To complete the other answers - if you are using ISO week numbers, this string is appropriate (to get the Monday of a given ISO week number):
import datetime
d = '2013-W26'
r = datetime.datetime.strptime(d + '-1', '%G-W%V-%u')
print(r)
%G, %V, %u are ISO equivalents of %Y, %W, %w, so this outputs:
2013-06-24 00:00:00
Availabe in Python 3.6+; from docs.
import datetime
res = datetime.datetime.strptime("2018 W30 w1", "%Y %W w%w")
print res
Adding of 1 as week day will yield exact current week start. Adding of timedelta(days=6) will gives you the week end.
datetime.datetime(2018, 7, 23)
If anyone is looking for a simple function that returns all working days (Mo-Fr) dates from a week number consider this (based on accepted answer)
import datetime
def weeknum_to_dates(weeknum):
return [datetime.datetime.strptime("2021-W"+ str(weeknum) + str(x), "%Y-W%W-%w").strftime('%d.%m.%Y') for x in range(-5,0)]
weeknum_to_dates(37)
Output:
['17.09.2021', '16.09.2021', '15.09.2021', '14.09.2021', '13.09.2021']
In case you have the yearly number of week, just add the number of weeks to the first day of the year.
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> week = 40
>>> year = 2019
>>> date = datetime.date(year,1,1)+relativedelta(weeks=+week)
>>> date
datetime.date(2019, 10, 8)
Another solution which worked for me that accepts series data as opposed to strptime only accepting single string values:
#fw_to_date
import datetime
import pandas as pd
# fw is input in format 'YYYY-WW'
# Add weekday number to string 1 = Monday
fw = fw + '-1'
# dt is output column
# Use %G-%V-%w if input is in ISO format
dt = pd.to_datetime(fw, format='%Y-%W-%w', errors='coerce')
Here's a handy function including the issue with zero-week.

Get date object for the first/last day of the current year

I need to get date objects for the first and last day in the current year.
Currently I'm using this code which works fine, but I'm curious if there's a nicer way to do it; e.g. without having to specify the month/day manually.
from datetime import date
a = date(date.today().year, 1, 1)
b = date(date.today().year, 12, 31)
The only real improvement that comes to mind is to give your variables more descriptive names than a and b.
from datetime import datetime
starting_day_of_current_year = datetime.now().date().replace(month=1, day=1)
ending_day_of_current_year = datetime.now().date().replace(month=12, day=31)
There is nothing in the python library but there are external libraries that wrap this functionality up. For example, pandas has a timeseries library, with which you can do:
from datetime import date
from pandas.tseries import offsets
a = date.today() - offsets.YearBegin()
b = date.today() + offsets.YearEnd()
Whilst pandas is overkill if all you want is year begin and year end functionality, it also has support for a lot of other high level concepts such as business days, holiday calendars, month/quarter/year offsets: http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects
You'll have some funky stuff going on if you happen to be running this late on New Year's Eve and the two calls to today() cross the year boundary. It's safer to do this:
from datetime import date
epoch_year = date.today().year
year_start = date(epoch_year, 1, 1)
year_end = date(epoch_year, 12, 31)
import datetime
year = 2016
first_day_of_year = datetime.date.min.replace(year = year)
last_day_of_year = datetime.date.max.replace(year = year)
print(first_day_of_year, last_day_of_year)
duh.
What if we want to get the exact time the year begins or ends? Same thing. Replace datetime.date with datetime.datetime, and there you go, you got the first last day of year in datetime.datetime format.
To make this even fancier, wrap the whole thing in a function:
import datetime
def year_range(year, datetime_o = datetime.date):
return (
datetime_o.min.replace(year = year),
datetime_o.max.replace(year = year)
)
print(year_range(2016, datetime.date))
print(year_range(2016, datetime.datetime))
Output:
(datetime.date(2016, 1, 1), datetime.date(2016, 12, 31))
(datetime.datetime(2016, 1, 1, 0, 0), datetime.datetime(2016, 12, 31, 23, 59, 59, 999999))
use relative timedelta and substract from date object
from dateutil.relativedelta import relativedelta
import datetime
date = datetime.date.today()
fistOfYear = date - relativedelta(years=0, month=1, day=1)
one genius way to find out first and last day of year is code below
this code works well even for leap years
first_day=datetime.date(year=i,month=1, day=1)
first_day_of_next_year=first_day.replace(year=first_day.year+1,month=1, day=1)
last_day=first_day_of_next_year-jdatetime.timedelta(days=1)

Categories

Resources