I'm working through Exercism.io gigasecond problem:
"Calculate the moment when someone has lived for 10^9 seconds."
My method was to convert the datetime input to a timestamp, add 10**9, then convert back. My answers are very close, but the test suite (provided by Exercism) fails because the hour arg is off by one. All other args are correct.
After a bit of searching, I found an answer that uses timedelta; the structure of the answer is almost identical to mine, but it generates the full correct answer.
My question is, why is there a difference in the output of these two methods? As you can see below, the problem only manifests when the input arg for hour is the default value of 0.
Code:
def add_gigasecond(birth_date):
gigadate = birth_date.timestamp() + 10**9
print(datetime.fromtimestamp(gigadate).__repr__())
gigadate = birth_date + timedelta(seconds=10**9)
print(gigadate.__repr__())
Inputs:
tests = [datetime(2011, 4, 25),
datetime(1977, 6, 13),
datetime(1959, 7, 19),
datetime(2015, 1, 24, 22, 0, 0),
datetime(2015, 1, 24, 23, 59, 59),]
Results:
test 1
datetime.datetime(2043, 1, 1, 0, 46, 40)
datetime.datetime(2043, 1, 1, 1, 46, 40)
test 2
datetime.datetime(2009, 2, 19, 0, 46, 40)
datetime.datetime(2009, 2, 19, 1, 46, 40)
test 3
datetime.datetime(1991, 3, 27, 0, 46, 40)
datetime.datetime(1991, 3, 27, 1, 46, 40)
test 4
datetime.datetime(2046, 10, 2, 23, 46, 40)
datetime.datetime(2046, 10, 2, 23, 46, 40)
test 5
datetime.datetime(2046, 10, 3, 1, 46, 39)
datetime.datetime(2046, 10, 3, 1, 46, 39)
As you can see, the top answer in each test (using timestamps) is off by 1, for all inputs where year, month, date are specified. The correct answer is achieved when the hour, minute, second, and microsecond args are included in the input.
You can also find the difference between two datetime objects to get a timedelta object and perform the comparison based on the positive or negative value returned by the timedelta. total_seconds() function. if seconds < 0: print('First date is less than the second date.
A timedelta object represents a duration, the difference between two dates or times. All arguments are optional and default to 0 . Arguments may be integers or floats, and may be positive or negative. Only days, seconds and microseconds are stored internally.
Subtracting the later time from the first time difference = later_time - first_time creates a datetime object that only holds the difference.
Timedeltas are differences in times, expressed in difference units, e.g. days, hours, minutes, seconds. They can be both positive and negative. Timedelta is a subclass of datetime.
Daylight Savings
Some detective work can shed light on these problems. For this investigation, I pick the first date in your list, 25-Apr-2011.
from datetime import datetime, timedelta
def add_seconds(birth_date, n):
x = datetime.fromtimestamp(birth_date.timestamp() + n)
y = birth_date + timedelta(seconds=n)
return (x, y)
for i in range(365):
ts, td = add_seconds(datetime(2011, 4, 25), i*60**2*24) # add i days via seconds
if ts-td: # test for difference in timestamp vs timedelta methods
print(i, ts, td)
break
Result:
189 2011-10-30 23:00:00 2011-10-31 00:00:00
As you can see, there is a discrepancy on exactly 30th October. This is, for many countries, the second date in the year where we see a daylight savings adjustment.
Update: A similar question is asked here: Difference between evaluating timestamp and total_seconds. The underlying reason for the difference is that datetime.timedelta
does not take into account DST, while timestamp
does take this into account.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With