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