8

I have got into an issue or might quite possibly feature in turn! Not sure, wondering!! In python's datetime library, to get difference in time, as in below snippet.

>>> import datetime
>>> datetime.datetime.now() - datetime.datetime.now()
datetime.timedelta(-1, 86399, 999958)
>>> tnow = datetime.datetime.now()
>>> datetime.datetime.now() - tnow
datetime.timedelta(0, 4, 327859)

I would like to understand why datetime.datetime.now() - datetime.datetime.now() is producing output as -1 days, 86399 seconds whereas assigning current time to some variable and computing difference gives desired output 0 days, 4 seconds.

The results seems to be bit confusing, it would be helpful if someone could decode whats going behind

Note: I'm using Python 2.7

  • the first statement gives datetime.now - datetime.now which is like 15:55 - 15:55. I don't know what it should return but it isn't what you want I assume. the second one records the time of when a variable is set then gets the time now vs that time. not sure why it would return 4 seconds though... 4 seconds to go through datetime.now - tnow? – L_Church Feb 20 '18 at 10:05
  • 1
    `datetime.datetime.now() - datetime.datetime.now()` returns `datetime.timedelta(0)`. I can think of an explanation... how slow is your machine? I'd bet you can't reproduce it every time you want. – CristiFati Feb 20 '18 at 10:07
  • 1
    Looks like it only happens in python 2. In python 3, I get `datetime.timedelta(0)` – pe-perry Feb 20 '18 at 10:08
  • problem solved: its the python versioning. python 2.x gives bad output for datetime.now - datetime.now but python 3.x is fine – L_Church Feb 20 '18 at 10:08

2 Answers2

7

From the documentation for timedelta objects:

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)

This occurs in both Python 2.7 and Python 3.

The reason for the observed result is simple:

a , b = datetime.datetime.now(), datetime.datetime.now()
# here datetime.now() in a will be <= b.
# That is because they will be executed separately at different CPU clock cycle.

a - b
# datetime.timedelta(-1, 86399, 999973)

b - a
# datetime.timedelta(0, 0, 27)

To get the proper time difference:

(tnow - datetime.datetime.now()).total_seconds()
# output: -1.751166

See also Python timedelta issue with negative values.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Vikash Singh
  • 13,213
  • 8
  • 40
  • 70
2

You are encountering a "corner case" situation.

  • Every datetime.datetime.now() produces a datetime.datetime object ([Python]: https://docs.python.org/3/library/datetime.html#datetime-objects), which is the current date & time at the moment the call was made
  • You have 2 such calls (even if they are on the same line). Since the CPU speeds are very high nowadays, every such call takes a very small amount of time (much less than microseconds, I presume)
  • But, when the 1st call is at the very end of a (microsecond?) period, and the 2nd one is at the beginning of the next one, you'd get this behavior:
>>> import datetime

>>> now0 = datetime.datetime.now()
>>> now0
datetime.datetime(2018, 2, 20, 12, 23, 23, 1000)
>>> delta = datetime.timedelta(microseconds=1)
>>> now1 = now0 + delta
>>> now0 - now1
datetime.timedelta(-1, 86399, 999999)

Explanation:

  • Let now0 to be the result of the 1st call made to datetime.datetime.now()
  • Let's say that the 2nd datetime.datetime.now() call happens one microsecond later (I am reproducing the behavior using the delta object, as the times involved here are waaay too small for me to be able to to run the line at the exact time when this behavior is encountered). That is placed into now1
  • When subtracting them you get the negative value (in my case is -delta), since now0 happened earlier than now1 (check [Python]: timedelta Objects for more details)
CristiFati
  • 38,250
  • 9
  • 50
  • 87