1.. -*- mode: rst; encoding: utf-8 -*-
2
3.. _date-and-time:
4
5=============
6Date and Time
7=============
8
9
10When working with date and time information in Python, you commonly use the
11classes ``date``, ``datetime`` and/or ``time`` from the `datetime` package.
12Babel provides functions for locale-specific formatting of those objects in its
13``dates`` module:
14
15.. code-block:: pycon
16
17    >>> from datetime import date, datetime, time
18    >>> from babel.dates import format_date, format_datetime, format_time
19
20    >>> d = date(2007, 4, 1)
21    >>> format_date(d, locale='en')
22    u'Apr 1, 2007'
23    >>> format_date(d, locale='de_DE')
24    u'01.04.2007'
25
26As this example demonstrates, Babel will automatically choose a date format
27that is appropriate for the requested locale.
28
29The ``format_*()`` functions also accept an optional ``format`` argument, which
30allows you to choose between one of four format variations:
31
32 * ``short``,
33 * ``medium`` (the default),
34 * ``long``, and
35 * ``full``.
36
37For example:
38
39.. code-block:: pycon
40
41    >>> format_date(d, format='short', locale='en')
42    u'4/1/07'
43    >>> format_date(d, format='long', locale='en')
44    u'April 1, 2007'
45    >>> format_date(d, format='full', locale='en')
46    u'Sunday, April 1, 2007'
47
48Core Time Concepts
49==================
50
51Working with dates and time can be a complicated thing.  Babel attempts to
52simplify working with them by making some decisions for you.  Python's
53datetime module has different ways to deal with times and dates: naive and
54timezone-aware datetime objects.
55
56Babel generally recommends you to store all your time in naive datetime
57objects and treat them as UTC at all times.  This simplifies dealing with
58time a lot because otherwise you can get into the hairy situation where
59you are dealing with datetime objects of different timezones.  That is
60tricky because there are situations where time can be ambiguous.  This is
61usually the case when dealing with dates around timezone transitions.  The
62most common case of timezone transition is changes between daylight saving
63time and standard time.
64
65As such we recommend to always use UTC internally and only reformat to
66local time when returning dates to users.  At that point the timezone the
67user has selected can usually be established and Babel can automatically
68rebase the time for you.
69
70To get the current time use the :meth:`~datetime.datetime.utcnow` method
71of the :class:`~datetime.datetime` object.  It will return a naive
72:class:`~datetime.datetime` object in UTC.
73
74For more information about timezones see :ref:`timezone-support`.
75
76Pattern Syntax
77==============
78
79While Babel makes it simple to use the appropriate date/time format for a given
80locale, you can also force it to use custom patterns. Note that Babel uses
81different patterns for specifying number and date formats compared to the
82Python equivalents (such as ``time.strftime()``), which have mostly been
83inherited from C and POSIX. The patterns used in Babel are based on the
84`Locale Data Markup Language specification`_ (LDML), which defines them as
85follows:
86
87    A date/time pattern is a string of characters, where specific strings of
88    characters are replaced with date and time data from a calendar when
89    formatting or used to generate data for a calendar when parsing. […]
90
91    Characters may be used multiple times. For example, if ``y`` is used for the
92    year, ``yy`` might produce "99", whereas ``yyyy`` produces "1999". For most
93    numerical fields, the number of characters specifies the field width. For
94    example, if ``h`` is the hour, ``h`` might produce "5", but ``hh`` produces
95    "05". For some characters, the count specifies whether an abbreviated or full
96    form should be used […]
97
98    Two single quotes represent a literal single quote, either inside or outside
99    single quotes. Text within single quotes is not interpreted in any way (except
100    for two adjacent single quotes).
101
102For example:
103
104.. code-block:: pycon
105
106    >>> d = date(2007, 4, 1)
107    >>> format_date(d, "EEE, MMM d, ''yy", locale='en')
108    u"Sun, Apr 1, '07"
109    >>> format_date(d, "EEEE, d.M.yyyy", locale='de')
110    u'Sonntag, 1.4.2007'
111
112    >>> t = time(15, 30)
113    >>> format_time(t, "hh 'o''clock' a", locale='en')
114    u"03 o'clock PM"
115    >>> format_time(t, 'H:mm a', locale='de')
116    u'15:30 nachm.'
117
118    >>> dt = datetime(2007, 4, 1, 15, 30)
119    >>> format_datetime(dt, "yyyyy.MMMM.dd GGG hh:mm a", locale='en')
120    u'02007.April.01 AD 03:30 PM'
121
122The syntax for custom datetime format patterns is described in detail in the
123the `Locale Data Markup Language specification`_. The following table is just a
124relatively brief overview.
125
126 .. _`Locale Data Markup Language specification`:
127    https://unicode.org/reports/tr35/#Date_Format_Patterns
128
129Date Fields
130-----------
131
132  +----------+--------+--------------------------------------------------------+
133  | Field    | Symbol | Description                                            |
134  +==========+========+========================================================+
135  | Era      | ``G``  | Replaced with the era string for the current date. One |
136  |          |        | to three letters for the abbreviated form, four        |
137  |          |        | lettersfor the long form, five for the narrow form     |
138  +----------+--------+--------------------------------------------------------+
139  | Year     | ``y``  | Replaced by the year. Normally the length specifies    |
140  |          |        | the padding, but for two letters it also specifies the |
141  |          |        | maximum length.                                        |
142  |          +--------+--------------------------------------------------------+
143  |          | ``Y``  | Same as ``y`` but uses the ISO year-week calendar. ISO |
144  |          |        | year-week increments after completing the last week of |
145  |          |        | the year. Therefore it may change a few days before or |
146  |          |        | after ``y``. Recommend use with the ``w`` Symbol.      |
147  |          +--------+--------------------------------------------------------+
148  |          | ``u``  | ??                                                     |
149  +----------+--------+--------------------------------------------------------+
150  | Quarter  | ``Q``  | Use one or two for the numerical quarter, three for    |
151  |          |        | the abbreviation, or four for the full name.           |
152  |          +--------+--------------------------------------------------------+
153  |          | ``q``  | Use one or two for the numerical quarter, three for    |
154  |          |        | the abbreviation, or four for the full name.           |
155  +----------+--------+--------------------------------------------------------+
156  | Month    | ``M``  | Use one or two for the numerical month, three for the  |
157  |          |        | abbreviation, or four for the full name, or five for   |
158  |          |        | the narrow name.                                       |
159  |          +--------+--------------------------------------------------------+
160  |          | ``L``  | Use one or two for the numerical month, three for the  |
161  |          |        | abbreviation, or four for the full name, or 5 for the  |
162  |          |        | narrow name.                                           |
163  +----------+--------+--------------------------------------------------------+
164  | Week     | ``w``  | Week of year according to the ISO year-week calendar.  |
165  |          |        | This may have 52 or 53 weeks depending on the year.    |
166  |          |        | Recommend use with the ``Y`` symbol.                   |
167  |          +--------+--------------------------------------------------------+
168  |          | ``W``  | Week of month.                                         |
169  +----------+--------+--------------------------------------------------------+
170  | Day      | ``d``  | Day of month.                                          |
171  |          +--------+--------------------------------------------------------+
172  |          | ``D``  | Day of year.                                           |
173  |          +--------+--------------------------------------------------------+
174  |          | ``F``  | Day of week in month.                                  |
175  |          +--------+--------------------------------------------------------+
176  |          | ``g``  | ??                                                     |
177  +----------+--------+--------------------------------------------------------+
178  | Week day | ``E``  | Day of week. Use one through three letters for the     |
179  |          |        | short day, or four for the full name, or five for the  |
180  |          |        | narrow name.                                           |
181  |          +--------+--------------------------------------------------------+
182  |          | ``e``  | Local day of week. Same as E except adds a numeric     |
183  |          |        | value that will depend on the local starting day of    |
184  |          |        | the week, using one or two letters.                    |
185  |          +--------+--------------------------------------------------------+
186  |          | ``c``  | ??                                                     |
187  +----------+--------+--------------------------------------------------------+
188
189Time Fields
190-----------
191
192  +----------+--------+--------------------------------------------------------+
193  | Field    | Symbol | Description                                            |
194  +==========+========+========================================================+
195  | Period   | ``a``  | AM or PM                                               |
196  +----------+--------+--------------------------------------------------------+
197  | Hour     | ``h``  | Hour [1-12].                                           |
198  |          +--------+--------------------------------------------------------+
199  |          | ``H``  | Hour [0-23].                                           |
200  |          +--------+--------------------------------------------------------+
201  |          | ``K``  | Hour [0-11].                                           |
202  |          +--------+--------------------------------------------------------+
203  |          | ``k``  | Hour [1-24].                                           |
204  +----------+--------+--------------------------------------------------------+
205  | Minute   | ``m``  | Use one or two for zero places padding.                |
206  +----------+--------+--------------------------------------------------------+
207  | Second   | ``s``  | Use one or two for zero places padding.                |
208  |          +--------+--------------------------------------------------------+
209  |          | ``S``  | Fractional second, rounds to the count of letters.     |
210  |          +--------+--------------------------------------------------------+
211  |          | ``A``  | Milliseconds in day.                                   |
212  +----------+--------+--------------------------------------------------------+
213  | Timezone | ``z``  | Use one to three letters for the short timezone or     |
214  |          |        | four for the full name.                                |
215  |          +--------+--------------------------------------------------------+
216  |          | ``Z``  | Use one to three letters for RFC 822, four letters for |
217  |          |        | GMT format.                                            |
218  |          +--------+--------------------------------------------------------+
219  |          | ``v``  | Use one letter for short wall (generic) time, four for |
220  |          |        | long wall time.                                        |
221  |          +--------+--------------------------------------------------------+
222  |          | ``V``  | Same as ``z``, except that timezone abbreviations      |
223  |          |        | should be used regardless of whether they are in       |
224  |          |        | common use by the locale.                              |
225  +----------+--------+--------------------------------------------------------+
226
227
228Time Delta Formatting
229=====================
230
231In addition to providing functions for formatting localized dates and times,
232the ``babel.dates`` module also provides a function to format the difference
233between two times, called a ''time delta''. These are usually represented as
234``datetime.timedelta`` objects in Python, and it's also what you get when you
235subtract one ``datetime`` object from an other.
236
237The ``format_timedelta`` function takes a ``timedelta`` object and returns a
238human-readable representation. This happens at the cost of precision, as it
239chooses only the most significant unit (such as year, week, or hour) of the
240difference, and displays that:
241
242.. code-block:: pycon
243
244    >>> from datetime import timedelta
245    >>> from babel.dates import format_timedelta
246    >>> delta = timedelta(days=6)
247    >>> format_timedelta(delta, locale='en_US')
248    u'1 week'
249
250The resulting strings are based from the CLDR data, and are properly
251pluralized depending on the plural rules of the locale and the calculated
252number of units.
253
254The function provides parameters for you to influence how this most significant
255unit is chosen: with ``threshold`` you set the value after which the
256presentation switches to the next larger unit, and with ``granularity`` you
257can limit the smallest unit to display:
258
259.. code-block:: pycon
260
261    >>> delta = timedelta(days=6)
262    >>> format_timedelta(delta, threshold=1.2, locale='en_US')
263    u'6 days'
264    >>> format_timedelta(delta, granularity='month', locale='en_US')
265    u'1 month'
266
267.. _timezone-support:
268
269Time-zone Support
270=================
271
272Many of the verbose time formats include the time-zone, but time-zone
273information is not by default available for the Python ``datetime`` and
274``time`` objects. The standard library includes only the abstract ``tzinfo``
275class, which you need appropriate implementations for to actually use in your
276application. Babel includes a ``tzinfo`` implementation for UTC (Universal
277Time).
278
279Babel uses `pytz`_ for real timezone support which includes the
280definitions of practically all of the time-zones used on the world, as
281well as important functions for reliably converting from UTC to local
282time, and vice versa.  The module is generally wrapped for you so you can
283directly interface with it from within Babel:
284
285.. code-block:: pycon
286
287    >>> from datetime import time
288    >>> from babel.dates import get_timezone, UTC
289    >>> dt = datetime(2007, 4, 1, 15, 30, tzinfo=UTC)
290    >>> eastern = get_timezone('US/Eastern')
291    >>> format_datetime(dt, 'H:mm Z', tzinfo=eastern, locale='en_US')
292    u'11:30 -0400'
293
294The recommended approach to deal with different time-zones in a Python
295application is to always use UTC internally, and only convert from/to the users
296time-zone when accepting user input and displaying date/time data, respectively.
297You can use Babel together with ``pytz`` to apply a time-zone to any
298``datetime`` or ``time`` object for display, leaving the original information
299unchanged:
300
301.. code-block:: pycon
302
303    >>> british = get_timezone('Europe/London')
304    >>> format_datetime(dt, 'H:mm zzzz', tzinfo=british, locale='en_US')
305    u'16:30 British Summer Time'
306
307Here, the given UTC time is adjusted to the "Europe/London" time-zone, and
308daylight savings time is taken into account. Daylight savings time is also
309applied to ``format_time``, but because the actual date is unknown in that
310case, the current day is assumed to determine whether DST or standard time
311should be used.
312
313For many timezones it's also possible to ask for the next timezone
314transition.  This for instance is useful to answer the question “when do I
315have to move the clock forward next”:
316
317.. code-block:: pycon
318
319    >>> t = get_next_timezone_transition('Europe/Vienna', datetime(2011, 3, 2))
320    >>> t
321    <TimezoneTransition CET -> CEST (2011-03-27 01:00:00)>
322    >>> t.from_offset
323    3600.0
324    >>> t.to_offset
325    7200.0
326    >>> t.from_tz
327    'CET'
328    >>> t.to_tz
329    'CEST'
330
331Lastly Babel also provides support for working with the local timezone of
332your operating system.  It's provided through the ``LOCALTZ`` constant:
333
334.. code-block:: pycon
335
336    >>> from babel.dates import LOCALTZ, get_timezone_name
337    >>> LOCALTZ
338    <DstTzInfo 'Europe/Vienna' CET+1:00:00 STD>
339    >>> get_timezone_name(LOCALTZ)
340    u'Central European Time'
341
342.. _pytz: http://pytz.sourceforge.net/
343
344
345Localized Time-zone Names
346-------------------------
347
348While the ``Locale`` class provides access to various locale display names
349related to time-zones, the process of building a localized name of a time-zone
350is actually quite complicated. Babel implements it in separately usable
351functions in the ``babel.dates`` module, most importantly the
352``get_timezone_name`` function:
353
354.. code-block:: pycon
355
356    >>> from babel import Locale
357    >>> from babel.dates import get_timezone_name, get_timezone
358
359    >>> tz = get_timezone('Europe/Berlin')
360    >>> get_timezone_name(tz, locale=Locale.parse('pt_PT'))
361    u'Hora da Europa Central'
362
363You can pass the function either a ``datetime.tzinfo`` object, or a
364``datetime.date`` or ``datetime.datetime`` object. If you pass an actual date,
365the function will be able to take daylight savings time into account. If you
366pass just the time-zone, Babel does not know whether daylight savings time is
367in effect, so it uses a generic representation, which is useful for example to
368display a list of time-zones to the user.
369
370.. code-block:: pycon
371
372    >>> from datetime import datetime
373
374    >>> dt = tz.localize(datetime(2007, 8, 15))
375    >>> get_timezone_name(dt, locale=Locale.parse('de_DE'))
376    u'Mitteleurop\xe4ische Sommerzeit'
377    >>> get_timezone_name(tz, locale=Locale.parse('de_DE'))
378    u'Mitteleurop\xe4ische Zeit'
379