]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
dates: Add day period API 349/head
authorAarni Koskela <akx@iki.fi>
Sun, 14 Feb 2016 18:56:02 +0000 (20:56 +0200)
committerAarni Koskela <akx@iki.fi>
Sat, 5 Mar 2016 19:23:55 +0000 (21:23 +0200)
babel/core.py
babel/dates.py
tests/test_day_periods.py [new file with mode: 0644]

index f6bc25f14e25e5a298b8214dcebd937e808101d5..c7d299e04a68033dcf54219085cc83994eacfeba 100644 (file)
@@ -627,6 +627,12 @@ class Locale(object):
         """
         return self._data['day_periods']
 
+    @property
+    def day_period_rules(self):
+        """Day period rules for the locale.  Used by `get_period_id`.
+        """
+        return self._data.get('day_period_rules', {})
+
     @property
     def days(self):
         """Locale display names for weekdays.
index 991d11b7f915ee02e7c42f4ac5bd5d40523ea8f9..62ba79b966f243b082f2c10c5b68c6e67a87f1ce 100644 (file)
@@ -1059,6 +1059,56 @@ def format_interval(start, end, skeleton=None, tzinfo=None, fuzzy=True, locale=L
     return _format_fallback_interval(start, end, skeleton, tzinfo, locale)
 
 
+def get_period_id(time, tzinfo=None, type=None, locale=LC_TIME):
+    """
+    Get the day period ID for a given time.
+
+    This ID can be used as a key for the period name dictionary.
+
+    >>> get_period_names(locale="de")[get_period_id(time(7, 42), locale="de")]
+    u'Morgen'
+
+    :param time: The time to inspect.
+    :param tzinfo: The timezone for the time. See ``format_time``.
+    :param type: The period type to use. Either "selection" or None.
+                 The selection type is used for selecting among phrases such as
+                 “Your email arrived yesterday evening” or “Your email arrived last night”.
+    :param locale: the `Locale` object, or a locale string
+    :return: period ID. Something is always returned -- even if it's just "am" or "pm".
+    """
+    time = _get_time(time, tzinfo)
+    seconds_past_midnight = int(time.hour * 60 * 60 + time.minute * 60 + time.second)
+    locale = Locale.parse(locale)
+
+    # The LDML rules state that the rules may not overlap, so iterating in arbitrary
+    # order should be alright.
+    for rule_id, rules in locale.day_period_rules.get(type, {}).items():
+        for rule in rules:
+            if "at" in rule and rule["at"] == seconds_past_midnight:
+                return rule_id
+
+            start_ok = end_ok = False
+
+            if "from" in rule and seconds_past_midnight >= rule["from"]:
+                start_ok = True
+            if "to" in rule and seconds_past_midnight <= rule["to"]:
+                # This rule type does not exist in the present CLDR data;
+                # excuse the lack of test coverage.
+                end_ok = True
+            if "before" in rule and seconds_past_midnight < rule["before"]:
+                end_ok = True
+            if "after" in rule and seconds_past_midnight > rule["after"]:
+                start_ok = True
+
+            if start_ok and end_ok:
+                return rule_id
+
+    if seconds_past_midnight < 43200:
+        return "am"
+    else:
+        return "pm"
+
+
 def parse_date(string, locale=LC_TIME):
     """Parse a date from a string.
 
diff --git a/tests/test_day_periods.py b/tests/test_day_periods.py
new file mode 100644 (file)
index 0000000..eb12b07
--- /dev/null
@@ -0,0 +1,18 @@
+# -- encoding: UTF-8 --
+from datetime import time
+
+import babel.dates as dates
+import pytest
+
+
+@pytest.mark.parametrize("locale, time, expected_period_id", [
+    ("de", time(7, 42), "morning1"),  # (from, before)
+    ("de", time(3, 11), "night1"),  # (after, before)
+    ("fi", time(0), "midnight"),  # (at)
+    ("en_US", time(12), "noon"),  # (at)
+    ("agq", time(10), "am"),  # no periods defined
+    ("agq", time(22), "pm"),  # no periods defined
+    ("am", time(14), "afternoon1"),  # (before, after)
+])
+def test_day_period_rules(locale, time, expected_period_id):
+    assert dates.get_period_id(time, locale=locale) == expected_period_id