datetime1 = '2020-08-19 10:13:19'
datetime2 = '2020-08-19 19:00:00'
diff = datetime1 - datetime2
The diff is a timedelta object, with:
diff.days = -1
diff.seconds = 54766 = 15.22 hours
There are only about 9 hours diff between the two datetimes. Why does it show the number of days is '1' and 15.22 hours? How to understand the diff of two datetimes?
If you subtract the earlier datetime from the later datetime, you get a positive timedelta, as one would expect.
The other way around, you get a negative timedelata in the unusual format.
But when you calculate -1 day + 15 hours = -24 hours + 15 hours = -9 hours, the result is correct.
Of course, doing this calculation manually is not what we want.
So, either avoid subtracting a later datetime from an earlier datetime:
# to get an absolute timedelta
if datetime2 > datetime1:
print(datetime2 - datetime1)
else:
print(datetime1 - datetime2)
Or use .total_seconds():
print((datetime1 - datetime2).total_seconds())
-31601.0
print((datetime2 - datetime1).total_seconds())
31601.0
In this example, the difference between two datetime objects has a negative number of days, and a positive number of hours.
import datetime
datetime1 = datetime.datetime.fromisoformat('2020-08-19 10:13:19')
datetime2 = datetime.datetime.fromisoformat('2020-08-19 19:00:00')
print(datetime1 - datetime2)
-1 day, 15:13:19
# divide by timedelta() (with argument of hours, minutes, seconds, etc.
print((datetime1 - datetime2) / datetime.timedelta(hours=1)) # in hours
-8.778055555555556
Here is an interesting interview with the core developer who maintains date / time in CPython: https://talkpython.fm/episodes/show/271/unlock-the-mysteries-of-time-pythons-datetime-that-is
UPDATE
You can calculate time difference in minutes, or days, or other units, by supplying a different parameter to .timedelta():
print((datetime1 - datetime2) / datetime.timedelta(minutes=1)) # in minutes
-526.68
print((datetime1 - datetime2) / datetime.timedelta(days=1)) # in days
-0.3658
Related
This question already has answers here:
Convert timedelta to total seconds
(4 answers)
Closed 27 days ago.
I am pulling an ending time from a json api response. Then I am trying to calculate the time remaining, before the end time, to call a function after it ends.
end_time_string = data['endTime'] # Get the end time in a string in weird format
date_format = "%Y%m%dT%H%M%S.%fZ" # Specify the date format for the datetime parser
end_time = datetime.strptime(end_time_string, date_format) # turn the date time string into datetime object
current_time = datetime.utcnow() # Get current time in UTC time zone, which is what CoC uses.
time_remaining = end_time - current_time # Get the time remaining till end of war
My end_time is a datetime object. My current_time is a datetime object. But time_remaining is a timedelta object. I am able to pull the hours, minutes and seconds from the object using:
hours, minutes, seconds = map(float, str(time_remaining).split(':'))
But the problem is that sometimes the time_remaining has days in it, and sometimes it doesn't.
1 day, 4:55:22.761359
-1 days, 23:59:08.45766
When there are days involved, specifically when the timedelta object goes negative, my script fails.
What is the best find the amount of time between my two datetime objects in ONLY hours, minutes, and seconds, without days included?
timedelta is an object. One of its methods is total_seconds() so dividing by 3600 gives hours. Also dividing by another timedelta gives a float result of the ratio, so divide by timedelta(hours=1) to get the time in hours:
>>> import datetime as dt
>>> x = dt.timedelta(days=1, seconds=5000)
>>> x.total_seconds() / 3600
25.38888888888889
>>> x / dt.timedelta(hours=1)
25.38888888888889
or in hours, minutes, seconds:
>>> hours, remaining_seconds = divmod(x.total_seconds(), 3600)
>>> minutes, seconds = divmod(remaining_seconds, 60)
>>> hours, minutes, seconds
(25.0, 23.0, 20.0)
So, a timedelta object has days, seconds and microseconds. Multiply the days by 24 to convert it into hours, and then some nice math with modulo (%) and the usefull // operator, for which I will quote something:
//: Divides the number on its left by the number on its right, rounds
down the answer, and returns a whole number.
combining everything you get a nice f-string with padding for the zeros:
f"{td.seconds//3600 + td.days*24:02}:{(td.seconds//60)%60:02}:{td.seconds%60:02}:{td.microseconds:06}"
To put this into code:
from datetime import datetime, timedelta
# 3670 seconds is 1h1m10s
tomorrow = datetime.utcnow() + timedelta(1, 3670, 123)
current_time = datetime.utcnow()
td = tomorrow - current_time
print(td)
print(td.days)
print(td.seconds)
print(td.microseconds)
print(f"{td.seconds//3600 + td.days*24:02}:{(td.seconds//60)%60:02}:{td.seconds%60:02}:{td.microseconds:06}")
Which generates the following output:
1 day, 1:01:10.000123
1
3670
123
25:01:10:000123
I get this strange result by substracting earlier time stamp for later one:
pd.to_datetime('2021-05-21 06:00:00') - pd.to_datetime('2021-05-21 06:02:00')
Output:
Timedelta('-1 days +23:58:00')
Expected Output:
Timedelta('-0 days 00:02:00')
What is the correct way to calculate a negative time difference? Thank you!
Timedelta('-1 days +23:58:00') is the proper representation of a negative time difference in pandas (and also in pure python)
# using pure python
from datetime import datetime
datetime(2021,5,21,6,0,0) - datetime(2021,5,21,6,2,0)
datetime.timedelta(days=-1, seconds=86280)
this is because the difference is properly calculated as -120 seconds, but individual time elements cannot exceed their moduli. the timedelta components are normalized. To represent negative 2 minutes, a negative day & positive time component are used.
from the python datetime module's documentation
and days, seconds and microseconds are then normalized so that the representation is unique, with
0 <= microseconds < 1000000
0 <= seconds < 3600*24 (the number of seconds in one day)
-999999999 <= days <= 999999999
Note that normalization of negative values may be surprising at first. For example:
from datetime import timedelta
d = timedelta(microseconds=-1)
(d.days, d.seconds, d.microseconds)
(-1, 86399, 999999)
it is possible to retrieve the total seconds as a negative integer using the method Timedelta.total_seconds
We can do total_seconds
(pd.to_datetime('2021-05-21 06:00:00') - pd.to_datetime('2021-05-21 06:02:00')).total_seconds()
Out[9]: -120.0
Use abs to get the time delta:
>>> abs(pd.to_datetime('2021-05-21 06:00:00') - pd.to_datetime('2021-05-21 06:02:00'))
Timedelta('0 days 00:02:00')
Well your code is giving correct output ...
Your result is Timedelta('-1 days +23:58:00') which is equal to -24:00:00 + 23:58:00 => 2 mins
you can use np.timedelta64 to change the time delta to your desired output
as others have said, the pandas negative Timedelta object is the correct output in python.
import numpy as np
delta = pd.to_datetime('2021-05-21 06:00:00') - pd.to_datetime('2021-05-21 06:02:00')
print(delta)
Timedelta('-1 days +23:58:00')
#minutes
print(delta / np.timedelta64(1,'m')
-2.0
#seconds
delta / np.timedelta64(1,'s')
-120.0
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 2 times stored in separate strings in the form of H:M I need to get the difference between these two and be able to tell how much minutes it equals to. I was trying datetime and timedelta, but I'm only a beginner and I don't really understand how that works. I'm getting attribute errors everytime.
So I have a and b times, and I have to get their difference in minutes.
E.G. if a = 14:08 and b= 14:50 the difference should be 42
How do I do that in python in the simplest way possible? also, in what formats do I need to use for each step?
I assume the difference is 42, not 4 (since there are 42 minutes between 14:08 and 14:50).
If the times always contains of a 5 character length string, than it's reasonably easy.
time1 = '14:08'
time2 = '15:03'
hours = int(time2[:2]) - int(time1[:2])
mins = int(time2[3:]) - int(time1[3:])
print(hours)
print(mins)
print(hours * 60 + mins)
Prints:
1
-5
55
hours will be the integer value of the left two digits [:1] subtraction of the second and first time
minutes will be the integer value of the right two digits [3:] subtraction of the second and first time
This prints 55 ... with your values it prints out 42 (the above example is to show it also works when moving over a whole hour.
You can use datetime.strptime
also the difference is 42 not 4 50-8==42 I assume that was a typo
from datetime import datetime
a,b = "14:08", "14:50"
#convert to datetime
time_a = datetime.strptime(a, "%H:%M")
time_b = datetime.strptime(b, "%H:%M")
#get timedelta from the difference of the two datetimes
delta = time_b - time_a
#get the minutes elapsed
minutes = (delta.seconds//60)%60
print(minutes)
#42
You can get the difference between the datetime.timedelta objects created from the given time strings a and b by subtracting the former from the latter, and use the total_seconds method to obtain the time interval in seconds, with which you can convert to minutes by dividing it by 60:
from datetime import timedelta
from operator import sub
sub(*(timedelta(**dict(zip(('hours', 'minutes'), map(int, t.split(':'))))) for t in (b, a))).total_seconds() // 60
So that given a = '29:50' and b = '30:08', this returns:
18.0
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)