0

I'm working on a simple Python3 script that considers data in five-minute increments. Thanks to this post, I have code which takes any Python datetime object and then rounds it down to the nearest five minutes. (:00, :05, :10, :15, etc.) Note that I cannot use pandas.

Now I need to be able to compare that "rounded-down" datetime with other datetimes, and here I'm running into a problem. Consider this test code:

import sys
from datetime import datetime
from datetime import timedelta

def roundDownDateTime(dt):
    # Arguments:
    #   dt      datetime object
    delta = timedelta(minutes=1) * (dt.minute % 5)
    return dt - delta

def testAlarm(testDate):
    # Arguments:
    #   testDate    datetime object
    currDate = roundDownDateTime( datetime.now() )      # currDate is a DateTime object, rounded down to 5 mins
    print("currDate:  "+currDate.strftime("%Y%m%d%H%M"))
    print("testDate:  "+testDate.strftime("%Y%m%d%H%M"))
    if(currDate == testDate):
        print("ALARM!!!!")

def main():
    testDate = datetime.strptime(sys.argv[1], "%Y%m%d%H%M")
    testAlarm(testDate)

if __name__ == "__main__":
    main()

The code does all of the following:

  • The main() function takes a string you enter on the command line, then converts it into a "%Y%m%d%H%M" datetime
  • Your datetime is rounded down to the last five minute increment
  • In testAlarm(), your date is compared with the current date, also in "%Y%m%d%H%M" format, also rounded down five minutes.
  • If the current date matches the cmd line argument, you should get an "ALARM!!! in the output.

Here's the actual output, run on my Ubuntu machine:

me@unbuntu1$ date
Tue Jan 17 14:27:41 UTC 2023
me@unbuntu1$ 
me@unbuntu1$ python3 toy04.py 202301171425
currDate:  202301171425
testDate:  202301171425
me@unbuntu1$

Okay: Although I'm rounding down my date to match the "rounded-down" version of the current date, the if(currDate == testDate): line of code is still evaluating to False. While both datetimes appear equal in the "%Y%m%d%H%M" format, they are somehow not equal.

My first thought was that maybe the "rounded down" datetime still retained some residual seconds or microseconds even after the rounding part? So I modified my function to this:

def roundDownDateTime(dt):
    # Arguments:
    #   dt      DateTime object
    delta = timedelta(minutes=1) * (dt.minute % 5)
    dt = dt - delta
    dt.replace(second=0, microsecond=0)
    return dt

But that makes no difference; I still get the exact same output as before.

Normally, you would only care if currDate > testDate for alarming purposes. But in my case, I must be able to compare datetimes for equality after one (or more) of them has been through the roundDownDateTime() function. What am I missing? Is my roundDownDateTime() function faulty? Thank you.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Pete
  • 1,511
  • 2
  • 26
  • 49
  • 1
    Most likely this is a floating point rounding error – mousetail Jan 17 '23 at 14:57
  • 3
    https://docs.python.org/3/library/datetime.html#datetime-objects - check if one of them isn't naive. According to docs, "For equality comparisons, naive instances are never equal to aware instances." – matszwecja Jan 17 '23 at 14:59
  • 2
    You are printing the `strftime` but comparing the datetime object for `currDate`, which are not equal because of the decimals. – It_is_Chris Jan 17 '23 at 15:02
  • @It_is_Chris That's a great point, probably the source of my confusion. What's the recommended way to print datetime's, I wonder? – Pete Jan 17 '23 at 15:09

1 Answers1

4

dt.replace returns a new datetime object; it does not modify dt in place.

def roundDownDateTime(dt):
    # Arguments:
    #   dt      DateTime object
    delta = timedelta(minutes=1) * (dt.minute % 5)
    dt = dt - delta
    return dt.replace(second=0, microsecond=0)
chepner
  • 497,756
  • 71
  • 530
  • 681