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_next and `get_prev` return wrong time across DST boundary when schedule is for a specific time. #116

Closed liammeck closed 4 years ago

liammeck commented 5 years ago

I saw someone else commenting on the same problem here: https://github.com/taichino/croniter/issues/90 This seems to be a separate issue so I created this, but sorry if you consider it a duplicate.

Here's a simple example showing the problem. Schedule is 8 am on weekdays; US DST ends Nov. 4 at 2 am.

>>> foo
datetime.datetime(2018, 11, 4, 5, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> cr = croniter.croniter('0 8 * * 1,2,3,4,5', foo)
>>> cr.get_prev(datetime)
datetime.datetime(2018, 11, 2, 9, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> cr.get_prev(datetime)
datetime.datetime(2018, 11, 2, 8, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> cr.get_prev(datetime)
datetime.datetime(2018, 11, 1, 8, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> cr.get_next(datetime)
datetime.datetime(2018, 11, 2, 8, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> cr.get_next(datetime)
datetime.datetime(2018, 11, 5, 7, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> cr.get_prev(datetime)
datetime.datetime(2018, 11, 2, 9, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)

Notice it gives 9:00 instead of 8:00, then when we go forward across the DST boundary again it gives 7:00.

A couple more examples:

>>> foo
datetime.datetime(2018, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
>>> cr = croniter('0 8 * * *', foo)
>>> cr.get_next(datetime)
datetime.datetime(2018, 11, 4, 7, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> foo
datetime.datetime(2018, 11, 4, 7, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> cr = croniter('0 8 * * *', foo)
>>> cr.get_prev(datetime)
datetime.datetime(2018, 11, 3, 9, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
kiorky commented 4 years ago

dup #90