I implemented a datetime.datetime to decimal year (year fraction) converter based on a previous answer. I am not getting the expected results but I can't find the bug.
from datetime import datetime, timedelta
def decimal_year_to_datetime(decimal_year_float):
year = int(decimal_year_float)
remain = decimal_year_float - year
base = datetime(year, 1, 1)
whole_year_time_delta = (base.replace(year=base.year + 1) - base)
fractional_seconds = whole_year_time_delta.total_seconds() * remain
our_time_delta = timedelta(seconds=fractional_seconds)
result = base + our_time_delta
return result
def test_conversion():
year = 2013
month = 1
day = 1
hour = 2
minute = 16
second = 48
date = datetime(year=year, month=month, day=day)
fraction_of_the_day = (hour + (minute + second / 60.0) / 60.0) / 24.
days_in_year = (date.replace(year=date.year + 1) - date).days
dec_yr = year + (date.timetuple().tm_yday +
fraction_of_the_day) / float(days_in_year)
expect_date = datetime(year=year, month=month, day=day,
hour=hour, minute=minute, second=second)
got_date = decimal_year_to_datetime(dec_yr)
assert(got_date == expect_date)
if __name__ == '__main__':
test_conversion()
I seem to be a day (an and a fraction of a second) off with my conversion. But I cannot see the bug.
Have I missed something obvious?
You're out by one day (a classic fencepost error!) because, although we consider 1st January to to be day one of the year, in computing terms that's the zeroth day. The simplest fix is to add in a - 1, but your approach seems generally quite complex; I would do it as follows:
def dt_to_dec(dt):
"""Convert a datetime to decimal year."""
year_start = datetime(dt.year, 1, 1)
year_end = year_start.replace(year=dt.year+1)
return dt.year + ((dt - year_start).total_seconds() / # seconds so far
float((year_end - year_start).total_seconds())) # seconds in year
In use:
>>> dec = dt_to_dec(datetime(2013, 1, 1, 2, 16, 48))
>>> dec
2013.0002602739726
>>> decimal_year_to_datetime(dec)
datetime.datetime(2013, 1, 1, 2, 16, 47, 999999)
(given floating point accuracy, that's as close as you're likely to get...)
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