Python datetime countdown miscalculates remaining time - python

delta = datetime.now() - datetime(2020, 3, 24)
yeardif = round(delta.days/365)
yearRem = round(delta.days%365)
mondif = round(yearRem/30)
daydif = round(delta.days%365%30)
The code is for a countdown timer. Variable "delta" should output the time difference in days using
.days
but something about the equation is wrong because the output is incorrect.

If you are looking at time differences in terms of time remaining you wouldn‘t want to round your values but rather use floor() instead.

The code is for a countdown timer. Variable "delta" should output the time difference in days using .days
If you just want the time difference in days this is all you need:
delta = datetime.now() - datetime(2020, 3, 24)
days = delta.days + delta.seconds / 86400
This will give you 13.35866 days (13 whole days, plus 0.35866 days). This is preferable to dividing by 30 and 365 since this method accounts for differing days per month and leap years.

Related

Trying to find the difference between 2 datetime objects and getting only Hours, Minutes, and Seconds [duplicate]

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

Why is the diff of two datetime objects so?

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

How do I calculate year fraction from datetime objects in Python?

I have two dates expressed as datetime objects and trying to calculate the time between the two dates in fractions of years (equivalent to the Excel yearfrac function).
Using relativedelta I can get the number of years, number of months and number of days between the dates, but not the fraction of years, and I can also subtract the dates to get the number of days, but dividing by 365.25 doesn't seem to get me the answer I would expect.
start_date = dt.datetime(2010, 12, 31)
end_date = dt.datetime(2019, 5, 16);
delta = relativedelta(end_date, start_date);
print(delta)
This is the output I get:
relativedelta(years=+8, months=+4, days=+16)
What I am looking for is: 8.38
If I use the following code:
delta = (end_date - start_date)/365.25
print(delta)
I get output of:
8 days, 8:56:10.841889
I just did the math of 8 + ((months * 30) + days)/365 = 8.3726. This is assuming 30 days in all months and 365 days in a year. Less precise but can fit on one line. What do you get when you divide by the number 365.25 that makes it wrong? How precise does it have to be?
If you need absolute precision, I would simply do:
from datetime import date
d0 = date(2010, 12, 31)
d1 = date(2019, 5, 16)
delta = d1 - d0
delta_fraction = delta.days/365.25
print(delta_fraction)
# Output: 8.72348
EDIT
This is a simplified solution assuming 365.25 days in a year (you can use 365.2425 days to be accurate up to the 400 year exception) to account for leap years. If you require it to match exactly excel's output, your probably better off writing a vba macro for excel
One thing to remember is that datetime.datetime objects have the subtraction operator defined, returning a datetime.timedelta object. And datetime.timedelta objects have the division operator defined, so you can get a ratio between a timedelta and either a common year (365 days) or the average length of all common and leap years (365 days, 5 hours, 49 minutes and 12 seconds).
import datetime as dt
start_date = dt.datetime(2010, 12, 31)
end_date = dt.datetime(2019, 5, 16)
print(round((end_date-start_date)/dt.timedelta(365,0,0,0),2)) #8.38
print(round((end_date-start_date)/dt.timedelta(365,5,49,12),2)) #8.38

Calculating the date a fixed number of days from given date [duplicate]

This question already has answers here:
Days between two dates? [duplicate]
(4 answers)
Closed 5 years ago.
I need to design a code that will automatically generate the date X number of days from current date.
For that, I currently have a function that returns an epoch timestamp, which I then add the fixed number of days in seconds. However, I am currently stuck there and do not know how to convert the epoch timestamp into a Gregorian calendar date format (DD/MM/YYYY HH:MM). Displaying time is optional, can be rounded to the nearest day.
A way to do this without using an epoch timestamp and directly getting the current date in a readable format, printing it, and adding X days to it before generating the second date, is also fine, but I have no idea how that would work.
Any help/input would be much appreciated. Thanks in advance.
You can use timedelta.
import datetime as dt
x = 5 # Days offset.
now = dt.datetime.now()
>>> now + dt.timedelta(days=x)
datetime.datetime(2017, 12, 2, 21, 10, 19, 290884)
Or just using days:
today = dt.date.today()
>>> today + dt.timedelta(days=x)
datetime.date(2017, 12, 2)
Easy enough to convert back to a string using strftime:
>>> (today + dt.timedelta(days=x)).strftime('%Y-%m-%d')
'2017-12-02'
import datetime
x = 5
'''
Date_Time = datetime.datetime.now()#It wil give Date & time both
Time = datetime.datetime.now().time()#It will give Time Only
'''
Date = datetime.datetime.now().date()#It will give date only
print(Date + datetime.timedelta(days=x))#It will add days to current date
Output:
2017-12-03

dateutil.relativedelta - How to get duration in days?

I wish to get the total duration of a relativedelta in terms of days.
Expected:
dateutil.timedelta(1 month, 24 days) -> dateutil.timedelta(55 days)
What I tried:
dateutil.timedelta(1 month, 24 days).days -> 24 (WRONG)
Is there a simple way to do this? Thanks!
This one bothered me as well. There isn't a very clean way to get the span of time in a particular unit. This is partly because of the date-range dependency on units.
relativedelta() takes an argument for months. But when you think about how long a month is, the answer is "it depends". With that said, it's technically impossible to convert a relativedelta() directly to days, without knowing which days the delta lands on.
Here is what I ended up doing.
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
rd = relativedelta(years=3, months=7, days=19)
# I use 'now', but you may want to adjust your start and end range to a specific set of dates.
now = datetime.now()
# calculate the date difference from the relativedelta span
then = now - rd
# unlike normal timedelta 'then' is returned as a datetime
# subtracting two dates will give you a timedelta which contains the value you're looking for
diff = now - then
print diff.days
Simple date diff does it actually.
>>> from datetime import datetime
>>> (datetime(2017, 12, 1) - datetime(2018, 1, 1)).days
-31
To get positive number You can swap dates or use abs:
>>> abs((datetime(2017, 12, 1) - datetime(2018, 1, 1)).days)
31
In many situations you have a much restricted relativedelta, in my case, my relativedelta had only relative fields set (years, months, weeks, and days) and no other field. You may be able to get away with the simple method.
This is definitely off by few days, but it may be all you need
(365 * duration.years) + (30 * duration.months) + (duration.days)

Categories

Resources