]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Add support for date-time skeletons 265/head
authorMichael Birtwell <michael.birtwell@starleaf.com>
Mon, 28 Sep 2015 16:44:30 +0000 (17:44 +0100)
committerMichael Birtwell <michael.birtwell@starleaf.com>
Mon, 4 Jan 2016 17:56:36 +0000 (17:56 +0000)
The skeletons for dates and times are described on
http://cldr.unicode.org/translation/date-time-patterns under
Additional Date-Time Formats. And are useful when you want to some more
control over formatting dates and times but don't want to force all
locales to use the same pattern.

babel/core.py
babel/dates.py
scripts/import_cldr.py
tests/test_core.py
tests/test_dates.py

index 813a61a96a480eedc19ac92baad9f419f5b06195..c08cfa737f19f5cfddade01e2492385b7bf5ab65 100644 (file)
@@ -731,6 +731,19 @@ class Locale(object):
         """
         return self._data['datetime_formats']
 
+    @property
+    def datetime_skeletons(self):
+        """Locale patterns for formatting parts of a datetime.
+
+        >>> Locale('en').datetime_skeletons['MEd']
+        <DateTimePattern u'E, M/d'>
+        >>> Locale('fr').datetime_skeletons['MEd']
+        <DateTimePattern u'E dd/MM'>
+        >>> Locale('fr').datetime_skeletons['H']
+        <DateTimePattern u"HH 'h'">
+        """
+        return self._data['datetime_skeletons']
+
     @property
     def plural_form(self):
         """Plural rules for the locale.
index ab2d4fb2962938e93e900eb8f9a729282c16ac48..4f66adbe55297c8138d7cbdb8da8d3f4e0f95f10 100644 (file)
@@ -694,6 +694,34 @@ def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME):
     return parse_pattern(format).apply(time, locale)
 
 
+def format_skeleton(skeleton, datetime=None, tzinfo=None, locale=LC_TIME):
+    r"""Return a time and/or date formatted according to the given pattern.
+
+    The skeletons are defined in the CLDR data and provide more flexibility
+    than the simple short/long/medium formats, but are a bit harder to use.
+    The are defined using the date/time symbols without order or punctuation
+    and map to a suitable format for the given locale.
+
+    >>> t = datetime(2007, 4, 1, 15, 30)
+    >>> format_skeleton('MMMEd', t, locale='fr')
+    u'dim. 1 avr.'
+    >>> format_skeleton('MMMEd', t, locale='en')
+    u'Sun, Apr 1'
+
+    After the skeleton is resolved to a pattern `format_datetime` is called so
+    all timezone processing etc is the same as for that.
+
+    :param skeleton: A date time skeleton as defined in the cldr data.
+    :param datetime: the ``time`` or ``datetime`` object; if `None`, the current
+                 time in UTC is used
+    :param tzinfo: the time-zone to apply to the time for display
+    :param locale: a `Locale` object or a locale identifier
+    """
+    locale = Locale.parse(locale)
+    format = locale.datetime_skeletons[skeleton]
+    return format_datetime(datetime, format, tzinfo, locale)
+
+
 TIMEDELTA_UNITS = (
     ('year',   3600 * 24 * 365),
     ('month',  3600 * 24 * 30),
index 2925acc8a7c727fae3bc88b296c5bc7ac1d640d0..a5d0ad5dddf4d5287167b1886a56fa50af8c8ba6 100755 (executable)
@@ -576,6 +576,7 @@ def main():
                         )
 
             datetime_formats = data.setdefault('datetime_formats', {})
+            datetime_skeletons = data.setdefault('datetime_skeletons', {})
             for format in calendar.findall('dateTimeFormats'):
                 for elem in format.getiterator():
                     if elem.tag == 'dateTimeFormatLength':
@@ -591,6 +592,10 @@ def main():
                         datetime_formats = Alias(_translate_alias(
                             ['datetime_formats'], elem.attrib['path'])
                         )
+                    elif elem.tag == 'availableFormats':
+                        for datetime_skeleton in elem.findall('dateFormatItem'):
+                            datetime_skeletons[datetime_skeleton.attrib['id']] = \
+                                dates.parse_pattern(text_type(datetime_skeleton.text))
 
         # <numbers>
 
index 48eb9fe7e1ddc3b91a1ccc747045b5194eee4a16..54cf37dde5352361a806e07396ef561e4f4a412a 100644 (file)
@@ -236,6 +236,10 @@ class TestLocaleClass:
         assert Locale('en').datetime_formats['full'] == u"{1} 'at' {0}"
         assert Locale('th').datetime_formats['medium'] == u'{1} {0}'
 
+    def test_datetime_skeleton_property(self):
+        assert Locale('en').datetime_skeletons['Md'].pattern == u"M/d"
+        assert Locale('th').datetime_skeletons['Md'].pattern == u'd/M'
+
     def test_plural_form_property(self):
         assert Locale('en').plural_form(1) == 'one'
         assert Locale('en').plural_form(0) == 'other'
index ea4805bb876c471d07633cb0db422d49058c22d8..30a0ea3d56da2a4467cd1de780b525a04031d965 100644 (file)
@@ -498,6 +498,15 @@ def test_format_time():
     assert us_east == u'3:30:00 PM Eastern Standard Time'
 
 
+def test_format_skeleton():
+    dt = datetime(2007, 4, 1, 15, 30)
+    assert (dates.format_skeleton('yMEd', dt, locale='en_US') == u'Sun, 4/1/2007')
+    assert (dates.format_skeleton('yMEd', dt, locale='th') == u'อา. 1/4/2007')
+
+    assert (dates.format_skeleton('EHm', dt, locale='en') == u'Sun 15:30')
+    assert (dates.format_skeleton('EHm', dt, tzinfo=timezone('Asia/Bangkok'), locale='th') == u'อา. 22:30 น.')
+
+
 def test_format_timedelta():
     assert (dates.format_timedelta(timedelta(weeks=12), locale='en_US')
             == u'3 months')