From 6a3b89f9df85d0718e55d460164ff65e7bdd823e Mon Sep 17 00:00:00 2001 From: Jean Forget Date: Fri, 23 Jul 2021 15:26:40 +0200 Subject: [PATCH] Add more support for the French Revolutionary Calendar * lisp/calendar/cal-french.el (calendar-french-feasts-array): New variable (bug#19174). (calendar-french-trim-feast): New function. (calendar-french-date-string, calendar-french-goto-date): (calendar-french-goto-date): Use them. http://datetime.mongueurs.net/Histoire/s-c/01-g.en.html https://metacpan.org/pod/DateTime::Calendar::FrenchRevolutionary#Internet --- lisp/calendar/cal-french.el | 192 ++++++++++++++++++++++--- test/lisp/calendar/cal-french-tests.el | 113 +++++++++++++++ 2 files changed, 284 insertions(+), 21 deletions(-) create mode 100644 test/lisp/calendar/cal-french-tests.el diff --git a/lisp/calendar/cal-french.el b/lisp/calendar/cal-french.el index 639bae700cc..cc18a2a5d8e 100644 --- a/lisp/calendar/cal-french.el +++ b/lisp/calendar/cal-french.el @@ -40,12 +40,13 @@ (defconst calendar-french-month-name-array ["Vendémiaire" "Brumaire" "Frimaire" "Nivôse" "Pluviôse" "Ventôse" - "Germinal" "Floréal" "Prairial" "Messidor" "Thermidor" "Fructidor"] + "Germinal" "Floréal" "Prairial" "Messidor" "Thermidor" "Fructidor" + "jour complémentaire"] "Array of month names in the French calendar.") (defconst calendar-french-day-name-array ["Primidi" "Duodi" "Tridi" "Quartidi" "Quintidi" "Sextidi" "Septidi" - "Octidi" "Nonidi" "Decadi"] + "Octidi" "Nonidi" "Décadi"] "Array of day names in the French calendar.") (define-obsolete-variable-alias 'calendar-french-multibyte-special-days-array @@ -56,6 +57,144 @@ "de la Révolution"] "Array of special day names in the French calendar.") +(defconst calendar-french-feasts-array + [;; Vendémiaire + "du Raisin" "du Safran" "de la Châtaigne" + "de la Colchique" "du Cheval" "de la Balsamine" + "de la Carotte" "de l'Amarante" "du Panais" + "de la Cuve" "de la Pomme de terre" "de l'Immortelle" + "du Potiron" "du Réséda" "de l'Âne" + "de la Belle de nuit" "de la Citrouille" "du Sarrasin" + "du Tournesol" "du Pressoir" "du Chanvre" + "de la Pêche" "du Navet" "de l'Amaryllis" + "du Bœuf" "de l'Aubergine" "du Piment" + "de la Tomate" "de l'Orge" "du Tonneau" + ;; Brumaire + "de la Pomme" "du Céleri" "de la Poire" + "de la Betterave" "de l'Oie" "de l'Héliotrope" + "de la Figue" "de la Scorsonère" "de l'Alisier" + "de la Charrue" "du Salsifis" "de la Macre" + "du Topinambour" "de l'Endive" "du Dindon" + "du Chervis" "du Cresson" "de la Dentelaire" + "de la Grenade" "de la Herse" "de la Bacchante" + "de l'Azerole" "de la Garance" "de l'Orange" + "du Faisan" "de la Pistache" "du Macjon" + "du Coing" "du Cormier" "du Rouleau" + ;; Frimaire + "de la Raiponce" "du Turneps" "de la Chicorée" + "de la Nèfle" "du Cochon" "de la Mâche" + "du Chou-fleur" "du Miel" "du Genièvre" + "de la Pioche" "de la Cire" "du Raifort" + "du Cèdre" "du Sapin" "du Chevreuil" + "de l'Ajonc" "du Cyprès" "du Lierre" + "de la Sabine" "du Hoyau" "de l'Érable-sucre" + "de la Bruyère" "du Roseau" "de l'Oseille" + "du Grillon" "du Pignon" "du Liège" + "de la Truffe" "de l'Olive" "de la Pelle" + ;; Nivôse + "de la Tourbe" "de la Houille" "du Bitume" + "du Soufre" "du Chien" "de la Lave" + "de la Terre végétale" "du Fumier" "du Salpêtre" + "du Fléau" "du Granit" "de l'Argile" + "de l'Ardoise" "du Grès" "du Lapin" + "du Silex" "de la Marne" "de la Pierre à chaux" + "du Marbre" "du Van" "de la Pierre à plâtre" + "du Sel" "du Fer" "du Cuivre" + "du Chat" "de l'Étain" "du Plomb" + "du Zinc" "du Mercure" "du Crible" + ;; Pluviôse + "de la Lauréole" "de la Mousse" "du Fragon" + "du Perce-neige" "du Taureau" "du Laurier-thym" + "de l'Amadouvier" "du Mézéréon" "du Peuplier" + "de la Cognée" "de l'Ellébore" "du Brocoli" + "du Laurier" "de l'Avelinier" "de la Vache" + "du Buis" "du Lichen" "de l'If" + "de la Pulmonaire" "de la Serpette" "du Thlaspi" + "du Thymelé" "du Chiendent" "de la Traînasse" + "du Lièvre" "de la Guède" "du Noisetier" + "du Cyclamen" "de la Chélidoine" "du Traîneau" + ;; Ventôse + "du Tussilage" "du Cornouiller" "du Violier" + "du Troène" "du Bouc" "de l'Asaret" + "de l'Alaterne" "de la Violette" "du Marsault" + "de la Bêche" "du Narcisse" "de l'Orme" + "de la Fumeterre" "du Vélar" "de la Chèvre" + "de l'Épinard" "du Doronic" "du Mouron" + "du Cerfeuil" "du Cordeau" "de la Mandragore" + "du Persil" "du Cochléaria" "de la Pâquerette" + "du Thon" "du Pissenlit" "de la Sylvie" + "du Capillaire" "du Frêne" "du Plantoir" + ;; Germinal + "de la Primevère" "du Platane" "de l'Asperge" + "de la Tulipe" "de la Poule" "de la Blette" + "du Bouleau" "de la Jonquille" "de l'Aulne" + "du Couvoir" "de la Pervenche" "du Charme" + "de la Morille" "du Hêtre" "de l'Abeille" + "de la Laitue" "du Mélèze" "de la Ciguë" + "du Radis" "de la Ruche" "du Gainier" + "de la Romaine" "du Marronnier" "de la Roquette" + "du Pigeon" "du Lilas" "de l'Anémone" + "de la Pensée" "de la Myrtille" "du Greffoir" + ;; Floréal + "de la Rose" "du Chêne" "de la Fougère" + "de l'Aubépine" "du Rossignol" "de l'Ancolie" + "du Muguet" "du Champignon" "de la Jacinthe" + "du Rateau" "de la Rhubarbe" "du Sainfoin" + "du Bâton-d'or" "du Chamérisier" "du Ver à soie" + "de la Consoude" "de la Pimprenelle" "de la Corbeille-d'or" + "de l'Arroche" "du Sarcloir" "du Statice" + "de la Fritillaire" "de la Bourrache" "de la Valériane" + "de la Carpe" "du Fusain" "de la Civette" + "de la Buglosse" "du Sénevé" "de la Houlette" + ;; Prairial + "de la Luzerne" "de l'Hémérocalle" "du Trèfle" + "de l'Angélique" "du Canard" "de la Mélisse" + "du Fromental" "du Martagon" "du Serpolet" + "de la Faux" "de la Fraise" "de la Bétoine" + "du Pois" "de l'Acacia" "de la Caille" + "de l'Œillet" "du Sureau" "du Pavot" + "du Tilleul" "de la Fourche" "du Barbeau" + "de la Camomille" "du Chèvrefeuille" "du Caille-lait" + "de la Tanche" "du Jasmin" "de la Verveine" + "du Thym" "de la Pivoine" "du Chariot" + ;; Messidor + "du Seigle" "de l'Avoine" "de l'Oignon" + "de la Véronique" "du Mulet" "du Romarin" + "du Concombre" "de l'Échalotte" "de l'Absinthe" + "de la Faucille" "de la Coriandre" "de l'Artichaut" + "de la Giroflée" "de la Lavande" "du Chamois" + "du Tabac" "de la Groseille" "de la Gesse" + "de la Cerise" "du Parc" "de la Menthe" + "du Cumin" "du Haricot" "de l'Orcanète" + "de la Pintade" "de la Sauge" "de l'Ail" + "de la Vesce" "du Blé" "de la Chalémie" + ;; Thermidor + "de l'Épautre" "du Bouillon-blanc" "du Melon" + "de l'Ivraie" "du Bélier" "de la Prèle" + "de l'Armoise" "du Carthame" "de la Mûre" + "de l'Arrosoir" "du Panis" "du Salicor" + "de l'Abricot" "du Basilic" "de la Brebis" + "de la Guimauve" "du Lin" "de l'Amande" + "de la Gentiane" "de l'Écluse" "de la Carline" + "du Câprier" "de la Lentille" "de l'Aunée" + "de la Loutre" "de la Myrte" "du Colza" + "du Lupin" "du Coton" "du Moulin" + ;; Fructidor + "de la Prune" "du Millet" "du Lycoperdon" + "de l'Escourgeon" "du Saumon" "de la Tubéreuse" + "du Sucrion" "de l'Apocyn" "de la Réglisse" + "de l'Échelle" "de la Pastèque" "du Fenouil" + "de l'Épine-vinette" "de la Noix" "de la Truite" + "du Citron" "de la Cardère" "du Nerprun" + "du Tagette" "de la Hotte" "de l'Églantier" + "de la Noisette" "du Houblon" "du Sorgho" + "de l'Écrevisse" "de la Bagarade" "de la Verge-d'or" + "du Maïs" "du Marron" "du Panier" + ;; jour complémentaire + "de la Vertu" "du Génie" "du Travail" + "de la Raison" "des Récompenses" "de la Révolution"] + "Array of day feasts in the French calendar.") + (defun calendar-french-accents-p () (declare (obsolete nil "28.1")) t) @@ -75,6 +214,16 @@ (declare (obsolete "use the variable of the same name instead" "28.1")) calendar-french-special-days-array) +(defun calendar-french-trim-feast (feast) + "Remove the article from the feast, e.g. \"du Raisin\" -> \"Raisin\" +or \"de la Vertu\" -> \"Vertu\"" + (cond + ((equal (substring feast 0 3) "du ") (substring feast 3)) + ((equal (substring feast 0 6) "de la ") (substring feast 6)) + ((equal (substring feast 0 5) "de l'") (substring feast 5)) + ((equal (substring feast 0 4) "des ") (substring feast 4)) + (t feast))) + (defun calendar-french-leap-year-p (year) "True if YEAR is a leap year on the French Revolutionary calendar. For Gregorian years 1793 to 1805, the years of actual operation of the @@ -162,14 +311,13 @@ Defaults to today's date if DATE is not given." (d (calendar-extract-day french-date))) (cond ((< y 1) "") - ((= m 13) (format "Jour %s de l'Année %d de la Révolution" - (aref calendar-french-special-days-array (1- d)) - y)) (t (format - "%d %s an %d de la Révolution" + "%s %d %s an %d de la Révolution, jour %s" + (aref calendar-french-day-name-array (% (1- d) 10)) d (aref calendar-french-month-name-array (1- m)) - y))))) + y + (aref calendar-french-feasts-array (+ -31 (* 30 m) d))))))) ;;;###cal-autoload (defun calendar-french-print-date () @@ -186,7 +334,7 @@ Defaults to today's date if DATE is not given." Echo French Revolutionary date unless NOECHO is non-nil." (interactive (let* ((months calendar-french-month-name-array) - (special-days calendar-french-special-days-array) + (feasts calendar-french-feasts-array) (year (progn (calendar-read-sexp "Année de la Révolution (>0)" @@ -199,29 +347,31 @@ Echo French Revolutionary date unless NOECHO is non-nil." (mapcar 'list (append months (if (calendar-french-leap-year-p year) - (mapcar - (lambda (x) (concat "Jour " x)) - calendar-french-special-days-array) + (mapcar #'calendar-french-trim-feast feasts) (reverse (cdr ; we don't want rev. day in a non-leap yr (reverse - (mapcar - (lambda (x) - (concat "Jour " x)) - special-days)))))))) + (mapcar #'calendar-french-trim-feast + feasts)))))))) (completion-ignore-case t) (month (cdr (assoc-string (completing-read - "Mois ou Sansculottide: " + "Mois ou \"jour complémentaire\" ou fête: " month-list nil t) (calendar-make-alist month-list 1 'car) t))) - (day (if (> month 12) - (- month 12) + (last-day (calendar-french-last-day-of-month (min month 13) year)) + (day (if (> month 13) + (- month 13) (calendar-read-sexp - "Jour (1-30)" - (lambda (x) (and (<= 1 x) (<= x 30)))))) - (month (if (> month 12) 13 month))) + (format "Jour (1-%d): " last-day) + (lambda (x) (<= 1 x last-day))))) + ;; All days in Vendémiaire and numbered 1 to 365 e.g., "Pomme" + ;; gives 31 Vendémiaire automatically normalized to 1 Brumaire + ;; "Céleri" gives 32 Vnd normalized to 2 Bru, "Raiponce" gives + ;; 61 Vnd normalized to 1 Frimaire, etc until "Récompences" which + ;; gives 365 Vnd normalized to 5 jour complémentaire. + (month (if (> month 13) 1 month))) (list (list month day year)))) (calendar-goto-date (calendar-gregorian-from-absolute (calendar-french-to-absolute date))) diff --git a/test/lisp/calendar/cal-french-tests.el b/test/lisp/calendar/cal-french-tests.el new file mode 100644 index 00000000000..ab62c1e6fc1 --- /dev/null +++ b/test/lisp/calendar/cal-french-tests.el @@ -0,0 +1,113 @@ +;;; cal-french-tests.el --- tests for cal-french.el -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'ert) +(require 'cal-french) + +(defconst cal-french-test-cases + '( + (1792 9 22 "Primidi 1 Vendémiaire an 1 de la Révolution, jour du Raisin") + (1793 10 23 "Duodi 2 Brumaire an 2 de la Révolution, jour du Céleri") + (1794 7 27 "Nonidi 9 Thermidor an 2 de la Révolution, jour de la Mûre") + (1794 11 23 "Tridi 3 Frimaire an 3 de la Révolution, jour de la Chicorée") + (1795 10 5 "Tridi 13 Vendémiaire an 4 de la Révolution, jour du Potiron") + (1795 12 25 "Quartidi 4 Nivôse an 4 de la Révolution, jour du Soufre") + (1797 1 24 "Quintidi 5 Pluviôse an 5 de la Révolution, jour du Taureau") + (1798 2 24 "Sextidi 6 Ventôse an 6 de la Révolution, jour de l'Asaret") + (1799 11 9 "Octidi 18 Brumaire an 8 de la Révolution, jour de la Dentelaire") + (1801 3 29 "Octidi 8 Germinal an 9 de la Révolution, jour de la Jonquille") + (1804 4 30 "Décadi 10 Floréal an 12 de la Révolution, jour du Rateau") + (1807 6 1 "Duodi 12 Prairial an 15 de la Révolution, jour de la Bétoine") + (1810 7 3 "Quartidi 14 Messidor an 18 de la Révolution, jour de la Lavande") + (1813 8 4 "Sextidi 16 Thermidor an 21 de la Révolution, jour de la Guimauve") + (1816 9 4 "Octidi 18 Fructidor an 24 de la Révolution, jour du Nerprun") + (2000 1 1 "Duodi 12 Nivôse an 208 de la Révolution, jour de l'Argile") + (2021 7 11 "Tridi 23 Messidor an 229 de la Révolution, jour du Haricot") + (2001 5 11 "Duodi 22 Floréal an 209 de la Révolution, jour de la Fritillaire") + (1792 9 22 "Primidi 1 Vendémiaire an 1 de la Révolution, jour du Raisin") + (1793 9 21 "Quintidi 5 jour complémentaire an 1 de la Révolution, jour des Récompenses") + (1793 9 22 "Primidi 1 Vendémiaire an 2 de la Révolution, jour du Raisin") + (1794 9 21 "Quintidi 5 jour complémentaire an 2 de la Révolution, jour des Récompenses") + (1794 9 22 "Primidi 1 Vendémiaire an 3 de la Révolution, jour du Raisin") + (1795 9 22 "Sextidi 6 jour complémentaire an 3 de la Révolution, jour de la Révolution") + (1795 9 23 "Primidi 1 Vendémiaire an 4 de la Révolution, jour du Raisin") + (1796 9 21 "Quintidi 5 jour complémentaire an 4 de la Révolution, jour des Récompenses") + (1796 9 22 "Primidi 1 Vendémiaire an 5 de la Révolution, jour du Raisin") + (1797 9 21 "Quintidi 5 jour complémentaire an 5 de la Révolution, jour des Récompenses") + (1797 9 22 "Primidi 1 Vendémiaire an 6 de la Révolution, jour du Raisin") + (1799 9 22 "Sextidi 6 jour complémentaire an 7 de la Révolution, jour de la Révolution") + (1799 9 23 "Primidi 1 Vendémiaire an 8 de la Révolution, jour du Raisin") + (1800 9 22 "Quintidi 5 jour complémentaire an 8 de la Révolution, jour des Récompenses") + (1800 9 23 "Primidi 1 Vendémiaire an 9 de la Révolution, jour du Raisin") + (1801 9 22 "Quintidi 5 jour complémentaire an 9 de la Révolution, jour des Récompenses") + (1801 9 23 "Primidi 1 Vendémiaire an 10 de la Révolution, jour du Raisin") + (1823 9 22 "Quintidi 5 jour complémentaire an 31 de la Révolution, jour des Récompenses") + (1823 9 23 "Primidi 1 Vendémiaire an 32 de la Révolution, jour du Raisin") + (1824 9 22 "Sextidi 6 jour complémentaire an 32 de la Révolution, jour de la Révolution") + (1824 9 23 "Primidi 1 Vendémiaire an 33 de la Révolution, jour du Raisin") + (1825 9 22 "Quintidi 5 jour complémentaire an 33 de la Révolution, jour des Récompenses") + (1825 9 23 "Primidi 1 Vendémiaire an 34 de la Révolution, jour du Raisin") + (1892 9 21 "Quintidi 5 jour complémentaire an 100 de la Révolution, jour des Récompenses") + (1892 9 22 "Primidi 1 Vendémiaire an 101 de la Révolution, jour du Raisin") + (1900 9 22 "Sextidi 6 jour complémentaire an 108 de la Révolution, jour de la Révolution") + (1900 9 23 "Primidi 1 Vendémiaire an 109 de la Révolution, jour du Raisin") + (1992 9 21 "Quintidi 5 jour complémentaire an 200 de la Révolution, jour des Récompenses") + (1992 9 22 "Primidi 1 Vendémiaire an 201 de la Révolution, jour du Raisin") + (2000 9 21 "Sextidi 6 jour complémentaire an 208 de la Révolution, jour de la Révolution") + (2000 9 22 "Primidi 1 Vendémiaire an 209 de la Révolution, jour du Raisin") + (2092 9 20 "Quintidi 5 jour complémentaire an 300 de la Révolution, jour des Récompenses") + (2092 9 21 "Primidi 1 Vendémiaire an 301 de la Révolution, jour du Raisin") + (2100 9 21 "Sextidi 6 jour complémentaire an 308 de la Révolution, jour de la Révolution") + (2100 9 22 "Primidi 1 Vendémiaire an 309 de la Révolution, jour du Raisin") + (2192 9 21 "Sextidi 6 jour complémentaire an 400 de la Révolution, jour de la Révolution") + (2192 9 22 "Primidi 1 Vendémiaire an 401 de la Révolution, jour du Raisin") + (2193 9 21 "Quintidi 5 jour complémentaire an 401 de la Révolution, jour des Récompenses") + (2199 9 22 "Primidi 1 Vendémiaire an 408 de la Révolution, jour du Raisin") + (2200 9 22 "Sextidi 6 jour complémentaire an 408 de la Révolution, jour de la Révolution") + (2791 9 23 "Primidi 1 Vendémiaire an 1000 de la Révolution, jour du Raisin") + (2792 9 22 "Primidi 1 Vendémiaire an 1001 de la Révolution, jour du Raisin") + (3000 1 1 "Duodi 12 Nivôse an 1208 de la Révolution, jour de l'Argile") + (3001 1 1 "Primidi 11 Nivôse an 1209 de la Révolution, jour du Granit") + (3791 9 22 "Primidi 1 Vendémiaire an 2000 de la Révolution, jour du Raisin") + (3792 9 22 "Primidi 1 Vendémiaire an 2001 de la Révolution, jour du Raisin") + (4000 1 1 "Duodi 12 Nivôse an 2208 de la Révolution, jour de l'Argile") + (4001 1 1 "Duodi 12 Nivôse an 2209 de la Révolution, jour de l'Argile") + (4320 9 10 "Quartidi 24 Fructidor an 2528 de la Révolution, jour du Sorgho") + (4320 9 11 "Quintidi 25 Fructidor an 2528 de la Révolution, jour de l'Écrevisse") + (4791 9 23 "Primidi 1 Vendémiaire an 3000 de la Révolution, jour du Raisin") + (4792 9 22 "Primidi 1 Vendémiaire an 3001 de la Révolution, jour du Raisin") + (5000 1 1 "Duodi 12 Nivôse an 3208 de la Révolution, jour de l'Argile") + (5001 1 1 "Primidi 11 Nivôse an 3209 de la Révolution, jour du Granit") + (5791 9 22 "Primidi 1 Vendémiaire an 4000 de la Révolution, jour du Raisin") + (5792 9 21 "Primidi 1 Vendémiaire an 4001 de la Révolution, jour du Raisin") + (6000 1 1 "Tridi 13 Nivôse an 4208 de la Révolution, jour de l'Ardoise") + (6001 1 1 "Tridi 13 Nivôse an 4209 de la Révolution, jour de l'Ardoise") + (6791 9 22 "Primidi 1 Vendémiaire an 5000 de la Révolution, jour du Raisin") + (6792 9 21 "Primidi 1 Vendémiaire an 5001 de la Révolution, jour du Raisin") + (7791 9 21 "Primidi 1 Vendémiaire an 6000 de la Révolution, jour du Raisin") + (7792 9 21 "Primidi 1 Vendémiaire an 6001 de la Révolution, jour du Raisin") + )) + +(ert-deftest cal-french-tests () + (pcase-dolist (`(,y ,m ,d ,str) cal-french-test-cases) + (should (equal (calendar-french-date-string (list m d y)) str)))) + +(provide 'cal-french-tests) -- 2.39.2