Expand date to the beginning and end datetime for the day - python

Based on the current time (datetime.now()) I want to expand this to cover the whole days time.
Right now I have been using:
start = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
end = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
Problem is that this is 24 hours from the current date. If it is 12pm noon that means it should only look back 12 hours as I want to search for the current days records.
How can I accomplish this in Python?

I hope this makes sense, I just gave very descriptive variable names
from datetime import datetime
from datetime import timedelta
now = datetime.now()
start_of_day = datetime(now.year,now.month,now.day)
delta_since_start_of_day = now - start_of_day
delta_till_end_of_day = timedelta(days=1) - delta_since_start_of_day
end_of_day = start_of_day + timedelta(days=1)

Here's another solution that directly resets the time - no math required. Uses datetime.replace():
now = datetime.now()
day_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
day_end = day_start + timedelta(hours=24)

It seems you could accomplish what you wish like so:
from datetime import datetime, time
now = datetime.now()
start = datetime.combine(now, time.min) # datetime.datetime(2021, 11, 5, 0, 0)
end = datetime.combine(now, time.max) # datetime.datetime(2021, 11, 5, 23, 59, 59, 999999)
No need for maths, replacing, timedeltas.

I just use datetime.time.max in this way:
now = datetime.now()
day_end = datetime.datetime.combine(now, datetime.time.max)

Related

Python DateTime minus TimeDelta vs TimeDelta minus DateTime

Say I have the datetime now:
import datetime
now = datetime.datetime(2019, 10, 3, 1, 57, 3, 939862)
print(now)
2019-10-03 01:57:03.939862
and I have a timedelta for the start of business day (07:00:00).
start_biz_dt = datetime.timedelta(hours = 7)
I want to do a calculation that gives me the time from now to start of business day.
ie, I want:
6:03:56.060138
But I obviously cannot do:
start_biz_dt - now
I could give start_biz_dt the same date as now, but I have many datetimes in a column of various dates, so this might not be the best way. Any help is appreciated.
To find closest 07:00:00, so you can use next code:
from datetime import datetime, timedelta
start_of_business_day = datetime.now().replace(hour=7, minute=0, second=0)
if start_of_business_day < datetime.now():
start_of_business_day += timedelta(days=1)
To calculate how much left just substitute current datetime from start_of_business_day:
sleep_time = start_of_business_day - datetime.now()

How to convert datetime from decimal to ā€œ%y-%m-%d %H:%M:%Sā€ given the time origin?

I did my search around but I couldn't find an answer that satisfies my problem.
I am using python 3.7 and I need to convert a series of decimal numbers into datetime object in the form %Y-%m-%d %H:%M:%S. While doing so I need to consider an origin point, for example:
t = 0.000000 equals to 2016-06-25 00:00:00
t = 0.010417 equals to ..... ?
and so on. I know that in my decimal time the integer part is day since start, decimal part is fraction of day.
I have found an answer using R here. I also think that I might need to use the class method date.fromordinal(ordinal)or something similar but I cannot figure it out how to do it.
This is what I have tried so far:
example t = 1.010416
import datetime as DT
from datetime import timedelta
day = int(x)
datetime_object = DT.datetime.strptime("2016-06-25 00:00:00", '%Y-%m-%d %H:%M:%S')
python_datetime = DT.datetime.fromordinal(day) + timedelta(days=datetime_object.day-1)
I get:
datetime.datetime(1, 1, 25, 0, 0)
But I cannot add the year 2016 nor the month. Also, for every case in which int(t) = 0, I get:
ValueError: ordinal must be >= 1
Thank you very much for your answers
Just to leave a clear answer here, taking into account my comments on the other answers:
from datetime import datetime,timedelta
base_date = datetime(2016, 6, 25)
deltas = (2.34857, 0.010417, 1.010416)
for delta in deltas:
print((base_date + timedelta(delta)).strftime('%Y-%m-%d %H:%M:%S'))
That code yields the following ouput:
>>> from datetime import datetime,timedelta
>>>
>>> base_date = datetime(2016, 6, 25)
>>> deltas = (2.34857, 0.010417, 1.010416)
>>>
>>> for delta in deltas:
... print((base_date + timedelta(delta)).strftime('%Y-%m-%d %H:%M:%S'))
...
2016-06-27 08:21:56
2016-06-25 00:15:00
2016-06-26 00:14:59
>>>
timedelta stores its data in this format: (DAYS, SECONDS) so you can calculate it easily:
import datetime
t = 2.34857
# Full days
days = int(t)
# Part of a day
part_of_day = t - int(t)
seconds = int(part_of_day * 24 * 60 * 60)
# Calculate the time delta
dt = datetime.timedelta(
days=days,
seconds=seconds
)
# Add t-delta to the first day
first_day = datetime.datetime(2016, 6, 25)
current_time = first_day + dt
current_time
will return:
datetime.datetime(2016, 6, 27, 8, 21, 56)
Then you can convert it to a string with this function:
datetime.datetime.strftime(current_time, '%Y-%m-%d %H:%M:%S')
'2016-06-27 08:21:56'
Edit 1: Instead of constructing the timedelta by days-seconds, one can use just float days as parameter (thanks to accdias!):
dt = datetime.timedelta(days=t)

Python How to Check if time is midnight and not display time if true

I'm modifying our pacific time zone filter to include a time option. I don't want the time component to be shown if midnight. The only import thus far we are using is dateutil.parser. Any pointers on best solution would be appreciated! Thanks.
def to_pacific_date_str(timestamp, format='%Y-%m-%d', time=False):
pacific_timestamp = timestamp
if time:
format='%Y-%m-%d %H:%M' # 2016-10-03 00:00
if timestamp.tzname() is None:
# setting timezone lost when pulled from DB
utc_timestamp = timestamp.replace(tzinfo=pytz.utc)
# always converting to pacific timezone
pacific_timestamp = utc_timestamp.astimezone(pytz.timezone('US/Pacific'))
return pacific_timestamp.strftime(format)
I believe the best thing to do would be to just take the time() from the datetime before passing it, then compare that to datetime.time(0, 0).
import pytz
import datetime
def to_pacific_date_str(timestamp, date_fmt='%Y-%m-%d', time=False):
pacific_timestamp = timestamp
if timestamp.tzinfo is None:
# setting timezone lost when pulled from DB
utc_timestamp = timestamp.replace(tzinfo=pytz.utc)
# always converting to pacific timezone
pacific_timestamp = utc_timestamp.astimezone(pytz.timezone('US/Pacific'))
if time and pacific_timestamp.time() != datetime.time(0, 0):
date_fmt = '%Y-%m-%d %H:%M' # 2016-10-03 00:00
return pacific_timestamp.strftime(date_fmt)
Note that I've changed format to date_fmt, because format() is already a builtin. Also, from a design standpoint, it's probably not a great idea to have time override the specified format string, so maybe change the "add time" portion to be date_fmt = date_fmt + ' %H:%M'.
Demonstration:
>>> PST = pytz.timezone('US/Pacific')
>>> to_pacific_date_str(PST.localize(datetime.datetime(2015, 4, 1, 0, 0)), time=True)
'2015-04-01'
>>> PST = pytz.timezone('US/Pacific')
>>> to_pacific_date_str(PST.localize(datetime.datetime(2015, 4, 1, 2, 0)), time=True)
'2015-04-01 02:00'
Try this for UTC:
def checkIfMidnight():
return (time.time() % 86400) == 0
To check if the time is midnight:
from datetime import datetime
def checkIfMidnight():
now = datetime.now()
seconds_since_midnight = (now - now.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds()
return seconds_since_midnight == 0
Alternatively you can use the .hour, .minute and .second attributes of the datetime object. Like this:
from datetime import datetime as dt
from pytz import timezone
now = dt.now(timezone('US/Pacific'))
midnight = now.hour == 0 and now.minute == 0 and now.second == 0 and now.microsecond == 0
midnight is a boolean indicating if it is midnight in the US/Pacific timezone.
I am not sure if this is the solution you are/were looking for but personally I use simple comparison:
import datetime
...
time == datetime.time(hour=0, minute=0, second=0, microsecond=0)
where time is TimeObject (datetime.time)

Cleanest and most Pythonic way to get tomorrow's date?

What is the cleanest and most Pythonic way to get tomorrow's date? There must be a better way than to add one to the day, handle days at the end of the month, etc.
datetime.date.today() + datetime.timedelta(days=1) should do the trick
timedelta can handle adding days, seconds, microseconds, milliseconds, minutes, hours, or weeks.
>>> import datetime
>>> today = datetime.date.today()
>>> today
datetime.date(2009, 10, 1)
>>> today + datetime.timedelta(days=1)
datetime.date(2009, 10, 2)
>>> datetime.date(2009,10,31) + datetime.timedelta(hours=24)
datetime.date(2009, 11, 1)
As asked in a comment, leap days pose no problem:
>>> datetime.date(2004, 2, 28) + datetime.timedelta(days=1)
datetime.date(2004, 2, 29)
>>> datetime.date(2004, 2, 28) + datetime.timedelta(days=2)
datetime.date(2004, 3, 1)
>>> datetime.date(2005, 2, 28) + datetime.timedelta(days=1)
datetime.date(2005, 3, 1)
No handling of leap seconds tho:
>>> from datetime import datetime, timedelta
>>> dt = datetime(2008,12,31,23,59,59)
>>> str(dt)
'2008-12-31 23:59:59'
>>> # leap second was added at the end of 2008,
>>> # adding one second should create a datetime
>>> # of '2008-12-31 23:59:60'
>>> str(dt+timedelta(0,1))
'2009-01-01 00:00:00'
>>> str(dt+timedelta(0,2))
'2009-01-01 00:00:01'
darn.
EDIT - #Mark: The docs say "yes", but the code says "not so much":
>>> time.strptime("2008-12-31 23:59:60","%Y-%m-%d %H:%M:%S")
(2008, 12, 31, 23, 59, 60, 2, 366, -1)
>>> time.mktime(time.strptime("2008-12-31 23:59:60","%Y-%m-%d %H:%M:%S"))
1230789600.0
>>> time.gmtime(time.mktime(time.strptime("2008-12-31 23:59:60","%Y-%m-%d %H:%M:%S")))
(2009, 1, 1, 6, 0, 0, 3, 1, 0)
>>> time.localtime(time.mktime(time.strptime("2008-12-31 23:59:60","%Y-%m-%d %H:%M:%S")))
(2009, 1, 1, 0, 0, 0, 3, 1, 0)
I would think that gmtime or localtime would take the value returned by mktime and given me back the original tuple, with 60 as the number of seconds. And this test shows that these leap seconds can just fade away...
>>> a = time.mktime(time.strptime("2008-12-31 23:59:60","%Y-%m-%d %H:%M:%S"))
>>> b = time.mktime(time.strptime("2009-01-01 00:00:00","%Y-%m-%d %H:%M:%S"))
>>> a,b
(1230789600.0, 1230789600.0)
>>> b-a
0.0
Even the basic time module can handle this:
import time
time.localtime(time.time() + 24*3600)
For people who are dealing with servers Time Stamp
To get yesterday Time Stamp:
yesterdaytimestamp = datetime.datetime.today() + datetime.timedelta(days=-1)
To get Today Time Stamp:
currenttimestamp = datetime.datetime.now().timestamp()
To get Tomorrow Time Stamp:
tomorrowtimestamp = datetime.datetime.today() + datetime.timedelta(days=1)
To print:
print('\n Yesterday TimeStamp is : ', yesterdaytimestamp.timestamp(),
'\n Today TimeStamp is :', currenttimestamp,
'\n Tomorrow TimeStamp is: ', tomorrowtimestamp.timestamp())
The output:
Yesterday TimeStamp is : 1632842904.110993
Today TimeStamp is : 1632929304.111022
Tomorrow TimeStamp is : 1633015704.11103
There's nothing at all wrong with using today() as shown in the selected answer if that is the extent of your needs.
datetime.date.today() + datetime.timedelta(days=1)
Alternatively, if you or someone else working with your code might need more precision in handling tomorrow's date, consider using datetime.now() instead of today(). This will certainly allow for simpler, more readable code:
datetime.datetime.now() + datetime.timedelta(days=1)
This returns something like:
datetime.datetime(2022, 2, 17, 19, 50, 19, 984925)
The advantage is that you can now work with datetime attributes in a concise, human readable way:
class datetime.datetime
A combination of a date and a time. Attributes: year, month, day, hour, minute, second, microsecond, and tzinfo.
Examples
You can easily convert this to a date object withdate():
import datetime
tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
print(f"Tomorrow's date is {tomorrow.date()}")
tomorrow.date() is easy to use and it is very clear to anyone reading your code that it is returning the date for tomorrow. The output for the above looks like so:
Tomorrow's date is 2022-02-17
If later in your code you only need the date number for the day, you can now use tomorrow.day:
print(f"Tomorrow is the {tomorrow.day}rd")
Which will return something like:
Tomorrow is the 17rd
That's a silly example, but you can see how having access to these attributes can be useful and keep your code readable as well. It can be easily understood that tomorrow.day returns the day number.
Need to work with the exact time tomorrow's date begins? You can now replace the hours, minutes, seconds, and microseconds:
# Replace all attributes except day with 0.
midnight = tomorrow.replace(
hour=0,
minute=0,
second=0,
microsecond=0)
# Print midnight as the beginning of tomorrow's date.
print(f"{midnight}")
Reading the above code, it should be apparent which attributes of tomorrow are being replaced. When midnight is printed, it will output:
2022-02-17 00:00:00
Need to know the time left until tomorrow's date? Now something like that is possible, simple, and readable:
print(f"{midnight - datetime.datetime.now()}")
The output is the time to the microsecond that tomorrow's date begins:
3:14:28.158331
There are many ways people might wish to handle tomorrow's date. By ensuring these attributes are available from the beginning, you can write more readable code and avoid unnecessary work later.
For the case you only want to calculate the timestamp
import time
tomorrow = (int(time.time() / 86400) + 1) * 86400

How to iterate over a timespan after days, hours, weeks and months?

How do I iterate over a timespan after days, hours, weeks or months?
Something like:
for date in foo(from_date, to_date, delta=HOURS):
print date
Where foo is a function, returning an iterator. I've been looking at the calendar module, but that only works for one specific year or month, not between dates.
Use dateutil and its rrule implementation, like so:
from dateutil import rrule
from datetime import datetime, timedelta
now = datetime.now()
hundredDaysLater = now + timedelta(days=100)
for dt in rrule.rrule(rrule.MONTHLY, dtstart=now, until=hundredDaysLater):
print dt
Output is
2008-09-30 23:29:54
2008-10-30 23:29:54
2008-11-30 23:29:54
2008-12-30 23:29:54
Replace MONTHLY with any of YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, or SECONDLY. Replace dtstart and until with whatever datetime object you want.
This recipe has the advantage for working in all cases, including MONTHLY. Only caveat I could find is that if you pass a day number that doesn't exist for all months, it skips those months.
I don't think there is a method in Python library, but you can easily create one yourself using datetime module:
from datetime import date, datetime, timedelta
def datespan(startDate, endDate, delta=timedelta(days=1)):
currentDate = startDate
while currentDate < endDate:
yield currentDate
currentDate += delta
Then you could use it like this:
>>> for day in datespan(date(2007, 3, 30), date(2007, 4, 3),
>>> delta=timedelta(days=1)):
>>> print day
2007-03-30
2007-03-31
2007-04-01
2007-04-02
Or, if you wish to make your delta smaller:
>>> for timestamp in datespan(datetime(2007, 3, 30, 15, 30),
>>> datetime(2007, 3, 30, 18, 35),
>>> delta=timedelta(hours=1)):
>>> print timestamp
2007-03-30 15:30:00
2007-03-30 16:30:00
2007-03-30 17:30:00
2007-03-30 18:30:00
I achieved this using pandas and datetime libraries as follows. It was much more convenient for me.
import pandas as pd
from datetime import datetime
DATE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
start_datetime = datetime.strptime('2018-05-18 00:00:00', DATE_TIME_FORMAT)
end_datetime = datetime.strptime('2018-05-23 13:00:00', DATE_TIME_FORMAT)
timedelta_index = pd.date_range(start=start_datetime, end=end_datetime, freq='H').to_series()
for index, value in timedelta_index.iteritems():
dt = index.to_pydatetime()
print(dt)
For iterating over months you need a different recipe, since timedeltas can't express "one month".
from datetime import date
def jump_by_month(start_date, end_date, month_step=1):
current_date = start_date
while current_date < end_date:
yield current_date
carry, new_month = divmod(current_date.month - 1 + month_step, 12)
new_month += 1
current_date = current_date.replace(year=current_date.year + carry,
month=new_month)
(NB: you have to subtract 1 from the month for the modulus operation then add it back to new_month, since months in datetime.dates start at 1.)
Month iteration approach:
def months_between(date_start, date_end):
months = []
# Make sure start_date is smaller than end_date
if date_start > date_end:
tmp = date_start
date_start = date_end
date_end = tmp
tmp_date = date_start
while tmp_date.month <= date_end.month or tmp_date.year < date_end.year:
months.append(tmp_date) # Here you could do for example: months.append(datetime.datetime.strftime(tmp_date, "%b '%y"))
if tmp_date.month == 12: # New year
tmp_date = datetime.date(tmp_date.year + 1, 1, 1)
else:
tmp_date = datetime.date(tmp_date.year, tmp_date.month + 1, 1)
return months
More code but it will do fine dealing with long periods of time checking that the given dates are in order...
Also can use the module arrow
https://arrow.readthedocs.io/en/latest/guide.html#ranges-spans
>>> start = datetime(2013, 5, 5, 12, 30)
>>> end = datetime(2013, 5, 5, 17, 15)
>>> for r in arrow.Arrow.range('hour', start, end):
... print(repr(r))
...
<Arrow [2013-05-05T12:30:00+00:00]>
<Arrow [2013-05-05T13:30:00+00:00]>
<Arrow [2013-05-05T14:30:00+00:00]>
<Arrow [2013-05-05T15:30:00+00:00]>
<Arrow [2013-05-05T16:30:00+00:00]>
This library provides a handy calendar tool: mxDateTime, that should be enough :)
You should modify this line to make this work correctly:
current_date = current_date.replace(year=current_date.year + carry,month=new_month,day=1)
;)

Categories