summaryrefslogtreecommitdiffstats
path: root/docs/docs/timezones.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/docs/timezones.md')
-rw-r--r--docs/docs/timezones.md193
1 files changed, 193 insertions, 0 deletions
diff --git a/docs/docs/timezones.md b/docs/docs/timezones.md
new file mode 100644
index 0000000..85ff147
--- /dev/null
+++ b/docs/docs/timezones.md
@@ -0,0 +1,193 @@
+# 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.999998+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'
+```