Search code examples
pythonstringunit-testingdatetime

Unexpected millisecond offsets when doing subtraction with datetime and timedelta objects


I have this class implemented in python on which i am performing some unitests

from datetime import datetime, timedelta

class FreeTime:
    """Range in a timeframe where a task can be located"""

    def __init__(self, start: datetime, end: datetime) -> None:
        self.start = start
        """ start of the freetime """

        self.end = end
        """ end of the freetime """

        self.duration = end - start
        """ duration of the freetime"""

    def set_start(self, start: datetime):
        self.start = start
        self.duration = self.end - self.start

    def set_duration(self, duration: timedelta):
        self.duration = duration
        self.start = self.end - self.duration

    def __repr__(self) -> str:
        return f"FreeTime - {self.start} -> {self.end} - {self.duration}"

The test looks like this:

from datetime import datetime, timedelta

def test_FreeTime():
    """test the FreeTime class"""

    start = datetime.now()
    end = start + timedelta(hours=4.0)

    free_time = FreeTime(start=start, end=end)
    assert free_time.start == start
    assert free_time.end == end
    assert free_time.duration == end - start

    start_2 = datetime.now() + timedelta(hours=1.0)

    free_time.set_start(start_2)
    assert free_time.start == start_2
    assert free_time.duration == end - start_2

    delta = timedelta(hours=3.0)
    free_time.set_duration(delta)
    assert free_time.duration == timedelta(hours=3.0)
    assert free_time.start == end - delta

    assert str(free_time) == f"FreeTime - {start_2} -> {end} - {delta}"

Strangely when I run the test I get some variant of this assertion error, (some variant meaning the millisecond difference):

assert str(free_time) == f"FreeTime - {start_2} -> {end} - {delta}"
E       AssertionError: assert 'FreeTime - 2...544 - 3:00:00' == 'FreeTime - 2...544 - 3:00:00'
E         - FreeTime - 2023-01-04 21:54:27.421567 -> 2023-01-05 00:54:27.421544 - 3:00:00
E         ?                                    ^^
E         + FreeTime - 2023-01-04 21:54:27.421544 -> 2023-01-05 00:54:27.421544 - 3:00:00
E         ?                                    ^^

However I dont get how or where the difference in millisecond comes from, since all previous assertion tests pass wiht out errors. It alwasy failes on this assertion but the offset is different every time.

I allready tried instantiatiating all timedelata objects whith floats instead of int, but this did not have any effect.


Solution

  • Yes - Based on @homer512 's input, change your test class to be

    from datetime import datetime, timedelta
    
    def test_FreeTime():
        """test the FreeTime class"""
    
        start = datetime.now()
        end = start + timedelta(hours=4.0)
    
        free_time = FreeTime(start=start, end=end)
        assert free_time.start == start
        assert free_time.end == end
        assert free_time.duration == end - start
    
        start_2 = start + timedelta(hours=1.0)
    
        free_time.set_start(start_2)
        assert free_time.start == start_2
        assert free_time.duration == end - start_2
    
        delta = timedelta(hours=3.0)
        free_time.set_duration(delta)
        assert free_time.duration == timedelta(hours=3.0)
        assert free_time.start == end - delta
    
        assert str(free_time) == f"FreeTime - {start_2} -> {end} - {delta}"