A more suitable way to rewrite this? - python

I have the method:
def checkAgainstDate():
currentDate = date.today()
currentMonth = date.today().month
if currentMonth == 1
year = currentDate.year-1
return date(year, 11, 01)
elif currentMonth == 2:
year = currentDate.year-1
return date(year, 12, 01)
else
return date(currentDate.year, currentMonth-2, 01)
This just returns the first of the month 2 months ago, which is what I want is there a better approach I could have used using timedeltas? I choose my way because weeks in a month are not always constant.

dateutil is an amazing thing. It really should become stdlib someday.
>>> from dateutil.relativedelta import relativedelta
>>> from datetime import datetime
>>> (datetime.now() - relativedelta(months=2)).replace(day=1)
datetime.datetime(2010, 6, 1, 13, 16, 29, 643077)
>>> (datetime(2010, 4, 30) - relativedelta(months=2)).replace(day=1)
datetime.datetime(2010, 2, 1, 0, 0)
>>> (datetime(2010, 2, 28) - relativedelta(months=2)).replace(day=1)
datetime.datetime(2009, 12, 1, 0, 0)

Convert to an "absolute month number", subtract 2, convert back to year & month:
currentdate = date.today()
monthindex = 12*currentdate.year + (currentdate.month-1) -2
return datetime( monthindex // 12, monthindex % 12 + 1, 1)

Related

set datetime object time value to 0

I need to set the time value of detatime objects to 00:00, so I can easily compare two 'dates'
Now I do:
extracted_start_date = datetime.strptime(extracted_start_date.strftime('%Y-%m-%d'), '%Y-%m-%d')
so I have my datetime object
$ datetime.datetime(2021, 3, 18, 11, 13, 53, 782088),
I extract the date string strftime('%Y-%m-%d')
$ '2021-03-18'
and put this back into a datetime object now wch has time 00:00
$ datetime.datetime(2021, 3, 18, 0, 0)
This seems quite elaborate, is there a more efficient way, or is it OK like this?
datetime.datetime objects have method date which return datetime.date instance and these might be used for day-based comparison, consider following example:
import datetime
d1 = datetime.datetime(2021, 3, 17, 9, 0, 0) # yesterday 9:00
d2 = datetime.datetime(2021, 3, 18, 9, 0, 0) # today 9:00
d3 = datetime.datetime(2021, 3, 18, 12, 0, 0) # today 12:00
print(d1.date() == d2.date())
print(d2.date() == d3.date())
output:
False
True
You could use the replace method instead.
from datetime import datetime
d = datetime(2021, 3, 18, 11, 13, 53, 782088)
d.replace(hour=0, minute=0, second=0, microsecond=0)
> datetime.datetime(2021, 3, 18, 0, 0)

How to calculate the difference between 2 dates, split them dynamically? Python

I have to write a function which will count a difference in days between 2 dates. If the number of days exceeds 30, then split it in n date ranges and save in list or dict. I have started with the function but cannot finish it. The function has to calculate dynamic values.
For example
start_date = '2020-07-01'
end_date = '2020-09-15'
difference = (end_date - start_date).days
dateranges = []
dateranges.append(start_date)
if difference > 30:
end_date = start_date + dt.timedelta(days=30)
dateranges.append(end_date)
But I do not get how to make it cyclic, when it take each time a new start_date and end_date and calculates the difference between them. For example I always add 30 dys here but it can be that a less number of days has to be added.
If you want list of date ranges, between 2 dates, with maximum difference of 30 days, you can use timedelta to iterate over the range and split accordingly.
from datetime import datetime
from datetime import timedelta
def get_range(start_date, end_date, date_diff):
start_date = datetime.strptime(start_date, "%Y-%m-%d")
end_date = datetime.strptime(end_date, "%Y-%m-%d")
if abs((end_date - start_date).days) <= date_diff:
return [datetime.strftime(start_date,"%Y-%m-%d"),datetime.strftime(end_date,"%Y-%m-%d")]
else:
result=[]
while 1:
d3=start_date+timedelta(days=date_diff)
if d3>=end_date:
result.append([datetime.strftime(start_date,"%Y-%m-%d"),datetime.strftime(end_date,"%Y-%m-%d")])
break
else:
result.append([datetime.strftime(start_date,"%Y-%m-%d"),datetime.strftime(d3,"%Y-%m-%d")])
start_date=d3+timedelta(days=1)
return result
print(get_range('2020-07-01', '2020-09-15',30))
Output
[['2020-07-01', '2020-07-31'], ['2020-08-01', '2020-08-31'], ['2020-09-01', '2020-09-15']]
Here I assume, by date range, you mean start and end date like [start,end].
For example I always add 30 dys here but it can be that a less number
of days has to be added.
datetime library and timedelta function takes care of it and increase month if need.
from datetime import datetime
from datetime import timedelta
start_date = '2020-07-01'
end_date = '2020-09-15'
def date_difference(d1, d2):
d1 = datetime.strptime(d1, "%Y-%m-%d")
d2 = datetime.strptime(d2, "%Y-%m-%d")
if abs((d2 - d1).days) > 30:
dates = []
# if you don't want to include start_date, use range(1, 30) instead.
for i in range(0, 30):
dates.append(d1 + timedelta(days=i))
return dates
return []
print(date_difference(start_date, end_date))
Output:
[datetime.datetime(2020, 7, 1, 0, 0), datetime.datetime(2020, 7, 2, 0, 0),
datetime.datetime(2020, 7, 3, 0, 0), datetime.datetime(2020, 7, 4, 0, 0),
datetime.datetime(2020, 7, 5, 0, 0), datetime.datetime(2020, 7, 6, 0, 0),
datetime.datetime(2020, 7, 7, 0, 0), datetime.datetime(2020, 7, 8, 0, 0),
datetime.datetime(2020, 7, 9, 0, 0), datetime.datetime(2020, 7, 10, 0, 0),
...
datetime.datetime(2020, 7, 30, 0, 0)]
from datetime import datetime,timedelta
def split_dates(prev_date,next_date,interval):
date_ranges = []
if next_date > prev_date+timedelta(days=30):
while prev_date <= next_date:
prev_date += timedelta(days=interval)
date_ranges.append(prev_date)
return date_ranges

Reference each occurence of a day of the month given start datetime and an end datetime

As the title says, I'm trying to generate a list of datetimes corresponding to the occurrences of a specific day of the month between two dates.
So given a start date, an end date, and a day of the month, I want to see every occurrence of that day of the month:
from datetime import datetime
end_date = datetime(2012, 9, 15, 0, 0)
start_date = datetime(2012, 6, 1, 0, 0)
day_of_month = 16
dates = "magic code goes here"
dates would then hold an array as such:
dates == [
datetime(2012, 6, 16, 0, 0),
datetime(2012, 7, 16, 0, 0),
datetime(2012, 8, 16, 0, 0)
]
The issue I'm running into is the number of checks I have to perform. First I have to check if it's the start year, if so, then I have to start at the beginning month, but if the day of the month is before the start date, then I have to skip that month. This same thing applies for the end of the period. Not to mention I have to check if the period starts and ends in the same year. All in all it's turning into quite a mess of nested if and for statements.
Here is my solution:
import numpy as np
for year in np.arange(start_date.year, end_date.year + 1):
for month in np.arange(1, 13):
date = datetime(year, month, day_of_month, 0, 0)
if start_date < date < end_date:
dates.append(date)
Is there a more Pythonic way to accomplish this?
Here's a quick and dirty (but reasonably efficient) solution:
import datetime
d = start_date
days = []
while d <= end_date: # Change to < if you do not want the end_date
if d.day == day_of_month:
days.append(d)
d += datetime.timedelta(1)
days
# [datetime.datetime(2012, 6, 16, 0, 0),
# datetime.datetime(2012, 7, 16, 0, 0),
# datetime.datetime(2012, 8, 16, 0, 0)]
Ideally, you want to use pandas for this.
This is a succinct, but not efficient, way using pandas.date_range.
from datetime import datetime
import pandas as pd
end_date = datetime(2012, 9, 15, 0, 0)
start_date = datetime(2012, 6, 1, 0, 0)
day_of_month = 16
rng = [i.to_pydatetime() for i in pd.date_range(start_date, end_date, freq='1D') if i.day == day_of_month]
# [datetime.datetime(2012, 6, 16, 0, 0),
# datetime.datetime(2012, 7, 16, 0, 0),
# datetime.datetime(2012, 8, 16, 0, 0)]
Here is a more efficient method using a generator for the date range, which does not rely on pandas:
def daterange(start_date, end_date):
for n in range(int ((end_date - start_date).days)):
yield start_date + timedelta(n)
rng = [i for i in daterange(start_date, end_date) if i.day == day_of_month]
# [datetime.datetime(2012, 6, 16, 0, 0),
# datetime.datetime(2012, 7, 16, 0, 0),
# datetime.datetime(2012, 8, 16, 0, 0)]

What is the best way to handle datetime value overflow

I am attempting to build a program to handle alerts. I want it to be able to handle specific dates like 8/23/2015 7:00 and relative dates like 5 days and 7 hours from now. specific dates are fine but for relative dates if I try and just add 5 days and 7 hours to the date time it can overflow the values intended for that spot
import datetime
dt = datetime.datetime.now()
dayslater = 5
hourslater = 7
minuteslater = 30
alarmTime = datetime.datetime(dt.year, dt.month, dt.day + dayslater,
dt.hour + hourslater,
dt.minute + minuteslater, 0,0)
this is fine sometimes but if dayslater was 40 days it would overflow the value. I did set up a simple
if hours >= 24:
hours -= 24
days++
however this won't work for overflowing months whose length in days isn't consistent.
Don't. Dates are hard, and it's very easy to get it wrong.
Instead, use timedelta:
In [1]: from datetime import datetime, timedelta
In [2]: dt = datetime.now()
In [3]: dt
Out[3]: datetime.datetime(2015, 7, 23, 15, 2, 55, 836914)
In [4]: alarmTime = dt + timedelta(days=5, hours=7, minutes=30)
In [5]: alarmTime
Out[5]: datetime.datetime(2015, 7, 28, 22, 32, 55, 836914)
Use a datetime.timedelta() object and leave calculations to the datetime library:
import datetime
delta = datetime.timedelta(days=dayslater, hours=hourslater, minutes=minuteslater)
alarmTime = datetime.datetime.now() + delta
Demo:
>>> import datetime
>>> dt = datetime.datetime.now()
>>> dayslater = 5
>>> hourslater = 7
>>> minuteslater = 30
>>> delta = datetime.timedelta(days=dayslater, hours=hourslater, minutes=minuteslater)
>>> delta
datetime.timedelta(5, 27000)
>>> dt
datetime.datetime(2015, 7, 23, 21, 4, 59, 987926)
>>> dt + delta
datetime.datetime(2015, 7, 29, 4, 34, 59, 987926)
Note how the hours carried over to the next day (from 21:04 to 04:34), and thus the date went from the 23rd to the 29th. I did not have to worry about 'overflow' here.
This continues to work at month boundaries, at year boundaries, and in leap years, with February 29th:
>>> datetime.datetime(2015, 7, 26, 22, 42) + delta
datetime.datetime(2015, 8, 1, 6, 12)
>>> datetime.datetime(2015, 12, 26, 22, 42) + delta
datetime.datetime(2016, 1, 1, 6, 12)
>>> datetime.datetime(2016, 2, 23, 22, 42) + delta
datetime.datetime(2016, 2, 29, 6, 12)

How do I construct a Python time struct from the day of year?

I have the day of the year, or as its called in Python, the tm_yday.
I want to get out the month and day of month.
How can I create a Python time struct from just the day of year?
You can use datetime.strptime to parse the day of the year:
>>> from datetime import datetime
>>> tm_yday = 59
>>> tm_year = datetime.now().year # current year
>>> datetime.strptime('{} {}'.format(tm_year, tm_yday), '%Y %j')
datetime.datetime(2014, 2, 28, 0, 0)
import datetime
>>> datetime.datetime.strptime('10', '%j')
datetime.datetime(1900, 1, 10, 0, 0)
>>> datetime.datetime.strptime('359', '%j')
datetime.datetime(1900, 12, 25, 0, 0)
>>> datetime.datetime.strptime('359', '%j').month
12
>>> datetime.datetime.strptime('359', '%j').day
25
import datetime
foo=datetime.datetime(1990, 1, 1) + datetime.timedelta(tm_yday - 1)
month = foo.month
dayOfMonth = foo.day
Year 1990 is an example, try other in the case of leap year.
Datetime date types are the way to go here:
import datetime
Here's today:
>>> datetime.date.today()
datetime.date(2014, 2, 27)
And here's Jan 1st of 2014:
>>> datetime.date(2014, 1, 1)
datetime.date(2014, 1, 1)
To combine into a datetime object:
datetime.datetime.combine(datetime.date(2014, 1, 1),
datetime.datetime.min.time())

Categories