From: Aarni Koskela Date: Sun, 14 Feb 2016 18:56:02 +0000 (+0200) Subject: dates: Add day period API X-Git-Tag: 2.3.1~6^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=151fda947accfb3501053613e5ebb17c63d64ef4;p=thirdparty%2Fbabel.git dates: Add day period API --- diff --git a/babel/core.py b/babel/core.py index f6bc25f1..c7d299e0 100644 --- a/babel/core.py +++ b/babel/core.py @@ -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. diff --git a/babel/dates.py b/babel/dates.py index 991d11b7..62ba79b9 100644 --- a/babel/dates.py +++ b/babel/dates.py @@ -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 index 00000000..eb12b07f --- /dev/null +++ b/tests/test_day_periods.py @@ -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