taichino / croniter

croniter is a python module to provide iteration for datetime object.
http://github.com/taichino/croniter
387 stars 105 forks source link

get_prev() introduces side effects leading to different behaviour of get_current() #113

Closed asyncee closed 6 years ago

asyncee commented 6 years ago

Hello.

I have noticed strange behaviour, please see example below:

import datetime as dt

from croniter import croniter

now = dt.datetime.now()
iter = croniter("* * * * *", now)

print("now", now)
print("prev", iter.get_prev(dt.datetime))  # calling get_prev modifies self.cur on croniter instance
print("current", iter.get_current(dt.datetime))  # this calculates against mutated self.cur
print("next", iter.get_next(dt.datetime))

# Output:
# now 2018-08-23 11:58:58.215918
# prev 2018-08-23 11:58:00
# current 2018-08-23 11:58:00 → this result is equal to previous; seconds and microseconds are truncated
# next 2018-08-23 11:59:00

now = dt.datetime.now()
iter = croniter("* * * * *", now)

print("now", now)
# print("prev", iter.get_prev(dt.datetime))  → this line is commented and self.cur is not mutated
print("current", iter.get_current(dt.datetime))
print("next", iter.get_next(dt.datetime))

# Output:
# now 2018-08-23 12:01:08.365190
# current 2018-08-23 12:01:09.365190  → seconds and microseconds are not truncated
# next 2018-08-23 12:02:00

Is this intended behaviour or a bug?

kiorky commented 6 years ago

Its intended to truncate the iterated datetime for prev calculations to remove any possibibly of double executions. Remember that cron has a target of minute precision, microsecond variation doesnt put you in any border case. If your program is sensible to microseconds, and as far as i see, the simplest way to keep Zero microseconds if to simply do a iter.replace(microseconds=0) wherever you have not to be sensible to microseconds variations, 2018-08-23 12:01:09.365190 without microseconds == 2018-08-23 12:01:09 ;)

asyncee commented 6 years ago

Thanks!