1 ;;; cal-french.el --- calendar functions for the French Revolutionary calendar
3 ;; Copyright (C) 1988-1989, 1992, 1994-1995, 1997, 2001-2017 Free
4 ;; Software Foundation, Inc.
6 ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
7 ;; Maintainer: Glenn Morris <rgm@gnu.org>
9 ;; Human-Keywords: French Revolutionary calendar, calendar, diary
12 ;; This file is part of GNU Emacs.
14 ;; GNU Emacs is free software: you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation, either version 3 of the License, or
17 ;; (at your option) any later version.
19 ;; GNU Emacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
35 (defconst calendar-french-epoch
(calendar-absolute-from-gregorian '(9 22 1792))
36 "Absolute date of start of French Revolutionary calendar = Sept 22, 1792.")
38 (defconst calendar-french-month-name-array
39 ["Vende'miaire" "Brumaire" "Frimaire" "Nivo^se" "Pluvio^se" "Vento^se"
40 "Germinal" "Flore'al" "Prairial" "Messidor" "Thermidor" "Fructidor"]
41 "Array of month names in the French calendar.")
43 (defconst calendar-french-multibyte-month-name-array
44 ["Vendémiaire" "Brumaire" "Frimaire" "Nivôse" "Pluviôse" "Ventôse"
45 "Germinal" "Floréal" "Prairial" "Messidor" "Thermidor" "Fructidor"]
46 "Array of multibyte month names in the French calendar.")
48 (defconst calendar-french-day-name-array
49 ["Primidi" "Duodi" "Tridi" "Quartidi" "Quintidi" "Sextidi" "Septidi"
50 "Octidi" "Nonidi" "Decadi"]
51 "Array of day names in the French calendar.")
53 (defconst calendar-french-special-days-array
54 ["de la Vertu" "du Ge'nie" "du Travail" "de la Raison" "des Re'compenses"
56 "Array of special day names in the French calendar.")
58 (defconst calendar-french-multibyte-special-days-array
59 ["de la Vertu" "du Génie" "du Travail" "de la Raison" "des Récompenses"
61 "Array of multibyte special day names in the French calendar.")
63 (defun calendar-french-accents-p ()
64 "Return non-nil if diacritical marks are available."
65 (and (or window-system
66 (terminal-coding-system))
67 (or enable-multibyte-characters
68 (and (char-table-p standard-display-table
)
69 (equal (aref standard-display-table
161) [161])))))
71 (defun calendar-french-month-name-array ()
72 "Return the array of month names, depending on whether accents are available."
73 (if (calendar-french-accents-p)
74 calendar-french-multibyte-month-name-array
75 calendar-french-month-name-array))
77 (defun calendar-french-day-name-array ()
78 "Return the array of day names."
79 calendar-french-day-name-array)
81 (defun calendar-french-special-days-array ()
82 "Return the special day names, depending on whether accents are available."
83 (if (calendar-french-accents-p)
84 calendar-french-multibyte-special-days-array
85 calendar-french-special-days-array))
87 (defun calendar-french-leap-year-p (year)
88 "True if YEAR is a leap year on the French Revolutionary calendar.
89 For Gregorian years 1793 to 1805, the years of actual operation of the
90 calendar, follows historical practice based on equinoxes (years 3, 7,
91 and 11 were leap years; 15 and 20 would have been leap years). For later
92 years uses the proposed rule of Romme (never adopted)--leap years fall every
93 four years except century years not divisible 400 and century years that are
95 (or (memq year '(3 7 11)) ; actual practice--based on equinoxes
96 (memq year '(15 20)) ; anticipated practice--based on equinoxes
97 (and (> year 20) ; Romme's proposal--never adopted
99 (not (memq (% year 400) '(100 200 300)))
100 (not (zerop (% year 4000))))))
102 (defun calendar-french-last-day-of-month (month year)
103 "Return last day of MONTH, YEAR on the French Revolutionary calendar.
104 The 13th month is not really a month, but the 5 (6 in leap years) day period of
105 `sansculottides' at the end of the year."
108 (if (calendar-french-leap-year-p year)
112 (defun calendar-french-to-absolute (date)
113 "Compute absolute date from French Revolutionary date DATE.
114 The absolute date is the number of days elapsed since the (imaginary)
115 Gregorian date Sunday, December 31, 1 BC."
116 (let ((month (calendar-extract-month date))
117 (day (calendar-extract-day date))
118 (year (calendar-extract-year date)))
119 (+ (* 365 (1- year)) ; days in prior years
120 ;; Leap days in prior years.
122 (/ year 4) ; actual and anticipated practice (years 3, 7, 11, 15)
123 ;; Romme's proposed rule (using the Principle of Inclusion/Exclusion).
124 (+ (/ (1- year) 4) ; luckily, there were 4 leap years before year 20
125 (- (/ (1- year) 100))
127 (- (/ (1- year) 4000))))
128 (* 30 (1- month)) ; days in prior months this year
129 day ; days so far this month
130 (1- calendar-french-epoch)))) ; days before start of calendar
132 (defun calendar-french-from-absolute (date)
133 "Compute the French Revolutionary equivalent for absolute date DATE.
134 The result is a list of the form (MONTH DAY YEAR).
135 The absolute date is the number of days elapsed since the
136 \(imaginary) Gregorian date Sunday, December 31, 1 BC."
137 (if (< date calendar-french-epoch)
138 (list 0 0 0) ; pre-French Revolutionary date
139 (let* ((approx ; approximation from below
140 (/ (- date calendar-french-epoch) 366))
141 (year ; search forward from the approximation
143 (calendar-sum y approx
144 (>= date (calendar-french-to-absolute
147 (month ; search forward from Vendemiaire
148 (1+ (calendar-sum m 1
150 (calendar-french-to-absolute
152 (calendar-french-last-day-of-month
156 (day ; calculate the day by subtraction
158 (1- (calendar-french-to-absolute (list month 1 year))))))
159 (list month day year))))
162 (defun calendar-french-date-string (&optional date)
163 "String of French Revolutionary date of Gregorian DATE.
164 Returns the empty string if DATE is pre-French Revolutionary.
165 Defaults to today's date if DATE is not given."
166 (let* ((french-date (calendar-french-from-absolute
167 (calendar-absolute-from-gregorian
168 (or date (calendar-current-date)))))
169 (y (calendar-extract-year french-date))
170 (m (calendar-extract-month french-date))
171 (d (calendar-extract-day french-date)))
174 ((= m 13) (format (if (calendar-french-accents-p)
175 "Jour %s de l'Année %d de la Révolution"
176 "Jour %s de l'Anne'e %d de la Re'volution")
177 (aref (calendar-french-special-days-array) (1- d))
180 (if (calendar-french-accents-p)
181 "%d %s an %d de la Révolution"
182 "%d %s an %d de la Re'volution")
184 (aref (calendar-french-month-name-array) (1- m))
188 (defun calendar-french-print-date ()
189 "Show the French Revolutionary calendar equivalent of the selected date."
191 (let ((f (calendar-french-date-string (calendar-cursor-to-date t))))
192 (if (string-equal f "")
193 (message "Date is pre-French Revolution")
194 (message "French Revolutionary date: %s" f))))
197 (defun calendar-french-goto-date (date &optional noecho)
198 "Move cursor to French Revolutionary date DATE.
199 Echo French Revolutionary date unless NOECHO is non-nil."
201 (let* ((months (calendar-french-month-name-array))
202 (special-days (calendar-french-special-days-array))
205 (if (calendar-french-accents-p)
206 "Année de la Révolution (>0): "
207 "Anne'e de la Re'volution (>0): ")
210 (calendar-extract-year
211 (calendar-french-from-absolute
212 (calendar-absolute-from-gregorian
213 (calendar-current-date))))))))
217 (if (calendar-french-leap-year-p year)
219 (lambda (x) (concat "Jour " x))
220 calendar-french-special-days-array)
222 (cdr ; we don't want rev. day in a non-leap yr
228 (completion-ignore-case t)
229 (month (cdr (assoc-string
231 "Mois ou Sansculottide: "
234 (calendar-make-alist month-list 1 'car) t)))
235 (day (if (> month 12)
239 (lambda (x) (and (<= 1 x) (<= x 30))))))
240 (month (if (> month 12) 13 month)))
241 (list (list month day year))))
242 (calendar-goto-date (calendar-gregorian-from-absolute
243 (calendar-french-to-absolute date)))
244 (or noecho (calendar-french-print-date)))
248 ;; To be called from diary-list-sexp-entries, where DATE is bound.
250 (defun diary-french-date ()
251 "French calendar equivalent of date diary entry."
252 (let ((f (calendar-french-date-string date)))
253 (if (string-equal f "")
254 "Date is pre-French Revolution"
255 (format "French Revolutionary date: %s" f))))
257 (provide 'cal-french)
259 ;;; cal-french.el ends here