Repository navigation
Adding/subtracting when there's a change on DST #59
Description
Activity
You are right, this is (well was 😃 ) an undesired behavior.
I just pushed a fix (660c6b9) on the
masterbranch.Basically, pendulum will now treat years, months, weeks and days as whole units and will not apply the transition but only set the proper timezone. Even if you combine it with other units (hours, minutes, seconds and microseconds).
Let's take an example:
import pendulum dt = pendulum.create(2016, 2, 20, 22, tz='America/Sao_Paulo') # <Pendulum [2016-02-20T22:00:00-02:00]> # Let's add 3 hours (we will stumble across the DST transition) dt.add(hours=3) # <Pendulum [2016-02-21T00:00:00-03:00]> # Let's add 1 day # (the transition has occurred but we won't apply it (i.e. remove one hour)) dt.add(days=1) # <Pendulum [2016-02-21T22:00:00-03:00]> # But the difference will actually be 25 hours dt.add(days=1).diff(dt).in_hours() # 25
As for your initial example:
>>> pendulum.parse("2016-01-12", tz="America/Sao_Paulo").add(months=4) # <Pendulum [2016-05-12T00:00:00-03:00]> >>> pendulum.parse("2016-01-30", tz="America/Sao_Paulo").add(months=4) # <Pendulum [2016-05-30T00:00:00-03:00]>
Blazingly fast! =)
I installed the git tip to try that commit, and I've found something perhaps related to the date adding/subtracting (I'm using IPython):
In [1]: import pendulum In [2]: # Change the string format just to avoid some undesired coloring on GitHub In [3]: pendulum.set_to_string_format("'%Y-%m-%d %H:%M:%S %_z'") In [4]: dt = pendulum.parse("2016-01-30", tz="America/Sao_Paulo") In [5]: p = dt.add(months=4) - dt In [6]: p.range("months") Out[6]: [<Pendulum ['2016-01-30 00:00:00 -02:00']>, <Pendulum ['2016-02-29 00:00:00 -03:00']>, <Pendulum ['2016-03-29 00:00:00 -03:00']>, <Pendulum ['2016-04-29 00:00:00 -03:00']>, <Pendulum ['2016-05-29 00:00:00 -03:00']>]
The period range seem to get the previous output to add, instead of using its
p.startvalue. I was expecting the result above to be like this:In [7]: [dt.add(months=m) for m in range(5)] Out[7]: [<Pendulum ['2016-01-30 00:00:00 -02:00']>, <Pendulum ['2016-02-29 00:00:00 -03:00']>, <Pendulum ['2016-03-30 00:00:00 -03:00']>, <Pendulum ['2016-04-30 00:00:00 -03:00']>, <Pendulum ['2016-05-30 00:00:00 -03:00']>]
That shouldn't make any difference when adding time (hours, minutes, seconds, microseconds), but when we're adding dates (days, weeks, months, years) that matters a lot as
some_dt_obj.add(days=1).add(days=1)andsome_dt_obj.add(days=2)might give us different results. The aforementioned range example isn't about DST, but here's an example that propagates something specific to a DST transition:In [8]: my_birthday = pendulum.parse("2016-10-14", tz="America/Sao_Paulo") In [9]: (my_birthday.add(weeks=1) - my_birthday).range("days") Out[9]: [<Pendulum ['2016-10-14 00:00:00 -03:00']>, <Pendulum ['2016-10-15 00:00:00 -03:00']>, <Pendulum ['2016-10-16 01:00:00 -02:00']>, <Pendulum ['2016-10-17 01:00:00 -02:00']>, <Pendulum ['2016-10-18 01:00:00 -02:00']>, <Pendulum ['2016-10-19 01:00:00 -02:00']>, <Pendulum ['2016-10-20 01:00:00 -02:00']>] In [10]: [my_birthday.add(days=d) for d in range(7)] Out[10]: [<Pendulum ['2016-10-14 00:00:00 -03:00']>, <Pendulum ['2016-10-15 00:00:00 -03:00']>, <Pendulum ['2016-10-16 01:00:00 -02:00']>, <Pendulum ['2016-10-17 00:00:00 -02:00']>, <Pendulum ['2016-10-18 00:00:00 -02:00']>, <Pendulum ['2016-10-19 00:00:00 -02:00']>, <Pendulum ['2016-10-20 00:00:00 -02:00']>]
For your first example, I agree that the behavior you expect should be the correct one since if you just do
dt.add(months=4)you will get<Pendulum ['2016-05-30 00:00:00 -03:00']>but this is not the last instance returned byrange().As for you second example, I think
range()should return the second batch of results too.Anyway, the two are related anyway and it should be an easy fix. I will keep you posted about the resolution of this issue.
It should be fixed on the
masterbranch.Wow! Thanks! Now my birthday is in your
test_range_with_dstcode. ^^As
some_dt.start_of("week")callsself.previous, which happens to call thesubtractmethod, the other places where I had seen a similar behavior (namely, thenext,previous,start_ofandend_ofmethods) seem to be fixed together as they call the sameaddandsubtractmethods.I'll be using the git tip until a version bump with this fix gets available. =)
I'm trying to do some maths with dates that results in objects with different DST timezone offsets, e.g.:
That's a behavior that seems undesired. I was expecting that every result had a
00:00:00as I'm adding months, not hours, and I think the day numbers (12and30in the example above) shouldn't be lost (unless I'm trying to move from january to february, but that wasn't the case).