# HG changeset patch # User cmlenz # Date 1180631447 0 # Node ID dce4cfd4ba5da8f2da021cb6bbff05035ec37c0d # Parent 762a5de6faae776862e13f27fc85a9803cc1a114 Started documentation for date formatting, plus some code tweaks in that area. diff --git a/babel/dates.py b/babel/dates.py --- a/babel/dates.py +++ b/babel/dates.py @@ -160,12 +160,31 @@ >>> format_time(d, "EEE, MMM d, ''yy", locale='en') u"Sun, Apr 1, '07" + If the pattern contains time fields, an `AttributeError` will be raised + when trying to apply the formatting: + + >>> format_date(d, "yyyy-MM-dd HH:mm", locale='en_US') + Traceback (most recent call last): + ... + AttributeError: 'datetime.date' object has no attribute 'hour' + + This is also true if the value of ``date`` parameter is a ``datetime`` + object, as this function automatically converts it to a ``date``:: + + >>> dt = datetime(2007, 04, 01, 15, 30) + >>> format_date(dt, "yyyy-MM-dd HH:mm", locale='en_US') + Traceback (most recent call last): + ... + AttributeError: 'datetime.date' object has no attribute 'hour' + :param date: the ``date`` object :param format: one of "full", "long", "medium", or "short", or a custom date/time pattern :param locale: a `Locale` object or a locale string :rtype: `unicode` """ + if isinstance(date, datetime): + date = date.date() locale = Locale.parse(locale) if format in ('full', 'long', 'medium', 'short'): format = get_date_format(format, locale=locale) @@ -181,7 +200,11 @@ :param locale: a `Locale` object or a locale string :rtype: `unicode` """ - raise NotImplementedError + locale = Locale.parse(locale) + if format in ('full', 'long', 'medium', 'short'): + raise NotImplementedError + pattern = parse_pattern(format) + return parse_pattern(format).apply(datetime, locale) def format_time(time, format='medium', locale=LC_TIME): """Returns a time formatted according to the given pattern. @@ -198,12 +221,33 @@ >>> format_time(t, "hh 'o''clock' a", locale='en') u"03 o'clock PM" + If the pattern contains date fields, an `AttributeError` will be raised + when trying to apply the formatting: + + >>> format_time(t, "yyyy-MM-dd HH:mm", locale='en_US') + Traceback (most recent call last): + ... + AttributeError: 'datetime.time' object has no attribute 'year' + + This is also true if the value of ``time`` parameter is a ``datetime`` + object, as this function automatically converts it to a ``time``:: + + >>> dt = datetime(2007, 04, 01, 15, 30) + >>> format_time(dt, "yyyy-MM-dd HH:mm", locale='en_US') + Traceback (most recent call last): + ... + AttributeError: 'datetime.time' object has no attribute 'year' + :param time: the ``time`` object :param format: one of "full", "long", "medium", or "short", or a custom date/time pattern :param locale: a `Locale` object or a locale string :rtype: `unicode` """ + if isinstance(time, (int, long)): + time = datetime.fromtimestamp(time).time() + elif isinstance(time, datetime): + time = time.time() locale = Locale.parse(locale) if format in ('full', 'long', 'medium', 'short'): format = get_time_format(format, locale=locale) @@ -268,6 +312,10 @@ return self.format(self.value.hour % 12, num) elif char == 'H': return self.format(self.value.hour, num) + elif char == 'K': + return self.format(self.value.hour % 12 - 1, num) + elif char == 'k': + return self.format(self.value.hour + 1, num) elif char == 'm': return self.format(self.value.minute, num) elif char == 's': diff --git a/doc/formatting.txt b/doc/formatting.txt --- a/doc/formatting.txt +++ b/doc/formatting.txt @@ -10,3 +10,203 @@ .. sectnum:: +Date Formatting +=============== + +When working with date and time information in Python, you commonly use the +classes ``date``, ``datetime`` and/or ``time`` from the `datetime package`_. +Babel provides functions for locale-specific formatting of those objects in its +``dates`` module:: + + >>> from datetime import date, datetime, time + >>> from babel.dates import format_date, format_datetime, format_time + + >>> d = date(2007, 4, 1) + >>> format_date(d, locale='en') + u'Apr 1, 2007' + >>> format_date(d, locale='de_DE') + u'01.04.2007' + +As this example demonstrates, Babel will automatically choose a date format +that is appropriate for the requested locale. + +The ``format_*()`` functions also accept an optional ``format`` argument, which +allows you to choose between one of four format variations: + + * ``short``, + * ``medium`` (the default), + * ``long`` (the default), and + * ``full`` (the default). + +For example:: + + >>> format_date(d, format='short', locale='en') + u'4/1/07' + >>> format_date(d, format='long', locale='en') + u'April 1, 2007' + >>> format_date(d, format='full', locale='en') + u'Sunday, April 1, 2007' + +.. _`datetime package`: http://docs.python.org/lib/module-datetime.html + + +Pattern Syntax +-------------- + +While Babel makes it simple to use the appropriate date/time format for a given +locale, you can also force it to use custom patterns. Note that Babel uses +different patterns for specifying number and date formats compared to the +Python equivalents (such as ``time.strftime()``), which have mostly been +inherited from C and POSIX. The patterns used in Babel are based on the +`Locale Data Markup Language specification`_ (LDML), which defines them as +follows: + + A date/time pattern is a string of characters, where specific strings of + characters are replaced with date and time data from a calendar when formatting + or used to generate data for a calendar when parsing. […] + + Characters may be used multiple times. For example, if ``y`` is used for the + year, ``yy`` might produce "99", whereas ``yyyy`` produces "1999". For most + numerical fields, the number of characters specifies the field width. For + example, if ``h`` is the hour, ``h`` might produce "5", but ``hh`` produces + "05". For some characters, the count specifies whether an abbreviated or full + form should be used […] + + Two single quotes represent a literal single quote, either inside or outside + single quotes. Text within single quotes is not interpreted in any way (except + for two adjacent single quotes). + +For example:: + + >>> d = date(2007, 4, 1) + >>> format_date(d, "EEE, MMM d, ''yy", locale='en') + u"Sun, Apr 1, '07" + >>> format_date(d, "EEEE, d.M.yyyy", locale='de') + u'Sonntag, 1.4.2007' + + >>> t = time(15, 30) + >>> format_time(t, "hh 'o''clock' a", locale='en') + u"03 o'clock PM" + >>> format_time(t, 'H:mm a', locale='de') + u'15:30 nachm.' + + >>> dt = datetime(2007, 4, 1, 15, 30) + >>> format_datetime(dt, "yyyyy.MMMM.dd GGG hh:mm a", locale='en') + u'02007.April.01 AD 03:30 PM' + +The syntax for custom datetime format patterns is described in detail in the +the `Locale Data Markup Language specification`_. The following table is just a +relatively brief overview. + + .. _`Locale Data Markup Language specification`: http://unicode.org/reports/tr35/#Date_Format_Patterns + +----------- +Date Fields +----------- + + +----------+--------+--------------------------------------------------------+ + | Field | Symbol | Description | + +==========+========+========================================================+ + | Era | ``G`` | Replaced with the era string for the current date. One | + | | | to three letters for the abbreviated form, four | + | | | lettersfor the long form, five for the narrow form | + +----------+--------+--------------------------------------------------------+ + | Year | ``y`` | Replaced by the year. Normally the length specifies | + | | | the padding, but for two letters it also specifies the | + | | | maximum length. | + | +--------+--------------------------------------------------------+ + | | ``Y`` | Same as ``y`` but uses the ISO year-week calendar. | + | +--------+--------------------------------------------------------+ + | | ``u`` | ?? | + +----------+--------+--------------------------------------------------------+ + | Quarter | ``Q`` | Use one or two for the numerical quarter, three for | + | | | the abbreviation, or four for the full name. | + | +--------+--------------------------------------------------------+ + | | ``q`` | Use one or two for the numerical quarter, three for | + | | | the abbreviation, or four for the full name. | + +----------+--------+--------------------------------------------------------+ + | Month | ``M`` | Use one or two for the numerical month, three for the | + | | | abbreviation, or four for the full name, or five for | + | | | the narrow name. | + | +--------+--------------------------------------------------------+ + | | ``L`` | Use one or two for the numerical month, three for the | + | | | abbreviation, or four for the full name, or 5 for the | + | | | narrow name. | + +----------+--------+--------------------------------------------------------+ + | Week | ``w`` | Week of year. | + | +--------+--------------------------------------------------------+ + | | ``W`` | Week of month. | + +----------+--------+--------------------------------------------------------+ + | Day | ``d`` | Day of month. | + | +--------+--------------------------------------------------------+ + | | ``D`` | Day of year. | + | +--------+--------------------------------------------------------+ + | | ``F`` | Day of week in month. | + | +--------+--------------------------------------------------------+ + | | ``g`` | ?? | + +----------+--------+--------------------------------------------------------+ + | Week day | ``E`` | Day of week. Use one through three letters for the | + | | | short day, or four for the full name, or five for the | + | | | narrow name. | + | +--------+--------------------------------------------------------+ + | | ``e`` | Local day of week. Same as E except adds a numeric | + | | | value that will depend on the local starting day of | + | | | the week, using one or two letters. | + | +--------+--------------------------------------------------------+ + | | ``c`` | ?? | + +----------+--------+--------------------------------------------------------+ + +----------- +Time Fields +----------- + + +----------+--------+--------------------------------------------------------+ + | Field | Symbol | Description | + +==========+========+========================================================+ + | Period | ``a`` | AM or PM | + +----------+--------+--------------------------------------------------------+ + | Hour | ``h`` | Hour [1-12]. | + | +--------+--------------------------------------------------------+ + | | ``H`` | Hour [0-23]. | + | +--------+--------------------------------------------------------+ + | | ``K`` | Hour [0-11]. | + | +--------+--------------------------------------------------------+ + | | ``k`` | Hour [1-24]. | + +----------+--------+--------------------------------------------------------+ + | Minute | ``m`` | Use one or two for zero places padding. | + +----------+--------+--------------------------------------------------------+ + | Second | ``s`` | Use one or two for zero places padding. | + | +--------+--------------------------------------------------------+ + | | ``S`` | Fractional second, rounds to the count of letters. | + | +--------+--------------------------------------------------------+ + | | ``A`` | Milliseconds in day. | + +----------+--------+--------------------------------------------------------+ + | Timezone | ``z`` | Use one to three letters for the short timezone or | + | | | four for the full name. | + | +--------+--------------------------------------------------------+ + | | ``Z`` | Use one to three letters for RFC 822, four letters for | + | | | GMT format. | + | +--------+--------------------------------------------------------+ + | | ``v`` | Use one letter for short wall (generic) time, four for | + | | | long wall time. | + +----------+--------+--------------------------------------------------------+ + + +Parsing Dates +------------- + +Babel can also parse date and time information in a locale-sensitive manner:: + + >>> from babel.dates import parse_date, parse_datetime, parse_time + + +Number Formatting +================= + + +Pattern Syntax +-------------- + + +Parsing Numbers +--------------- diff --git a/doc/style/edgewall.css b/doc/style/edgewall.css --- a/doc/style/edgewall.css +++ b/doc/style/edgewall.css @@ -17,6 +17,14 @@ hr { border: none; border-top: 1px solid #ccb; margin: 2em 0; } p { margin: 0 0 1em; } +table { border: 1px solid #999; border-width: 0 1px 0 0; + border-collapse: separate; border-spacing: 0; +} +table thead th { background: #999; border: 1px solid #999;; color: #fff; + font-weight: bold; +} +table td { border: 1px solid #ccc; border-width: 0 0 1px 1px; padding: .3em; } + :link, :visited { text-decoration: none; border-bottom: 1px dotted #bbb; color: #b00; }