I'm trying to get my head around the datetime module. I know the time now as an epoch and the time an event last happened (as an epoch time). What I need to do is figure out whether that event happened between midnight and midnight of yesterday.
t = time.time() # is now
t2 = 1234567890 # some arbitrary time from my log
24 hours ago is t - 86400, but how can I round that up and down to midnight. I'm having real trouble finding a way to get timestamps in and out of datetime or then manipulating a datetime to set the time.
In the Middle of the Night
Generating the last midnight is easy:
from datetime import datetime, time
midnight = datetime.combine(datetime.today(), time.min)
That combines today's date (you can use date() or a datetime() instance, your pick), together with time.min to form a datetime object at midnight.
Yesterday
With a timedelta() you can calculate the previous midnight:
from datetime import timedelta
yesterday_midnight = midnight - timedelta(days=1)
That Was Yesterday
Now test if your timestamp is in between these two points:
timestamp = datetime.fromtimestamp(some_timestamp_from_your_log)
if yesterday_midnight <= timestamp < midnight:
# this happened between 00:00:00 and 23:59:59 yesterday
All Together Now
Combined into one function:
from datetime import datetime, time, timedelta
def is_yesterday(timestamp):
midnight = datetime.combine(datetime.today(), time.min)
yesterday_midnight = midnight - timedelta(days=1)
return yesterday_midnight <= timestamp < midnight:
if is_yesterday(datetime.fromtimestamp(some_timestamp_from_your_log)):
# ...
Midnight at the start of today is:
midnight = (int(time.time() // 86400)) * 86400
so yesterday's midnight is:
midnight = (int(time.time() // 86400)) * 86400 - 86400
Given such a timestamp, you can use divmod to compute the number of days since the epoch (which you don't care about), and how many seconds are leftover (which you do):
days_since, remaining_seconds = divmod(t, 24*3600) # Divide by number of seconds in one day
Then, you subtract the leftover seconds from your original timestamp, which produces midnight
of the current day.
t -= remaining_seconds
Rounding up is as simple as shifting your target timestamp forward exactly one day before rounding down.
tomorrow_t = t + 24 * 3600
days_since, remaining_seconds = divmod(tomorrow_t, 24*3600)
t = tomorrow_t - remaining_seconds
To get the specific timezone's midnight timestamp:
from datetime import datetime
import pytz
TZ = "Asia/Shanghai"
datetime.now(pytz.timezone(TZ)).replace(hour=0, minute=0, second=0, microsecond=0).timestamp()
In my estimation, many date and time manipulations are easier to do, and to understand, using the arrow library. This is one of them.
Create an arbitrary date and time.
>>> import arrow
>>> arbitrary = arrow.get(2017,8,16,11,5)
Calculate midnight_yesterday: first, midnight of arbitrary as its 'day' floor; then shift this back by one day. Display the result.
>>> midnight_yesterday = arbitrary.floor('day').shift(days=-1)
>>> midnight_yesterday
<Arrow [2017-08-15T00:00:00+00:00]>
Use timestamp for the desired overall result, for Python 3.3+.
>>> midnight_yesterday.datetime.timestamp()
1502755200.0
Or use this expression for Python 2.7. (Credit: https://stackoverflow.com/a/11743262/131187 for the latter two expressions.)
>>> (midnight_yesterday-arrow.get(1970,1,1)).total_seconds()
1502755200.0
You can use this code:
import time
seconds_of_day = 24 * 60 * 60 # 86400
last_midnight = (round(time.time()) // seconds_of_day) * seconds_of_day
yesterday_last_midnight = last_midnight - seconds_of_day
import time
start_str = time.strftime( "%m/%d/%Y" ) + " 00:00:00"
end_str = time.strftime( "%m/%d/%Y ") + " 23:59:59"
start_ts = int( time.mktime( time.strptime( start_str, "%m/%d/%Y %H:%M:%S" ) ) )
end_ts = int( time.mktime( time.strptime( end_str, "%m/%d/%Y %H:%M:%S" ) ) )
print (start_ts) # timestamp today at 00:00:00
print (end_ts) # timestamp today at 23:59:59
# 1552435200
# 1552521599
Source Python get unix epoch for today’s midnight and today’s 23:59:59 (start of day, end of day)
Related
I would like to ask for a help. I am a beginner when it comes to Python. I try to write a function, that sums up together two "times" and returns new_time and also how many times new_time passed midnight of "start_time"(for example 23:00 and 03:00, new_date is 02:00, and 1 day has passed )
Thank you really much in advance
from datetime import datetime, timedelta
def add_time(start_time: str, time_to_add: str):
start_time_time = datetime.strptime(start_time, "%H:%M")
add_time_time = datetime.strptime(time_to_add, "%H:%M")
new_time = start_time_time + timedelta(minutes=add_time_time.minute, hours=add_time_time.hour)
return f"New time is {new_time.strftime('%H:%M')}, XXX days after"
print(add_time("23:20", "19:20"))
Calculate the dates for start_time_time and new_time. The number of days elapsed will be the difference (in days) between these dates.
I believe there are several ways to extract just the date from a "datetime", but I have just replaced the hours and minutes to zero.
from datetime import datetime, timedelta
def add_time(start_time: str, time_to_add: str):
start_time_time = datetime.strptime(start_time, "%H:%M")
start_date = start_time_time.replace(hour=0, minute=0)
#print(start_date)
add_time_time = datetime.strptime(time_to_add, "%H:%M")
new_time = start_time_time + timedelta(minutes=add_time_time.minute, hours=add_time_time.hour)
new_date = new_time.replace(hour=0, minute=0)
#print(new_date)
days_elapsed = (new_date - start_date).days
return f"New time is {new_time.strftime('%H:%M')}, {days_elapsed} days after"
print(add_time("23:20", "19:20"))
The following code snippets demonstrates how to calculate the number of days after. You can uncomment the print statements to see what these dates actually represent.
Hope this helps.
There are many ways to do this, I done mine in such as way that it should allow you to add example of 100hours, etc. Hope this helps.
from datetime import datetime, timedelta
# Function that adds time HH:mm to a datetime object, adds set Hours and Minutes to start time and returns total days, hours, minutes and seconds passed
def add_time(start_time, time_to_add):
# Add time to start time
start_time = datetime.strptime(start_time, '%H:%M')
# Strip hours, minutes and convert to ms
time_to_add = time_to_add.split(':')
time_to_add = timedelta(hours=int(time_to_add[0]), minutes=int(time_to_add[1]))
finish_time = start_time + time_to_add
# Calculate total days, hours, minutes and seconds passed
total_days = finish_time.day - start_time.day
total_hours = finish_time.hour - start_time.hour
total_minutes = finish_time.minute - start_time.minute
total_seconds = finish_time.second - start_time.second
# Return total days, hours, minutes and seconds passed
return total_days, total_hours, total_minutes, total_seconds
# today + 23 hours + 20 minutes
days, hours, minutes, seconds = add_time("13:13", "25:00")
print(days, hours, minutes, seconds)
I am trying to do some testing with time offsets from UTC. I have tried two methods as shown in the code listing below:
Adding timedelta to UTC datetime
Using astimezone method on UTC datetime
In the short test program below the resultant date from astimezone method is 1 hour behind. I do not understand why??
from datetime import datetime, timedelta, timezone
if __name__ == "__main__":
utc_now = datetime.utcnow()
target_time = int((utc_now + timedelta(hours=10)).timestamp())
timestamp = utc_now.astimezone(timezone(timedelta(hours=10)))
print(f"datetime.utcnow() = {utc_now.isoformat()}")
print(
f"datetime.utcnow() + 10 hours using timedelta = {datetime.fromtimestamp(target_time).isoformat()}"
)
print(f"datetime.utcnow() + 10 hours using astimezone = {timestamp.isoformat()}")
datetime.utcnow() = 2021-09-04T16:12:53.753059
datetime.utcnow() + 10 hours using timedelta = 2021-09-05T02:12:53
datetime.utcnow() + 10 hours using astimezone = 2021-09-05T01:12:53.753059+10:00
Edit - Update - datetime.now (timezone.utc )
from datetime import datetime, timedelta, timezone
if __name__ == "__main__":
utc_now = datetime.now(timezone.utc)
target_time = int((utc_now + timedelta(hours=10)).timestamp())
timestamp = utc_now.astimezone(timezone(timedelta(hours=10)))
print(f"datetime.utcnow() = {utc_now.isoformat()}")
print(
"datetime.utcnow() + 10 hours using timedelta ="
f" {datetime.fromtimestamp(target_time).isoformat()}"
)
print(f"datetime.utcnow() + 10 hours using astimezone = {timestamp.isoformat()}")
Tried to make timezone aware UTC datetime now with the same result.
How do I use astimezone to get an equivalent result?
The problem here is the assumption that datetime.utcnow() gives you UTC. It does not. It gives you a naive datetime object that Python still treats as local time although hours, minutes etc. resemble UTC.
Set tzinfo adequately to get consistent results (don't use utcnow at all if possible! - unless you know what you're doing):
from datetime import datetime, timedelta, timezone
utc_now = datetime(2021, 9, 4, tzinfo=timezone.utc)
target_time = int((utc_now + timedelta(hours=10)).timestamp())
timestamp = utc_now.astimezone(timezone(timedelta(hours=10)))
print(f"utc_now = {utc_now.isoformat()}")
print(f"utc_now + 10 hours using timedelta = {datetime.fromtimestamp(target_time, tz=timezone.utc).isoformat()}")
print(f"utc_now + 10 hours using astimezone = {timestamp.isoformat()}")
# utc_now = 2021-09-04T00:00:00+00:00
# utc_now + 10 hours using timedelta = 2021-09-04T10:00:00+00:00
# utc_now + 10 hours using astimezone = 2021-09-04T10:00:00+10:00
The key here is understanding the difference between naive datetime (=local time by default) and aware datetime (the time zone you set...). For more time zone handling, see also the zoneinfo lib.
an aspect that is also relevant here in the context of working with time zones in Python: timedelta arithmetic is wall time arithmetic - i.e. what you would observe on a wall clock that gets adjusted to DST active/inactive. In the following example, I add 24 hours:
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
t0 = datetime(2021, 10, 30, 20, tzinfo=ZoneInfo("Europe/Berlin")) # DST active
t1 = t0 + timedelta(hours=24) # add 24 hours -> DST is inactive
print(t0, t1)
# 2021-10-30 20:00:00+02:00 2021-10-31 20:00:00+01:00
print((t1-t0).total_seconds()/3600)
# 24.0
Now watch how they become 25 hours - not because of magic but because of the wall clock would show local time, not UTC...
t0_utc, t1_utc = t0.astimezone(ZoneInfo("UTC")), t1.astimezone(ZoneInfo("UTC"))
print(t0_utc, t1_utc)
# 2021-10-30 18:00:00+00:00 2021-10-31 19:00:00+00:00
print((t1_utc-t0_utc).total_seconds()/3600)
# 25.0
Note: since Europe/Berlin is the time zone my OS is configured to use, this would also work with t0 and t1 being naive datetime objects!
I want to calculate hours of work during a day, and subtract lunchtime from that time. So somebody clocks in at 8:00, takes a lunch from 12:00 to 12:30, and finish at 16:00.
Lunchtime is configured in a settings table, with start-time and end-time.
So in a nutshell I want to calculate this:
endtime minus starttime = n hours:minutes of work, minus lunchtime (= 12:30 - 12:00 = 30 minutes)
How can I calculate this in Python without making this a hardcoded thing?
Help would be much appreciated
cheers
You can do it with Python datetime:
import datetime as dt
def work_time(start, end, lunch=[], format_='%H:%M'):
""" Calculate the hours worked in a day.
"""
start_dt = dt.datetime.strptime(start, format_)
end_dt = dt.datetime.strptime(end, format_)
if lunch:
lunch_start_dt = dt.datetime.strptime(lunch[0], format_)
lunch_end_dt = dt.datetime.strptime(lunch[1], format_)
lunch_duration = lunch_end_dt - lunch_start_dt
else:
lunch_duration = dt.timedelta(0)
elapsed = end_dt - start_dt - lunch_duration
hours = elapsed.seconds / 3600
return hours
>>> work_time('8:00', '16:00', lunch=['12:00', '12:30'])
7.5
The documentation for datetime provides more information on specific formatting and how to use timedeltas to perform operations on datetime and time objects.
I have a time from five minutes ago, using datetime.time.now() and I need to know what the time would be if I subtracted that time from the current time.
Try 1 - Didn't Work:
from datetime import datetime, timedelta
time1 = datetime.now()
time2 = datetime.now() + timedelta(minutes=5)
print(time1 - time2)
This gave me "-1 day, 23:54:59.999987".
Try 2 - Worked, but is there a better way?:
time1 = datetime.now()
time2 = datetime.now() + timedelta(minutes=5)
print(str(time1 - time2).split(',')[1])
This gave me the desired result, but is there a method besides string manipulation?
You wanted to take an advice how to use a time object?
Well, if you want to specify a format of string representation of your time, just use strftime
Example below:
from datetime import datetime, timedelta
time1 = datetime.now()
time2 = datetime.now() + timedelta(minutes=5)
print((time1 - time2).strftime('%H:%M:%S'))
Assuming you want the time 5 minutes ago, you can use timedelta without any string manipulation:
five_min_ago = datetime.datetime.now() - datetime.timedelta(minutes = 5)
I have times which are in the form of seconds since the start of the Unix epoch. For example, 1410974864 which is Wed, 17 Sep 2014 17:27:44 GMT .
How can I find the start and end of the day for a given time in this form?
datetime and pytz are a good team for that:
import datetime, pytz
epoch = 1410974864
dt_epoch = datetime.datetime.fromtimestamp(epoch, tz=pytz.UTC)
dt_midnight = dt.replace(hour=0, minute=0, second=0, microsecond=0)
So, the beginning and end of day:
day_start = dt_midnight
day_end = dt_midnight + datetime.timedelta(days=1)
You know that a day is 3600 seconds/hour * 24 hours = 86400 seconds. So just take the time you have and mod it by 86400:
seconds_through_current_day = current_time % 86400
Now you have how many seconds have elapsed since the beginning of the day so subtract this from the total time since epoch and you'll be left with the beginning of the current day
beginning_of_current_day = current_time - second_through_current_day
Lastly, just add a day's worth of seconds to get the end of the current day
end_of_current_day = beginning_of_current_day + 86400