branch: elpa/datetime commit 4d11de332682e9942ad00c0ac86d79c8e1789329 Author: Paul Pogonyshev <pogonys...@gmail.com> Commit: Paul Pogonyshev <pogonys...@gmail.com>
Upgrade to fetching data from Java 17 (Debian build 17.0.8+7-1); handle 'B' in Java patterns, as it is used in standard patterns now. --- .github/workflows/check-for-updates.yml | 2 +- .github/workflows/test.yml | 2 +- datetime.el | 50 ++++++++++++++++++++++++++++---- dev/HarvestData.java | 41 ++++++++++++++++++++++++++ locale-data.extmap | Bin 278371 -> 349524 bytes test/format.el | 12 ++++++++ test/parse.el | 3 ++ timezone-data.extmap | Bin 870482 -> 889713 bytes timezone-name-data.extmap | Bin 2760832 -> 2997365 bytes 9 files changed, 102 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check-for-updates.yml b/.github/workflows/check-for-updates.yml index 580ee628f5..d5b6957beb 100644 --- a/.github/workflows/check-for-updates.yml +++ b/.github/workflows/check-for-updates.yml @@ -27,7 +27,7 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'zulu' - java-version: '14' + java-version: '17' - name: Check out the source code uses: actions/checkout@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ad0d676fb..9d3a7176bf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'zulu' - java-version: '14' + java-version: '17' - name: Check out the source code uses: actions/checkout@v2 diff --git a/datetime.el b/datetime.el index 8b2b137c48..6393e27152 100644 --- a/datetime.el +++ b/datetime.el @@ -92,6 +92,7 @@ ;; weekday-standalone-name (full | abbreviated) ;; ;; am-pm (full | abbreviated) +;; day-period (short | full | narrow) ;; ;; hour-0-23 (NUMBER) ;; hour-1-24 (NUMBER) @@ -140,6 +141,8 @@ ;; - `:eras' and `:am-pm' default to English version; ;; - month/dayweek standalone abbreviations or names default to ;; the corresponding context-aware property; +;; - for day period strings, both `:full' and `:narrow' variants +;; fall back to `:short'; ;; - date-time patterns are not stored, instead they are built from ;; date and time parts for that locale; corresponding field is a ;; cons with car determining what should be in the beginning (t @@ -381,6 +384,11 @@ form: (?k (cons 'hour-1-24 num-repetitions)) (?K (cons 'hour-am-pm-0-11 num-repetitions)) (?h (cons 'hour-am-pm-1-12 num-repetitions)) + (?B (cons 'day-period (pcase num-repetitions + (1 :short) + (4 :full) + (5 :narrow) + (_ (error "Pattern character `%c' must come in exactly 1, 4 or 5 repetitions" character))))) (?m (cons 'minute num-repetitions)) (?s (cons 'second num-repetitions)) (?S (cons 'second-fractional num-repetitions)) @@ -454,6 +462,11 @@ form: (`decimal-separator details) (`second-fractional (cons ?S details)) (`am-pm "a") + (`day-period (pcase details + (:short "B") + (:full "BBBB") + (:narrow "BBBBB") + (_ (error "Unexpected details for `%s' part: %s" type details)))) (_ (error "Unexpected part type %s" type))))) (push (cond ((integerp string) (string string)) @@ -506,6 +519,14 @@ form: (push (setq days (+ days month-days)) result)) (apply #'vector (nreverse result)))) +;; FIXME: Maybe use binary lookup or something? Not terribly important. +(defsubst datetime--day-period-index (thresholds minute) + (let ((index 0)) + (while (and thresholds (<= (car thresholds) minute)) + (setq thresholds (cdr thresholds) + index (1+ index))) + index)) + (defsubst datetime--digits-format (num-repetitions) (if (> num-repetitions 1) (format "%%0%dd" num-repetitions) "%d")) @@ -616,6 +637,13 @@ to this function. (setq need-hour t) (push "%s" format-parts) (push `(aref ,(datetime-locale-field locale :am-pm) (if (>= hour 12) 1 0)) format-arguments)) + (`day-period + (setq need-time t) + (push "%s" format-parts) + (let* ((day-period-data (datetime-locale-field locale :day-periods)) + (thresholds (plist-get day-period-data :thresholds)) + (strings (or (plist-get day-period-data details) (plist-get day-period-data :short)))) + (push `(aref ,strings (datetime--day-period-index ',thresholds (/ time 60))) format-arguments))) ((or `hour-0-23 `hour-1-24 `hour-am-pm-0-11 `hour-am-pm-1-12) (setq need-hour t) (push (datetime--digits-format details) format-parts) @@ -950,6 +978,7 @@ unless specified otherwise. month-name-part-indices day-of-month-part-indices am-pm-part-indices + day-period-part-indices hour-0-23-part-indices hour-1-24-part-indices hour-am-pm-1-12-part-indices @@ -1006,6 +1035,10 @@ unless specified otherwise. (`am-pm (when (or validating (null am-pm-part-indices)) (push part-index am-pm-part-indices)) (datetime-locale-field locale :am-pm)) + (`day-period (when (or validating (null day-period-part-indices)) + (push part-index day-period-part-indices)) + (let ((day-period-data (datetime-locale-field locale :day-periods))) + (or (plist-get day-period-data details) (plist-get day-period-data :short)))) (`hour-0-23 (when (or validating (null hour-0-23-part-indices)) (push part-index hour-0-23-part-indices)) 23) @@ -1075,6 +1108,7 @@ unless specified otherwise. month-name-part-indices (nreverse month-name-part-indices) day-of-month-part-indices (nreverse day-of-month-part-indices) am-pm-part-indices (nreverse am-pm-part-indices) + day-period-part-indices (nreverse day-period-part-indices) hour-0-23-part-indices (nreverse hour-0-23-part-indices) hour-1-24-part-indices (nreverse hour-1-24-part-indices) hour-am-pm-1-12-part-indices (nreverse hour-am-pm-1-12-part-indices) @@ -1098,7 +1132,7 @@ unless specified otherwise. (let* ((regexp-parts regexp-parts) (substituting-indices-in (list era-part-indices year-part-indices month-number-part-indices month-name-part-indices day-of-month-part-indices - am-pm-part-indices + am-pm-part-indices day-period-part-indices hour-0-23-part-indices hour-1-24-part-indices hour-am-pm-1-12-part-indices hour-am-pm-0-11-part-indices minute-part-indices second-part-indices second-fractional-part-indices)) (part-index 0) @@ -1140,6 +1174,7 @@ unless specified otherwise. (am-pm-computation (or (datetime--parser-computation pattern "am-pm" validating nil nil (am-pm-part-indices (datetime--parser-string-if-computation locale :am-pm downcased 0 12) t)) (plist-get 'am-pm 0) 0)) + (_day-period-computation) ;; FIXME: Write; currently not validated for consistency with actual time. (hour-computation (or (datetime--parser-computation pattern "hour" validating nil 23 (hour-0-23-part-indices datetime--parser-int-computation) (hour-1-24-part-indices datetime--parser-hour-1-24-computation) @@ -1368,6 +1403,9 @@ specified otherwise. (datetime-locale-field locale (if (eq details 'abbreviated) :weekday-standalone-abbr :weekday-standalone-names))) (`am-pm (datetime-locale-field locale :am-pm)) + (`day-period + (let ((day-period-data (datetime-locale-field locale :day-periods))) + (or (plist-get day-period-data details) (plist-get day-period-data :short)))) (`hour-0-23 23) (`hour-1-24 24) (`hour-am-pm-0-11 11) @@ -1468,7 +1506,7 @@ options can affect result of this function." OPTIONS are passed to `datetime-recode-pattern'. Currently no options can affect result of this function." (datetime--pattern-includes-p type pattern options - am-pm hour-0-23 hour-1-24 hour-am-pm-0-11 hour-am-pm-1-12 minute second second-fractional)) + am-pm day-period hour-0-23 hour-1-24 hour-am-pm-0-11 hour-am-pm-1-12 minute second second-fractional)) (defun datetime-pattern-includes-era-p (type pattern &rest options) "Determine if PATTERN includes the date era. @@ -1649,7 +1687,7 @@ Supported fields: :weekday-standalone-abbr :weekday-standalone-names :am-pm" - ;; Additionally `:date-patterns', `:time-patterns' and + ;; Additionally `:day-periods', `:date-patterns', `:time-patterns' and ;; `:date-time-pattern-rule' are supported for internal use. (let ((data (extmap-get datetime--locale-extmap locale t))) (or (datetime--do-get-locale-field data field) @@ -1698,7 +1736,7 @@ create based on locales `datetime' knows about. Note that this database doesn't include timezone names. See `datetime-timezone-name-database-version'." - 4) + 5) (defun datetime-timezone-database-version () "Return timezone database version, a simple integer. @@ -1708,7 +1746,7 @@ create based on timezones `datetime' knows about and their rules. Locale-specific timezone names are contained in a different database. See `datetime-timezone-name-database-version'." - 6) + 7) (defun datetime-timezone-name-database-version () "Return timezone name database version, a simple integer. @@ -1721,7 +1759,7 @@ Other locale-specific data as well as locale-independent data about timezones is contained in different databases. See `datetime-locale-database-version' and `datetime-timezone-database-version'." - 3) + 4) (provide 'datetime) diff --git a/dev/HarvestData.java b/dev/HarvestData.java index 41e785230d..7eb866dc55 100644 --- a/dev/HarvestData.java +++ b/dev/HarvestData.java @@ -81,6 +81,7 @@ public class HarvestData map.put (":weekday-standalone-abbr", toLispVector (getNames (locale, ChronoField.DAY_OF_WEEK, "ccc", 1, 7))); map.put (":weekday-standalone-names", toLispVector (getNames (locale, ChronoField.DAY_OF_WEEK, "cccc", 1, 7))); map.put (":am-pm", toLispVector (getNames (locale, ChronoField.AMPM_OF_DAY, "a", 0, 1))); + map.put (":day-periods", findDayPeriodData (locale)); Map <String, String> date_patterns = toPatternPlist ((style) -> DateTimeFormatterBuilder.getLocalizedDateTimePattern (style, null, chronology, locale)); Map <String, String> time_patterns = toPatternPlist ((style) -> DateTimeFormatterBuilder.getLocalizedDateTimePattern (null, style, chronology, locale)); @@ -194,6 +195,45 @@ public class HarvestData return names; } + protected static String findDayPeriodData (Locale locale) + { + var time = LocalDateTime.of (2001, 1, 1, 0, 0, 0); + var formatters = List.of (DateTimeFormatter.ofPattern ("B", locale), + DateTimeFormatter.ofPattern ("BBBB", locale), + DateTimeFormatter.ofPattern ("BBBBB", locale)); + List <String> strings = null; + var periods = new ArrayList <List <String>> (); + var thresholds = new ArrayList <Integer> (); + + // It seems the thresholds are not exposed, so we find them like this. + for (int minute = 0; minute < 24 * 60; minute++, time = time.plusMinutes (1)) { + var time_ = time; + var new_strings = formatters.stream ().map ((formatter) -> formatter.format (time_)).toList (); + + if (!Objects.equals (new_strings, strings)) { + periods.add (new_strings); + if (minute > 0) + thresholds.add (minute); + + strings = new_strings; + } + } + + var data = new LinkedHashMap <String, String> (); + + data.put (":thresholds", toLispList (thresholds)); + data.put (":short", toLispVector (periods.stream ().map ((strings_) -> strings_.get (0)).toList (), true)); + data.put (":full", toLispVector (periods.stream ().map ((strings_) -> strings_.get (1)).toList (), true)); + data.put (":narrow", toLispVector (periods.stream ().map ((strings_) -> strings_.get (2)).toList (), true)); + + if (Objects.equals (data.get (":full"), data.get (":short"))) + data.remove (":full"); + if (Objects.equals (data.get (":narrow"), data.get (":short"))) + data.remove (":narrow"); + + return toLispPlist (data, false); + } + protected static void removeUnnecessaryLocaleData (Map <Locale, Map <String, String>> data, Locale locale) { Map <String, String> locale_data = data.get (locale); @@ -212,6 +252,7 @@ public class HarvestData removeForFallback1 (locale_data, parent_data, ":decimal-separator", "?."); removeForFallback1 (locale_data, parent_data, ":eras", ENGLISH_ERAS); removeForFallback1 (locale_data, parent_data, ":am-pm", ENGLISH_AM_PM); + removeForFallback1 (locale_data, parent_data, ":day-periods", null); removeForFallback1 (locale_data, parent_data, ":date-time-pattern-rule", "(t . \" \")"); removeForFallback2 (locale_data, parent_data, ":month-standalone-abbr", ":month-context-abbr"); diff --git a/locale-data.extmap b/locale-data.extmap index cdccd85e21..04bab090b0 100644 Binary files a/locale-data.extmap and b/locale-data.extmap differ diff --git a/test/format.el b/test/format.el index faf7b47e23..c31f246aa9 100644 --- a/test/format.el +++ b/test/format.el @@ -119,3 +119,15 @@ ;; Rule-based transition on 2014-10-26. Should also result in ;; timezone name changing between CEST and CET. (datetime--test-formatter-around-transition 1414285200))) + +(ert-deftest datetime-formatting-day-periods () + (let (times) + (dotimes (minute (* 24 60)) + (push (* minute 60) times)) + (setf times (nreverse times)) + (dolist (pattern '("HH:mm:ss B" "HH:mm:ss BBBB" "HH:mm:ss BBBBB")) + (datetime--test-set-up-formatter 'UTC 'en pattern + (datetime--test-formatter times))))) + + +(provide 'test/format) diff --git a/test/parse.el b/test/parse.el index 7084f8eed3..3adf91e4fa 100644 --- a/test/parse.el +++ b/test/parse.el @@ -159,3 +159,6 @@ (dolist (timezone (datetime-list-timezones)) (datetime--test-set-up-parser timezone 'en "yyyyMMddHHmmss" (datetime--test-parser '("20220506123000"))))) + + +(provide 'test/parse) diff --git a/timezone-data.extmap b/timezone-data.extmap index f0882fe52b..bf074b459f 100644 Binary files a/timezone-data.extmap and b/timezone-data.extmap differ diff --git a/timezone-name-data.extmap b/timezone-name-data.extmap index 82eb48f17d..80ab282566 100644 Binary files a/timezone-name-data.extmap and b/timezone-name-data.extmap differ