# Timezones Timezones are an important part of every datetime library, and `pendulum` tries to provide an easy and accurate system to handle them properly. !!!note The timezone system works best inside the `pendulum` ecosystem but can also be used with the standard ``datetime`` library with a few limitations. See [Using the timezone library directly](#using-the-timezone-library-directly). ## Normalization When you create a `DateTime` instance, the library will normalize it for the given timezone to properly handle any transition that might have occurred. ```python >>> import pendulum >>> pendulum.datetime(2013, 3, 31, 2, 30, tz='Europe/Paris') # 2:30 for the 31th of March 2013 does not exist # so pendulum will return the actual time which is 3:30+02:00 '2013-03-31T03:30:00+02:00' >>> pendulum.datetime(2013, 10, 27, 2, 30, tz='Europe/Paris') # Here, 2:30 exists twice in the day so pendulum will # assume that the transition already occurred '2013-10-27T02:30:00+01:00' ``` You can, however, control the normalization behavior: ```python >>> import pendulum >>> pendulum.datetime(2013, 3, 31, 2, 30, 0, 0, tz='Europe/Paris', dst_rule=pendulum.PRE_TRANSITION) '2013-03-31T01:30:00+01:00' >>> pendulum.datetime(2013, 10, 27, 2, 30, 0, 0, tz='Europe/Paris', dst_rule=pendulum.PRE_TRANSITION) '2013-10-27T02:30:00+02:00' >>> pendulum.datetime(2013, 3, 31, 2, 30, 0, 0, tz='Europe/Paris', dst_rule=pendulum.TRANSITION_ERROR) # NonExistingTime: The datetime 2013-03-31 02:30:00 does not exist >>> pendulum.datetime(2013, 10, 27, 2, 30, 0, 0, tz='Europe/Paris', dst_rule=pendulum.TRANSITION_ERROR) # AmbiguousTime: The datetime 2013-10-27 02:30:00 is ambiguous. ``` Note that it only affects instances at creation time. Shifting time around transition times still behaves the same. ## Shifting time to transition So, what happens when you add time to a `DateTime` instance and stumble upon a transition time? Well `pendulum`, provided with the context of the previous instance, will adopt the proper behavior and apply the transition accordingly. ```python >>> import pendulum >>> dt = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz='Europe/Paris') '2013-03-31T01:59:59.999999+01:00' >>> dt = dt.add(microseconds=1) '2013-03-31T03:00:00+02:00' >>> dt.subtract(microseconds=1) '2013-03-31T01:59:59.999999+01:00' >>> dt = pendulum.datetime(2013, 10, 27, 2, 59, 59, 999999, tz='Europe/Paris', dst_rule=pendulum.PRE_TRANSITION) '2013-10-27T02:59:59.999999+02:00' >>> dt = dt.add(microseconds=1) '2013-10-27T02:00:00+01:00' >>> dt = dt.subtract(microseconds=1) '2013-10-27T02:59:59.999999+02:00' ``` ## Switching timezones You can easily change the timezone of a `DateTime` instance with the `in_timezone()` method. !!!note You can also use the more concise ``in_tz()`` ```python >>> in_paris = pendulum.datetime(2016, 8, 7, 22, 24, 30, tz='Europe/Paris') '2016-08-07T22:24:30+02:00' >>> in_paris.in_timezone('America/New_York') '2016-08-07T16:24:30-04:00' >>> in_paris.in_tz('Asia/Tokyo') '2016-08-08T05:24:30+09:00' ``` ## Using the timezone library directly !!!warning **You should avoid using the timezone library in Python < 3.6.** This is due to the fact that Pendulum relies heavily on the presence of the `fold` attribute which was introduced in Python 3.6. The reason it works inside the Pendulum ecosystem is that it backports the `fold` attribute in the `DateTime` class. Like said in the introduction, you can use the timezone library directly with standard `datetime` objects but with limitations, especially when adding and subtracting time around transition times. The value of the `fold` attribute will be used by default to determine the transition rule. ```python >>> from datetime import datetime >>> from pendulum import timezone >>> paris = timezone('Europe/Paris') >>> dt = datetime(2013, 3, 31, 2, 30) # By default, fold is set to 0 >>> dt = paris.convert(dt) >>> dt.isoformat() '2013-03-31T01:30:00+01:00' >>> dt = datetime(2013, 3, 31, 2, 30, fold=1) >>> dt = paris.convert(dt) >>> dt.isoformat() '2013-03-31T03:30:00+02:00' ``` Instead of relying on the `fold` attribute, you can use the `dst_rule` keyword argument. This is especially useful if you want to raise errors on non-existing and ambiguous times. ```python >>> import pendulum >>> dt = datetime(2013, 3, 31, 2, 30) # By default, fold is set to 0 >>> dt = paris.convert(dt, dst_rule=pendulum.PRE_TRANSITION) >>> dt.isoformat() '2013-03-31T01:30:00+01:00' >>> dt = paris.convert(dt, dst_rule=pendulum.POST_TRANSITION) >>> dt.isoformat() '2013-03-31T03:30:00+02:00' >>> paris.convert(dt, dst_rule=pendulum.TRANSITION_ERROR) # NonExistingTime: The datetime 2013-03-31 02:30:00 does not exist ``` This works as expected. However, whenever we add or subtract a `timedelta` object, things get tricky. ```python >>> from datetime import datetime, timedelta >>> from pendulum import timezone >>> dt = datetime(2013, 3, 31, 1, 59, 59, 999999) >>> dt = paris.convert(dt) >>> dt.isoformat() '2013-03-31T01:59:59.999999+01:00' >>> dt = dt + timedelta(microseconds=1) >>> dt.isoformat() '2013-03-31T02:00:00+01:00' ``` This is not what we expect. It should be `2013-03-31T03:00:00+02:00`. It is actually easy to retrieve the proper datetime by using `convert()` again. ```python >>> dt = tz.convert(dt) >>> dt.isoformat() '2013-03-31T03:00:00+02:00' ``` You can also get a normalized `datetime` object from a `Timezone` by using the `datetime()` method: ```python >>> import pendulum >>> tz = pendulum.timezone('Europe/Paris') >>> dt = tz.datetime(2013, 3, 31, 2, 30) >>> dt.isoformat() '2013-03-31T03:30:00+02:00' ```