Coverage Report

Created: 2025-10-19 21:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/a220/proj/radnelac/src/calendar/tranquility.rs
Line
Count
Source
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5
use crate::calendar::gregorian::Gregorian;
6
use crate::calendar::prelude::CommonDate;
7
use crate::calendar::prelude::HasLeapYears;
8
use crate::calendar::prelude::OrdinalDate;
9
use crate::calendar::prelude::Perennial;
10
use crate::calendar::prelude::Quarter;
11
use crate::calendar::prelude::ToFromCommonDate;
12
use crate::calendar::prelude::ToFromOrdinalDate;
13
use crate::calendar::CalendarMoment;
14
use crate::calendar::HasEpagemonae;
15
use crate::clock::ClockTime;
16
use crate::clock::TimeOfDay;
17
use crate::common::error::CalendarError;
18
use crate::common::math::TermNum;
19
use crate::day_count::BoundedDayCount;
20
use crate::day_count::CalculatedBounds;
21
use crate::day_count::Epoch;
22
use crate::day_count::Fixed;
23
use crate::day_count::FromFixed;
24
use crate::day_count::ToFixed;
25
use crate::day_cycle::Weekday;
26
#[allow(unused_imports)] //FromPrimitive is needed for derive
27
use num_traits::FromPrimitive;
28
use std::cmp::Ordering;
29
use std::num::NonZero;
30
31
const TRANQUILITY_EPOCH_GREGORIAN: CommonDate = CommonDate {
32
    year: 1969,
33
    month: 7,
34
    day: 20,
35
};
36
const NON_MONTH: u8 = 0;
37
38
const TRANQUILITY_EPOCH_CLOCK: ClockTime = ClockTime {
39
    hours: 20,
40
    minutes: 18,
41
    seconds: 1.2,
42
};
43
44
/// Represents a month of the Tranquility Calendar
45
///
46
/// The Tranquility months are named after famous historical figures.
47
///
48
/// Note that the complementary days of the Tranquility calendar year have no
49
/// month and thus are not represented by TranquilityMonth. When representing an
50
/// arbitrary day in the Tranquility calendar, use an `Option<TranquilityMonth>` for the
51
/// the month field.
52
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, FromPrimitive, ToPrimitive)]
53
pub enum TranquilityMonth {
54
    Archimedes = 1,
55
    Brahe,
56
    Copernicus,
57
    Darwin,
58
    Einstein,
59
    Faraday,
60
    Galileo,
61
    Hippocrates,
62
    Imhotep,
63
    Jung,
64
    Kepler,
65
    Lavoisier,
66
    Mendel,
67
}
68
69
const AFTER_H27: i64 = (TranquilityMonth::Hippocrates as i64) * 28;
70
71
/// Represents a complementary day of the Tranquility Calendar
72
///
73
/// These are a bit more complex than the complementary days of the Positivist
74
/// or Cotsworth calendars.
75
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, FromPrimitive, ToPrimitive)]
76
pub enum TranquilityComplementaryDay {
77
    /// This is the day of the Apollo 11 moon landing, which is the epoch for
78
    /// the Tranquility calendar. It is not part of any week, month or year.
79
    MoonLandingDay = 0,
80
    /// This is the last day of every year except 1 Before Tranquility. It
81
    /// is not part of any week or month.
82
    ArmstrongDay,
83
    /// This is an extra day added during leap years. It occurs between Hippocrates
84
    /// 27 and 28. It is not part of any week or month.
85
    AldrinDay,
86
}
87
88
/// Represents a date in the Tranquility Calendar
89
///
90
/// ## Introduction
91
///
92
/// The Tranquility calendar was proposed by Jeff Siggins in the July 1989 issue of
93
/// OMNI magazine. It is used by the Orion's Arm collaborative science fiction project.
94
/// Hardly anybody else uses the Tranquility calendar - it is so obscure that its Wikipedia
95
/// page was deleted for lack of notability.
96
///
97
/// Siggins' article starts with the following:
98
/// > Are you tired of that same old calendar, with 12 months of unequal length, and dates
99
/// > that always fall on different days? Do you forget lunch dates, closing days for real
100
/// > estate deals, or deadlines for IRA rollovers? When plotting graphs in your fruit fly
101
/// > experiment, do you ever get confused? Do you wonder why that same vile mood hits on the
102
/// > fifth of one month and the fifteenth of the next?
103
/// >
104
/// > If these problems are yours, you are probably ready for the next step in time accounting,
105
/// > the Tranquility calendar, designed for a perfection-seeking society, especially the men
106
/// > and women of science. Inspired by the Apollo 11 manned mission to the moon and developed
107
/// > for *Omni*, the Tranquility calendar will ease the complexity of scientific calculation,
108
/// > help astronomers fathom the movements of heavenly spheres, and facilitate high-stakes business.
109
/// > It will also aid everyday users who simply require a precise, easy-to-follow record of
110
/// > the events of their lives.
111
///
112
/// Unfortunately, despite these lofty goals, the Tranquility Calendar has many edge cases not
113
/// present in other timekeeping systems, and some aspects of the calendar are poorly documented;
114
/// this can cause difficulty when implementing software applications.
115
///
116
/// ### Year 0
117
///
118
/// Year 0 is **not** supported for this implementation of the Tranquility calendar, except as
119
/// a dummy value for the epoch. See the "Epoch" and "The Curious Case of 1 Before Tranquility"
120
/// sections for details.
121
///
122
/// ## Basic Structure
123
///
124
/// The epoch of the Tranquility calendar, known as Moon Landing Day, is an exception to
125
/// every other rule of the calendar. This also requires some special cases for the year
126
/// immediately before the epoch, 1 BT. See the "Epoch" section for details. The remainder
127
/// of this section is about days other than Moon Landing Day.
128
///
129
/// ### Months
130
///
131
/// From Siggins' article proposing the calendar:
132
/// > The Tranquility calendar uses a format of 13 months, each with 28 days (four seven-day
133
/// > weeks), for a total of 364 days. One extra day is added on at the end of the year to make
134
/// > 365. For leap years, a second extra day is added.
135
///
136
/// The months of the Tranquility calendar are named after notable scientists, and are also
137
/// in alphabetical order. Note that the "second extra day" for leap years is **not** at the
138
/// end of the year.
139
///
140
/// The first day of every Tranquility year is 1 Archimedes, as stated by Siggins:
141
/// >  The first day of each year is the first day of Archimedes (July 21 on the Gregorian calendar).
142
///
143
/// ### Armstrong Day and Aldrin Day
144
///
145
/// The two extra days are described as follows by Siggins:
146
/// > The last day of each Tranquility year is called Armstrong Day. Named for the first human
147
/// > to step on the moon, Armstrong Day celebrates the anniversary of Moon Landing Day. Thus
148
/// > July 20, 1970, is the Gregorian equivalent of Armstrong Day, 1 A.T., and July 20, 1989,
149
/// > is Armstrong Day, 20 A.T.
150
/// >
151
/// > Finally, the Tranquility calendar equivalent of leap day is called Aldrin Day. Named for
152
/// > Armstrong's fellow moon walker, Aldrin Day occurs every four years, with some exceptions.
153
/// > The exceptions are the leap days in every 400 years that are dropped to keep the calendar
154
/// > astronomically precise. Aldrin Day falls between the twenty-seventh and twenty-eighth of
155
/// > Hippocrates (February 29).
156
///
157
/// Siggins explains the Gregorian leap year rule earlier in the article, so we can assume that
158
/// "the leap days in every 400 years that are dropped" refer to the leap days dropped in
159
/// Gregorian years divisible by 100 and not by 400.
160
///
161
/// The odd placement of Aldrin Day is not explicitly justified in the text. However, implicit
162
/// in the passage above is the idea that *every* Armstrong Day corresponds to July 20 in the
163
/// proleptic Gregorian calendar, and *every* Aldrin Day corresponds to February 29. The year
164
/// lengths are also the same, meaning that there should be a one-to-one relationship between
165
/// Gregorian dates and Tranquility dates stable across all years (ignoring Moon Landing Day,
166
/// which replaces one specific Armstrong Day).
167
///
168
/// This would also imply that when calculating leap years, we need to apply the Gregorian
169
/// rule after applying an offset of 1969 or 1970, depending on the date relative to the epoch.
170
///
171
/// ## Epoch
172
///
173
/// The Tranquility calendar epoch is specific down to the tenth of a second. The day on which
174
/// the epoch occurs is called Moon Landing Day, and is described as follows by Siggins:
175
/// > The Tranquility calendar, on the other hand, is based on a recent, well-documented event,
176
/// > the landing by two American astronauts, Neil Armstrong and Edwin "Buzz" Aldrin, on the
177
/// > moon. Upon touchdown came those almost mystical words, "Houston ... Tranquility Base here.
178
/// > The Eagle has landed." Omni's Tranquility calendar starts at the very instant the word
179
/// > Tranquility was uttered. As one of the most astronomically analyzed moments in scientific
180
/// > history, our base point can be used to chart the exact position of the earth in
181
/// > relationship to the moon and other celestial bodies.
182
/// >
183
/// > Now for the details of the calendar itself. The day on which the moment of Tranquility
184
/// > occurred is called Moon Landing Day. It is the central day of the Tranquility calendar
185
/// > and it stands alone. Not part of any month or year, it has 20 hours, 18 minutes, and 1.2
186
/// > seconds Before Tranquility (B.T.), and 3 hours, 41 minutes, and 58.8 seconds After
187
/// > Tranquility (A.T). The Gregorian equivalent of Moon Landing Day is July 20, A.D. 1969.
188
///
189
/// We can assume that any date after Moon Landing Day is "After Tranquility" and any day before
190
/// Moon Landing Day is "Before Tranquility".
191
///
192
/// ### The Curious Case of 1 Before Tranquility
193
///
194
/// Siggins devoted very little of his article to dates Before Tranquility, and the year
195
/// immediately preceding Moon Landing Day is particularly confusing.
196
///
197
/// Consider the following statements in Siggins' article:
198
///
199
/// 1. "The Gregorian equivalent of Moon Landing Day is July 20, A.D. 1969"
200
/// 2. "The first day of each year is the first day of Archimedes (July 21 on the Gregorian calendar)."
201
/// 3. "The last day of each Tranquility year is called Armstrong Day."
202
/// 4. "Armstrong Day celebrates the anniversary of Moon Landing Day."
203
///
204
///    a. "July 20, 1970, is the Gregorian equivalent of Armstrong Day, 1 A.T."
205
///
206
///    b. "July 20, 1989, is Armstrong Day, 20 A.T."
207
///
208
/// First of all, it is not stated whether the year immediately preceding Moon Landing Day is
209
/// 1 BT or 0 BT - however the full version of Siggins' article in OMNI (with all the
210
/// images) contains many example dates which imply that 0 BT does not exist. For example,
211
/// the first airplane flight by Orville and Wilbur Wright at Kitty Hawk is listed as occurring
212
/// on Faraday 10, 66 BT and 1903 CE. [The exact date of the flight was December 17, 1903](https://airandspace.si.edu/collection-objects/1903-wright-flyer/nasm_A19610048000).
213
/// The 66th anniversary of the Wright brother's flight would be December 17, 1969 CE which
214
/// is after Moon Landing Day (as per statement 1 above) and before Armstrong Day, 1 AT (as
215
/// per statement 4a above) which is the last day of 1 AT (as per statement 3). However,
216
/// naively calculating 66 BT + 66 = 0 BT would suggest that the year should be 0 BT.
217
///
218
/// Based on the math above, we can assume some year BT was skipped, and the most obvious
219
/// choice is 0 BT. Skipping some other year such as 1 BT, 2 BT or 50 BT would be
220
/// unintuitive, whereas skipping year 0 is common practice when working with historical dates
221
/// using the Julian calendar.
222
///
223
/// Having established that the year immediately preceding Moon Landing Day is 1 BT, we must
224
/// figure out what the last day of 1 BT is named.
225
///
226
/// All 4 statements above cannot be true for 1 BT, as Armstrong Day, 1 BT would
227
/// either conflict with Moon Landing Day, not end the year, or not occur on the anniversary
228
/// of Moon Landing Day. Any implementation of the Tranquility calendar must implement some
229
/// special case to deal with this situation.
230
///
231
/// **This crate assumes that Armstrong Day is skipped in the year 1 BT** The day that
232
/// would normally be Armstrong Day, 1 BT is Moon Landing Day. The day before Moon Landing
233
/// Day is Mendel 28, 1 BT - which *would* be the day before Armstrong Day, 1 BT *if*
234
/// Armstrong Day existed in 1 BT.
235
///
236
/// This also seems to be the approach taken by the Orion's Arm Calendar Converter (note that
237
/// other pages in the Orion's Arm project may differ from the converter).
238
///
239
/// ## Representation and Examples
240
///
241
/// ### Months
242
///
243
/// The months are represented in this crate as [`TranquilityMonth`].
244
///
245
/// ```
246
/// use radnelac::calendar::*;
247
/// use radnelac::day_count::*;
248
///
249
/// let c_1_1 = CommonDate::new(57, 1, 1);
250
/// let tq_1_1 = Tranquility::try_from_common_date(c_1_1).unwrap();
251
/// assert_eq!(tq_1_1.try_month().unwrap(), TranquilityMonth::Archimedes);
252
/// let c_13_28 = CommonDate::new(57, 13, 28);
253
/// let tq_13_28 = Tranquility::try_from_common_date(c_13_28).unwrap();
254
/// assert_eq!(tq_13_28.try_month().unwrap(), TranquilityMonth::Mendel);
255
/// ```
256
///
257
/// ### Weekdays
258
///
259
/// The days of the Tranquility week are not always the same as the days of the common week.
260
///
261
/// ```
262
/// use radnelac::calendar::*;
263
/// use radnelac::day_count::*;
264
/// use radnelac::day_cycle::*;
265
///
266
/// let c = CommonDate::new(-1, 13, 28);
267
/// let p = Tranquility::try_from_common_date(c).unwrap();
268
/// assert_eq!(p.weekday().unwrap(), Weekday::Thursday); //Positivist week
269
/// assert_eq!(p.convert::<Weekday>(), Weekday::Saturday); //Common week
270
/// ```
271
///
272
/// ### Armstrong Day and Aldrin Day
273
///
274
/// The epagomenal days of a Tranquility year are represented as [`TranquilityComplementaryDay`].
275
/// When converting to and from a [`CommonDate`](crate::calendar::CommonDate), the epagomenal
276
/// days are treated as month 0.
277
///
278
/// ```
279
/// use radnelac::calendar::*;
280
/// use radnelac::day_count::*;
281
///
282
/// let c_arm = CommonDate::new(31, 0, 1);
283
/// let tq_arm = Tranquility::try_from_common_date(c_arm).unwrap();
284
/// assert!(tq_arm.try_month().is_none());
285
/// assert_eq!(tq_arm.epagomenae().unwrap(), TranquilityComplementaryDay::ArmstrongDay);
286
/// assert!(tq_arm.weekday().is_none());
287
///
288
/// let c_ald = CommonDate::new(31, 0, 2);
289
/// let tq_ald = Tranquility::try_from_common_date(c_ald).unwrap();
290
/// assert!(tq_ald.try_month().is_none());
291
/// assert_eq!(tq_ald.epagomenae().unwrap(), TranquilityComplementaryDay::AldrinDay);
292
/// assert!(tq_ald.weekday().is_none());
293
/// ```
294
///
295
/// Armstrong Day is at the end of a year (except the year 1 BT).
296
///
297
/// ```
298
/// use radnelac::calendar::*;
299
/// use radnelac::day_count::*;
300
///
301
/// let tq_end_31 = Tranquility::try_year_end(31).unwrap();
302
/// assert_eq!(tq_end_31.epagomenae().unwrap(), TranquilityComplementaryDay::ArmstrongDay);
303
/// let tq_end_1 = Tranquility::try_year_end(-1).unwrap();
304
/// assert!(tq_end_1.epagomenae().is_none());
305
/// ```
306
///
307
/// Aldrin Day is between 27 and 28 Hippocrates in a leap year. Note that leap years occur
308
/// at the same time as proleptic Gregorian leap years and Aldrin Day is always February 28
309
/// in the proleptic Gregorian calendar.
310
///
311
/// ```
312
/// use radnelac::calendar::*;
313
/// use radnelac::day_count::*;
314
///
315
/// let g_list = [
316
///     Gregorian::try_new(2024, GregorianMonth::February, 28).unwrap(),
317
///     Gregorian::try_new(2024, GregorianMonth::February, 29).unwrap(),
318
///     Gregorian::try_new(2024, GregorianMonth::March, 1).unwrap(),
319
/// ];
320
///
321
/// let tq_list = [
322
///     g_list[0].convert::<Tranquility>(),
323
///     g_list[1].convert::<Tranquility>(),
324
///     g_list[2].convert::<Tranquility>(),
325
/// ];
326
///
327
/// // Before Aldrin Day
328
/// assert_eq!(tq_list[0].year(), 55);
329
/// assert_eq!(tq_list[0].day(), 27);
330
/// assert_eq!(tq_list[0].try_month().unwrap(), TranquilityMonth::Hippocrates);
331
/// // Aldrin Day
332
/// assert_eq!(tq_list[1].year(), 55);
333
/// assert_eq!(tq_list[1].epagomenae().unwrap(), TranquilityComplementaryDay::AldrinDay);
334
/// assert!(tq_list[1].try_month().is_none());
335
/// // After Aldrin Day
336
/// assert_eq!(tq_list[2].year(), 55);
337
/// assert_eq!(tq_list[2].day(), 28);
338
/// assert_eq!(tq_list[2].try_month().unwrap(), TranquilityMonth::Hippocrates);
339
/// ```
340
///
341
/// ### Moon Landing Day
342
///
343
/// Moon Landing Day technically does not have any year, month or weekday. However it is
344
/// sometimes represented using the dummy year and month value `0`. The corresponding Gregorian
345
/// date is July 20, 1969.
346
///
347
/// ```
348
/// use radnelac::calendar::*;
349
/// use radnelac::day_count::*;
350
///
351
/// let g = Gregorian::try_new(1969, GregorianMonth::July, 20).unwrap();
352
/// let tq = g.convert::<Tranquility>();
353
/// assert_eq!(tq.year(), 0);
354
/// assert_eq!(tq.epagomenae().unwrap(), TranquilityComplementaryDay::MoonLandingDay);
355
/// assert!(tq.try_month().is_none());
356
/// assert!(tq.weekday().is_none());
357
/// assert_eq!(tq.to_common_date(), CommonDate::new(0, 0, 0));
358
/// ```
359
///
360
/// Moon Landing Day is between Mendel 28, 1 BT and Archimedes 1, 1 AT.
361
///
362
/// ```
363
/// use radnelac::calendar::*;
364
/// use radnelac::day_count::*;
365
///
366
/// let g_list = [
367
///     Gregorian::try_new(1969, GregorianMonth::July, 19).unwrap(),
368
///     Gregorian::try_new(1969, GregorianMonth::July, 20).unwrap(),
369
///     Gregorian::try_new(1969, GregorianMonth::July, 21).unwrap(),
370
/// ];
371
///
372
/// let tq_list = [
373
///     g_list[0].convert::<Tranquility>(),
374
///     g_list[1].convert::<Tranquility>(),
375
///     g_list[2].convert::<Tranquility>(),
376
/// ];
377
///
378
/// // Before Moon Landing Day
379
/// assert_eq!(tq_list[0].year(), -1);
380
/// assert_eq!(tq_list[0].day(), 28);
381
/// assert_eq!(tq_list[0].try_month().unwrap(), TranquilityMonth::Mendel);
382
/// // Moon Landing Day
383
/// assert_eq!(tq_list[1].epagomenae().unwrap(), TranquilityComplementaryDay::MoonLandingDay);
384
/// // After Moon Landing Day
385
/// assert_eq!(tq_list[2].year(), 1);
386
/// assert_eq!(tq_list[2].day(), 1);
387
/// assert_eq!(tq_list[2].try_month().unwrap(), TranquilityMonth::Archimedes);
388
/// ```
389
///
390
/// The epoch of the Tranquility calendar is specific to the tenth of a second. To check if
391
/// a specific point in time is before or after the epoch, callers should use [`TranquilityMoment`].
392
///
393
/// ## Inconsistencies with Other Implementations
394
///
395
/// The assumptions regarding 0 BT and 1 BT could differ from other implementations.
396
///
397
/// ## Further reading
398
/// + Orion's Arm
399
///   + ["Encyclopaedia Galactica"](https://www.orionsarm.com/eg-article/48c6d4c3d54cf/)
400
///   + [Calendar Converter](https://www.orionsarm.com/xcms.php?r=oa-calendar-converter)
401
/// + [Wikipedia Deletion Log](https://en.wikipedia.org/wiki/Wikipedia:Articles_for_deletion/Tranquility_Calendar)
402
/// + [Archived Wikipedia article](https://web.archive.org/web/20180818233025/https://en.wikipedia.org/wiki/Tranquility_calendar)
403
/// + Archived copies of Jeff Siggins' article for OMNI
404
///   + [archive.org copy of mithrandir.com](https://web.archive.org/web/20161025042320/http://www.mithrandir.com/Tranquility/tranquilityArticle.html)
405
///   + [archive.org copy of OMNI July 1989, pages 63, 64](https://archive.org/details/omni-archive/OMNI_1989_07/page/n63/mode/2up)
406
///   + [archive.org copy of OMNI July 1989, pages 65, 66](https://archive.org/details/omni-archive/OMNI_1989_07/page/n65/mode/2up)
407
#[derive(Debug, PartialEq, Clone, Copy)]
408
pub struct Tranquility(CommonDate);
409
410
impl Tranquility {
411
7.32k
    pub fn prior_elapsed_days(year: i32) -> i64 {
412
7.32k
        if year == 0 {
413
2
            TranquilityMoment::epoch().get_day_i() - 1
414
        } else {
415
7.32k
            let y = if year < 0 { 
year + 13.95k
} else {
year3.36k
};
416
7.32k
            let prior_g = Gregorian::try_from_common_date(CommonDate {
417
7.32k
                year: (y - 1) + TRANQUILITY_EPOCH_GREGORIAN.year,
418
7.32k
                month: TRANQUILITY_EPOCH_GREGORIAN.month,
419
7.32k
                day: TRANQUILITY_EPOCH_GREGORIAN.day,
420
7.32k
            })
421
7.32k
            .expect("Month and day known to be valid.");
422
7.32k
            prior_g.to_fixed().get_day_i()
423
        }
424
7.32k
    }
425
}
426
427
impl ToFromOrdinalDate for Tranquility {
428
1.28k
    fn valid_ordinal(ord: OrdinalDate) -> Result<(), CalendarError> {
429
1.28k
        let correction = if TranquilityMoment::is_leap(ord.year) {
430
326
            1
431
        } else {
432
954
            0
433
        };
434
1.28k
        if ord.day_of_year > 0 && 
ord.day_of_year <= (365 + correction)1.02k
{
435
577
            Ok(())
436
        } else {
437
703
            Err(CalendarError::InvalidDayOfYear)
438
        }
439
1.28k
    }
440
441
8.97k
    fn ordinal_from_fixed(fixed_date: Fixed) -> OrdinalDate {
442
        //Common
443
        //Gregorian:   (jan1).....(feb28)(mar1).....(jul20)(jul21).....(dec31)
444
        //Greg  ord:   (1)...........(59)(60).........(201)(202).........(365)
445
        //Tranquility: (far25)....(hip27)(hip28)......(arm)(arc1)......(far24)
446
        //Tran  ord:   (165)........(223)(224)........(365)(1)...........(164)
447
        //Leap
448
        //Gregorian:   (jan1).....(feb29)(mar1).....(jul20)(jul21).....(dec31)
449
        //Greg  ord:   (1)...........(60)(61).........(202)(203).........(366)
450
        //Tranquility: (far25)......(ald)(hip28)......(arm)(arc1)......(far24)
451
        //Tran  ord:   (165)........(224)(225)........(366)(1)...........(164)
452
        const ORDINAL_SHIFT: i64 = ((TranquilityMonth::Faraday as i64) * 28) - 4;
453
8.97k
        let g_ord = Gregorian::ordinal_from_fixed(fixed_date);
454
8.97k
        let g_doy_shift = (g_ord.day_of_year as i64) + ORDINAL_SHIFT;
455
8.97k
        let g_len = if Gregorian::is_leap(g_ord.year) {
456
2.43k
            366
457
        } else {
458
6.54k
            365
459
        };
460
8.97k
        let tq_doy = g_doy_shift.adjusted_remainder(g_len);
461
8.97k
        let y_approx_0 = g_ord.year - TRANQUILITY_EPOCH_GREGORIAN.year;
462
8.97k
        let correct_0 = if tq_doy <= ORDINAL_SHIFT { 
14.06k
} else {
04.91k
};
463
8.97k
        let y_approx_1 = y_approx_0 + correct_0;
464
8.97k
        let year = if y_approx_1 < 1 {
465
4.45k
            y_approx_1 - 1
466
        } else {
467
4.52k
            y_approx_1
468
        };
469
8.97k
        if year == -1 && 
tq_doy == 365119
{
470
3
            OrdinalDate {
471
3
                year: 0,
472
3
                day_of_year: 1,
473
3
            }
474
        } else {
475
8.97k
            OrdinalDate {
476
8.97k
                year: year,
477
8.97k
                day_of_year: tq_doy as u16,
478
8.97k
            }
479
        }
480
8.97k
    }
481
482
13.2k
    fn to_ordinal(self) -> OrdinalDate {
483
13.2k
        let comp_count = Self::epagomenae_count(self.0.year) as i64;
484
13.2k
        let ordinal_day = match self.epagomenae() {
485
2
            Some(TranquilityComplementaryDay::MoonLandingDay) => 1,
486
540
            Some(TranquilityComplementaryDay::ArmstrongDay) => 364 + comp_count,
487
79
            Some(TranquilityComplementaryDay::AldrinDay) => AFTER_H27,
488
            None => {
489
12.5k
                let month = self.0.month as i64;
490
12.5k
                let day = self.0.day as i64;
491
12.5k
                let approx = ((month - 1) * 28) + day;
492
12.5k
                let correction = if approx < AFTER_H27 || 
comp_count < 25.05k
{
493
11.3k
                    0
494
                } else {
495
1.21k
                    1
496
                };
497
12.5k
                approx + correction
498
            }
499
        };
500
13.2k
        OrdinalDate {
501
13.2k
            year: self.0.year,
502
13.2k
            day_of_year: ordinal_day as u16,
503
13.2k
        }
504
13.2k
    }
505
506
8.72k
    fn from_ordinal_unchecked(ord: OrdinalDate) -> Self {
507
8.72k
        let date_tq = match (
508
8.72k
            ord.day_of_year as i64,
509
8.72k
            ord.year,
510
8.72k
            TranquilityMoment::is_leap(ord.year),
511
8.72k
        ) {
512
3
            (_, 0, _) => CommonDate::new(0, NON_MONTH, 0),
513
21
            (365, _, false) => CommonDate::new(ord.year, NON_MONTH, 1),
514
5
            (366, _, true) => CommonDate::new(ord.year, NON_MONTH, 1),
515
3
            (AFTER_H27, _, true) => CommonDate::new(ord.year, NON_MONTH, 2),
516
8.69k
            (doy, y, is_leap) => {
517
8.69k
                let correction = if doy < AFTER_H27 || 
!is_leap3.03k
{
07.96k
} else {
1723
};
518
8.69k
                let month = ((((doy - correction) - 1) as i64).div_euclid(28) + 1) as u8;
519
8.69k
                let day = ((doy - correction) as i64).adjusted_remainder(28) as u8;
520
8.69k
                debug_assert!(month > 0 && month < 14, 
"doy: {}, y: {}"0
, doy, y);
521
8.69k
                CommonDate::new(y, month, day)
522
            }
523
        };
524
8.72k
        Tranquility(date_tq)
525
8.72k
    }
526
}
527
528
impl PartialOrd for Tranquility {
529
2.05k
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
530
2.05k
        if self == other {
531
8
            Some(Ordering::Equal)
532
        } else {
533
2.04k
            let self_ord = self.to_ordinal();
534
2.04k
            let other_ord = other.to_ordinal();
535
2.04k
            self_ord.partial_cmp(&other_ord)
536
        }
537
2.05k
    }
538
}
539
540
impl HasEpagemonae<TranquilityComplementaryDay> for Tranquility {
541
21.4k
    fn epagomenae(self) -> Option<TranquilityComplementaryDay> {
542
21.4k
        if self.0.month == NON_MONTH {
543
648
            TranquilityComplementaryDay::from_u8(self.0.day)
544
        } else {
545
20.7k
            None
546
        }
547
21.4k
    }
548
549
13.2k
    fn epagomenae_count(p_year: i32) -> u8 {
550
13.2k
        if Self::is_leap(p_year) {
551
3.28k
            2
552
9.92k
        } else if p_year == -1 {
553
            //Armstrong Day replaced by Moon Landing Day
554
4
            0
555
        } else {
556
9.91k
            1
557
        }
558
13.2k
    }
559
}
560
561
impl Perennial<TranquilityMonth, Weekday> for Tranquility {
562
4.86k
    fn weekday(self) -> Option<Weekday> {
563
4.86k
        if self.epagomenae().is_some() {
564
17
            None
565
        } else {
566
4.84k
            Weekday::from_i64(((self.0.day as i64) + 4).modulus(7))
567
        }
568
4.86k
    }
569
570
4.59k
    fn days_per_week() -> u8 {
571
4.59k
        7
572
4.59k
    }
573
574
4.59k
    fn weeks_per_month() -> u8 {
575
4.59k
        4
576
4.59k
    }
577
}
578
579
impl HasLeapYears for Tranquility {
580
24.3k
    fn is_leap(t_year: i32) -> bool {
581
24.3k
        if t_year > 0 {
582
11.7k
            Gregorian::is_leap(t_year + TRANQUILITY_EPOCH_GREGORIAN.year)
583
12.5k
        } else if t_year < 0 {
584
12.5k
            Gregorian::is_leap(t_year + TRANQUILITY_EPOCH_GREGORIAN.year + 1)
585
        } else {
586
5
            false
587
        }
588
24.3k
    }
589
}
590
591
impl CalculatedBounds for Tranquility {}
592
593
impl Epoch for Tranquility {
594
771
    fn epoch() -> Fixed {
595
771
        let date = Gregorian::try_from_common_date(TRANQUILITY_EPOCH_GREGORIAN)
596
771
            .expect("Epoch known to be valid")
597
771
            .to_fixed();
598
771
        let time = TimeOfDay::try_from_clock(TRANQUILITY_EPOCH_CLOCK).expect("Known valid");
599
771
        Fixed::new(date.get() + time.get())
600
771
    }
601
}
602
603
impl FromFixed for Tranquility {
604
8.46k
    fn from_fixed(date: Fixed) -> Tranquility {
605
8.46k
        let ord = Tranquility::ordinal_from_fixed(date);
606
8.46k
        Tranquility::from_ordinal_unchecked(ord)
607
8.46k
    }
608
}
609
610
impl ToFixed for Tranquility {
611
7.32k
    fn to_fixed(self) -> Fixed {
612
7.32k
        let ord = self.to_ordinal();
613
7.32k
        let offset_prior = Tranquility::prior_elapsed_days(ord.year);
614
7.32k
        Fixed::new((offset_prior as f64) + (ord.day_of_year as f64))
615
7.32k
    }
616
}
617
618
impl ToFromCommonDate<TranquilityMonth> for Tranquility {
619
13.7k
    fn to_common_date(self) -> CommonDate {
620
13.7k
        self.0
621
13.7k
    }
622
623
11.2k
    fn from_common_date_unchecked(date: CommonDate) -> Self {
624
11.2k
        debug_assert!(Self::valid_ymd(date).is_ok());
625
11.2k
        Self(date)
626
11.2k
    }
627
628
23.8k
    fn valid_ymd(date: CommonDate) -> Result<(), CalendarError> {
629
23.8k
        if date.month > 13 {
630
512
            Err(CalendarError::InvalidMonth)
631
23.3k
        } else if date.month == NON_MONTH {
632
2.43k
            if date.day == 0 && 
date.year == 02
{
633
2
                Ok(())
634
2.43k
            } else if date.day == 1 && 
date.year != 02.06k
&&
date.year != -12.06k
{
635
2.06k
                Ok(())
636
366
            } else if date.day == 2 && date.year != 0 && Self::is_leap(date.year) {
637
366
                Ok(())
638
            } else {
639
0
                Err(CalendarError::InvalidDay)
640
            }
641
20.8k
        } else if date.day < 1 || 
date.day > 2820.6k
{
642
512
            Err(CalendarError::InvalidDay)
643
20.3k
        } else if date.year == 0 {
644
            //Only for Moon Landing Day, as above
645
0
            Err(CalendarError::InvalidYear)
646
        } else {
647
20.3k
            Ok(())
648
        }
649
23.8k
    }
650
651
257
    fn year_start_date(year: i32) -> CommonDate {
652
257
        if year == 0 {
653
1
            CommonDate::new(
654
1
                year,
655
                NON_MONTH,
656
1
                TranquilityComplementaryDay::MoonLandingDay as u8,
657
            )
658
        } else {
659
256
            CommonDate::new(year, 1, 1)
660
        }
661
257
    }
662
663
258
    fn year_end_date(year: i32) -> CommonDate {
664
258
        if year == 0 {
665
1
            CommonDate::new(
666
1
                year,
667
                NON_MONTH,
668
1
                TranquilityComplementaryDay::MoonLandingDay as u8,
669
            )
670
257
        } else if year == -1 {
671
1
            CommonDate::new(year, TranquilityMonth::Mendel as u8, 28)
672
        } else {
673
256
            CommonDate::new(
674
256
                year,
675
                NON_MONTH,
676
256
                TranquilityComplementaryDay::ArmstrongDay as u8,
677
            )
678
        }
679
258
    }
680
681
0
    fn month_length(_year: i32, _month: TranquilityMonth) -> u8 {
682
0
        28
683
0
    }
684
}
685
686
impl Quarter for Tranquility {
687
2.56k
    fn quarter(self) -> NonZero<u8> {
688
2.56k
        match (self.try_week_of_year(), self.epagomenae()) {
689
0
            (None, Some(TranquilityComplementaryDay::MoonLandingDay)) => NonZero::new(4).unwrap(),
690
1
            (None, Some(TranquilityComplementaryDay::ArmstrongDay)) => NonZero::new(4).unwrap(),
691
0
            (None, Some(TranquilityComplementaryDay::AldrinDay)) => NonZero::new(3).unwrap(),
692
2.55k
            (Some(w), None) => NonZero::new((w - 1) / 13 + 1).expect("w > 0"),
693
0
            (_, _) => unreachable!(),
694
        }
695
2.56k
    }
696
}
697
698
/// Represents a date *and time* in the Tranquility Calendar
699
pub type TranquilityMoment = CalendarMoment<Tranquility>;
700
701
impl TranquilityMoment {
702
0
    pub fn is_after_tranquility(self) -> bool {
703
0
        if self.date().0.year == 0 {
704
0
            self.time_of_day() > TRANQUILITY_EPOCH_CLOCK
705
        } else {
706
0
            self.date().0.year > 0
707
        }
708
0
    }
709
}
710
711
#[cfg(test)]
712
mod tests {
713
    use super::*;
714
    //use crate::calendar::Julian;
715
    use crate::day_count::RataDie;
716
717
    use crate::day_count::FIXED_MAX;
718
    use crate::day_count::FIXED_MIN;
719
720
    use proptest::proptest;
721
722
    #[test]
723
1
    fn moon_landing_edge_cases() {
724
1
        let f0 = TranquilityMoment::epoch();
725
1
        let q0 = TranquilityMoment::from_fixed(f0);
726
1
        let c = CommonDate::new(0, 0, 0);
727
1
        assert_eq!(q0.to_common_date(), c);
728
1
        let f1 = q0.to_fixed();
729
1
        assert_eq!(f0, f1);
730
1
        assert_eq!(c, TranquilityMoment::year_end_date(0));
731
1
        assert_eq!(c, TranquilityMoment::year_start_date(0));
732
1
    }
733
734
    #[test]
735
1
    fn one_bt_edge_cases() {
736
1
        let c = CommonDate::new(-1, 13, 28);
737
1
        assert_eq!(c, TranquilityMoment::year_end_date(-1));
738
1
    }
739
740
    #[test]
741
1
    fn obvious_conversions_from_gregorian() {
742
1
        let d_list = [
743
1
            // Moon Landing Day
744
1
            (CommonDate::new(1969, 7, 20), CommonDate::new(0, 0, 0)),
745
1
            // Near Moon Landing Day
746
1
            (CommonDate::new(1969, 6, 30), CommonDate::new(-1, 13, 9)),
747
1
            (CommonDate::new(1969, 7, 1), CommonDate::new(-1, 13, 10)),
748
1
            (CommonDate::new(1969, 7, 9), CommonDate::new(-1, 13, 18)),
749
1
            (CommonDate::new(1969, 7, 19), CommonDate::new(-1, 13, 28)),
750
1
            (CommonDate::new(1969, 7, 21), CommonDate::new(1, 1, 1)),
751
1
            (CommonDate::new(1969, 7, 31), CommonDate::new(1, 1, 11)),
752
1
            (CommonDate::new(1969, 8, 1), CommonDate::new(1, 1, 12)),
753
1
            // Armstrong Day
754
1
            (CommonDate::new(1965, 7, 20), CommonDate::new(-5, 0, 1)),
755
1
            (CommonDate::new(1968, 7, 20), CommonDate::new(-2, 0, 1)),
756
1
            (CommonDate::new(1970, 7, 20), CommonDate::new(1, 0, 1)),
757
1
            (CommonDate::new(1989, 7, 20), CommonDate::new(20, 0, 1)), //in Siggins' article
758
1
            (CommonDate::new(1995, 7, 20), CommonDate::new(26, 0, 1)),
759
1
            (CommonDate::new(1995, 7, 21), CommonDate::new(27, 1, 1)),
760
1
            (CommonDate::new(2000, 7, 20), CommonDate::new(31, 0, 1)),
761
1
            (CommonDate::new(2020, 7, 20), CommonDate::new(51, 0, 1)),
762
1
            (CommonDate::new(2025, 7, 20), CommonDate::new(56, 0, 1)),
763
1
            // Aldrin Day
764
1
            (CommonDate::new(1968, 2, 29), CommonDate::new(-2, 0, 2)),
765
1
            (CommonDate::new(1972, 2, 29), CommonDate::new(3, 0, 2)),
766
1
            (CommonDate::new(2000, 2, 29), CommonDate::new(31, 0, 2)),
767
1
        ];
768
21
        for 
pair20
in d_list {
769
20
            let dg = Gregorian::try_from_common_date(pair.0).unwrap().to_fixed();
770
20
            let dq = TranquilityMoment::try_from_common_date(pair.1)
771
20
                .unwrap()
772
20
                .to_fixed();
773
20
            assert_eq!(dq.get_day_i(), dg.get_day_i());
774
        }
775
1
    }
776
777
    #[test]
778
1
    fn article_examples() {
779
1
        let d_list = [
780
1
            // From Siggins' article
781
1
            // 21, 1, 3
782
1
            // Beginning of the Perseid meteor showers (1989)
783
1
            // ???
784
1
            // Louise Brown, first test-tube baby, is born (1978)
785
1
            // 1978-07-25 https://en.wikipedia.org/wiki/Louise_Brown
786
1
            (CommonDate::new(1978, 7, 25), CommonDate::new(10, 1, 5)),
787
1
            // NASA established and funded by Congress (1958)
788
1
            // 1958-07-29 https://en.wikipedia.org/wiki/NASA
789
1
            (CommonDate::new(1958, 7, 29), CommonDate::new(-11, 1, 9)),
790
1
            // Explorer VI transmits first picture of Earth from space (1959)
791
1
            // 1959-08-14 https://en.wikipedia.org/wiki/Explorer_6
792
1
            // (CommonDate::new(1959, 8, 14), CommonDate::new(-10, 1, 18)), //Incorrect???
793
1
            // USSR explodes its first hydrogen bomb (1953)
794
1
            // 1953-08-12 https://en.wikipedia.org/wiki/RDS-6s
795
1
            (CommonDate::new(1953, 8, 12), CommonDate::new(-16, 1, 23)),
796
1
            // Lunar eclipse (1989)
797
1
            // 1989-08-17 https://en.wikipedia.org/wiki/August_1989_lunar_eclipse
798
1
            (CommonDate::new(1989, 8, 17), CommonDate::new(21, 1, 28)),
799
1
            // Launch of Voyager 2, space-craft for planetary exploration (1977)
800
1
            // 1977-08-20 https://en.wikipedia.org/wiki/Voyager_2
801
1
            (CommonDate::new(1977, 8, 20), CommonDate::new(9, 2, 3)),
802
1
            // Pliny the Elder dies in eruption of Vesuvius at Pompeii (79)
803
1
            // 79-08-24 https://en.wikipedia.org/wiki/Eruption_of_Mount_Vesuvius_in_79_AD
804
1
            // Actual date seems controversial, additionally shouldn't this be Julian?
805
1
            (CommonDate::new(79, 8, 24), CommonDate::new(-1890, 2, 7)),
806
1
            // Partial solar eclipse (1989)
807
1
            // 1989-08-31 wiki:https://en.wikipedia.org/wiki/Solar_eclipse_of_August_31,_1989
808
1
            (CommonDate::new(1989, 8, 31), CommonDate::new(21, 2, 14)),
809
1
            // Viking 2 lands near polar cap of Mars, sends photos of Earth (1976)
810
1
            // 1976-09-03 wiki:https://en.wikipedia.org/wiki/Viking_2
811
1
            (CommonDate::new(1976, 9, 3), CommonDate::new(8, 2, 17)),
812
1
            // Charles Darwin, in a letter to American botanist Asa Gray, propounds the law of evolution of species by means of natural selection (1857)
813
1
            // 1857-09-05 wiki:https://en.wikipedia.org/wiki/Charles_Darwin
814
1
            (CommonDate::new(1857, 9, 5), CommonDate::new(-112, 2, 19)),
815
1
            // First privately owned rocket launched by Space Services, Inc., of the USA (1982)
816
1
            // 1982-09-09 wiki:https://en.wikipedia.org/wiki/Conestoga_(rocket)
817
1
            (CommonDate::new(1982, 9, 9), CommonDate::new(14, 2, 23)),
818
1
            // 16, 2, 28
819
1
            // First solo balloon flight across the Atlantic Ocean embarks from Maine, arrives 86 hours later (1984)
820
1
            // ???
821
1
            // Autumnal equinox. The serpent of light appears on the pyramid at Chichen Itza Mexico (1989)
822
1
            // 1989-09-23 https://www.timeanddate.com/calendar/seasons.html?year=1950&n=1440
823
1
            (CommonDate::new(1989, 9, 23), CommonDate::new(21, 3, 9)),
824
1
            // "Blue sun," a 200-mile-wide blanket of smoke, caused by forest fires in Alberta and British Columbia, Canada (1950)
825
1
            // 1950-09-24 https://en.wikipedia.org/wiki/Chinchaga_fire (black sunday)
826
1
            // (CommonDate::new(1950, 9, 24), CommonDate::new(-19, 3, 12)), //Incorrect?
827
1
            // Shuttle Discovery launched, first manned US craft since the Challenger (1988)
828
1
            // 1988-09-29 https://en.wikipedia.org/wiki/STS-26
829
1
            (CommonDate::new(1988, 9, 29), CommonDate::new(20, 3, 15)),
830
1
            // 21, 3, 16
831
1
            // First day of year 5750 on the Judaic calendar (1989)
832
1
            // ???
833
1
            // Sputnik 1, first successful man-made satellite, is launched by the USSR (1957)
834
1
            // 1957-10-04 https://en.wikipedia.org/wiki/Sputnik_1
835
1
            (CommonDate::new(1957, 10, 4), CommonDate::new(-12, 3, 20)),
836
1
            // -302, 3, 25
837
1
            // Antonie van Leeuwenhoek announces discovery of microorganisms (1667)
838
1
            // ???
839
1
            // Christopher Columbus lands in the Bahamas (1492)
840
1
            // 1492-10-12 https://en.wikipedia.org/wiki/Voyages_of_Christopher_Columbus
841
1
            (CommonDate::new(1492, 10, 12), CommonDate::new(-477, 3, 28)), //Apparently not Julian
842
1
            // USAF Chaptain Charles Yeager becomes first human to fly faster than the speed of sound
843
1
            // 1947-10-14 https://en.wikipedia.org/wiki/Bell_X-1
844
1
            (CommonDate::new(1947, 10, 14), CommonDate::new(-22, 4, 2)),
845
1
            // -123, 4, 4
846
1
            // First public operation using ether as an anesthetic is performed at Massachusetts General Hospital
847
1
            // ???
848
1
            // Thomas Edison invents incandescent electric lamp (1879)
849
1
            // 1879-10-22 https://en.wikipedia.org/wiki/Incandescent_light_bulb
850
1
            // (CommonDate::new(1879, 10, 22), CommonDate::new(-90, 4, 9)), //Incorrect?
851
1
            // The first recorded parachute descent, from a balloon (1797) (1st Brumaire, Year VI of the Republican calendar)
852
1
            // 1797-10-22 https://en.wikipedia.org/wiki/Andr%C3%A9-Jacques_Garnerin
853
1
            (CommonDate::new(1797, 10, 22), CommonDate::new(-172, 4, 10)),
854
1
            // -10, 4, 15
855
1
            // The Soviet Union releases the first pictures of the far side of the moon, taken by Lunik 3 (1959)
856
1
            // ??? 1959-10-07 wiki:https://en.wikipedia.org/wiki/Luna_3
857
1
            // Laika, a Russian dog, becomes the first "higher" animal in space (1957)
858
1
            // 1957-11-03 https://en.wikipedia.org/wiki/Sputnik_2
859
1
            (CommonDate::new(1957, 11, 3), CommonDate::new(-12, 4, 22)),
860
1
            // Archaeologist Howard Carter discovers tomb of King Tut at Luxor, Egypt (1922)
861
1
            // 1992-11-04 https://en.wikipedia.org/wiki/Discovery_of_the_tomb_of_Tutankhamun
862
1
            (CommonDate::new(1922, 11, 4), CommonDate::new(-47, 4, 23)),
863
1
            // 25, 4, 28
864
1
            // The next transit of the planet Mercury across the face of the sun (1993)
865
1
            // ??? 1993-11-06 https://en.m.wikipedia.org/wiki/Transit_of_Mercury
866
1
            // The first coast-to-coast direct-dial telephone service begins, Englewood, New Jersey (1951)
867
1
            // 1951-11-10 https://en.wikipedia.org/wiki/Englewood,_New_Jersey
868
1
            (CommonDate::new(1951, 11, 10), CommonDate::new(-18, 5, 1)),
869
1
            // Voyager 1 nears Saturn; photos reveal three new moons (1980)
870
1
            // 1980-11-12 https://en.wikipedia.org/wiki/Voyager_1
871
1
            (CommonDate::new(1980, 11, 12), CommonDate::new(12, 5, 3)),
872
1
            // -3, 5, 8
873
1
            // The densest meteor shower ever recorded (1966)
874
1
            // ???
875
1
            // -63, 5, 13
876
1
            // SOS adopted as the international distress call (1906)
877
1
            // ??? 1906-11-03 wiki:https://en.wikipedia.org/wiki/SOS
878
1
            // Charles Darwin's The Origin of Species is published (1859)
879
1
            // 1859-11-24 https://en.wikipedia.org/wiki/On_the_Origin_of_Species
880
1
            (CommonDate::new(1859, 11, 24), CommonDate::new(-110, 5, 15)),
881
1
            // -23, 5, 28
882
1
            // Percy Spencer patents the microwave oven (1946)
883
1
            // ??? 1945-10-08 wiki:https://en.wikipedia.org/wiki/Percy_Spencer
884
1
            // Anethesia used for first time to perform a dental extraction (1844)
885
1
            //1844-12-10 https://en.wikipedia.org/wiki/History_of_general_anesthesia
886
1
            // (CommonDate::new(1844, 12, 10), CommonDate::new(-125, 6, 4)), // Incorrect??
887
1
            // -22, 6, 5
888
1
            // John Bardeen, Walter Brattain, and William Shockley invent the transistor (1947)
889
1
            // ??? 1947-(11-17 to 12-23) wiki:https://en.wikipedia.org/wiki/Transistor
890
1
            // The first airplane flight by Orville and Wilbur Wright, Kitty Hawk, North Carolina (1903)
891
1
            //1903-12-17 https://en.wikipedia.org/wiki/Wright_Flyer
892
1
            (CommonDate::new(1903, 12, 17), CommonDate::new(-66, 6, 10)),
893
1
            // Winter solstice (1989)
894
1
            //1989-12-21 https://aa.usno.navy.mil/calculated/seasons?year=1989&tz=0.00&tz_sign=-1&tz_label=false&dst=false&submit=Get+Data
895
1
            (CommonDate::new(1989, 12, 21), CommonDate::new(21, 6, 14)),
896
1
            // 6, 6, 17
897
1
            // The discovery of Lucy, fossil remains of an early female hominid, in Ethiopia (1974)
898
1
            // ???
899
1
            // New Year's Day on both the Gregorian Calendar (1990) and Japanese calendar (2651)
900
1
            // 1990-01-01 by definition
901
1
            (CommonDate::new(1990, 1, 1), CommonDate::new(21, 6, 25)),
902
1
            // 21, 6, 28
903
1
            // The earth is at its farthest distance from the sun (aphelion) (1990)
904
1
            // ??? 1990-01-04 is the perihelion wiki:https://aa.usno.navy.mil/calculated/seasons?year=1990&tz=0.00&tz_sign=-1&tz_label=false&dst=false&submit=Get+Data
905
1
            // Galileo discovers the moons of Jupiter (1610)
906
1
            // 1610-01-07 https://en.wikipedia.org/wiki/Galileo_Galilei
907
1
            (CommonDate::new(1610, 1, 7), CommonDate::new(-360, 7, 3)),
908
1
            // 16, 7, 9
909
1
            // Ornithologists count 1350 great white cranes at Poyand Lake in China, the most ever recorded (1985)
910
1
            // ???
911
1
            // Earthquake changes course of the Mississippi River (1812)
912
1
            // 1812-01-23 https://en.wikipedia.org/wiki/1811%E2%80%931812_New_Madrid_earthquakes
913
1
            (CommonDate::new(1812, 1, 23), CommonDate::new(-158, 7, 19)),
914
1
            // Annular eclipse of the sun (1990)
915
1
            // 1990-01-26 wiki:https://en.wikipedia.org/wiki/List_of_solar_eclipses_in_the_20th_century
916
1
            (CommonDate::new(1990, 1, 26), CommonDate::new(21, 7, 22)),
917
1
            // Apollo 1 fire kills US astronauts Gus Grissom, Ed White, and Roger Chaffee (1967)
918
1
            //1967-01-27 https://en.wikipedia.org/wiki/Apollo_1
919
1
            (CommonDate::new(1967, 1, 27), CommonDate::new(-3, 7, 23)),
920
1
            // The space shuttle Challenger explodes, killing seven American astronauts (1986)
921
1
            //1986-01-28 https://en.wikipedia.org/wiki/Space_Shuttle_Challenger_disaster
922
1
            (CommonDate::new(1986, 1, 28), CommonDate::new(17, 7, 24)),
923
1
            // Explorer 1, the first US satellite, is launched (1958)
924
1
            //1958-02-01 https://en.wikipedia.org/wiki/Explorer_1
925
1
            // (CommonDate::new(1958, 2, 1), CommonDate::new(-12, 7, 27)), //Incorrect??
926
1
            // Soviet Luna 9 makes first successful soft landing on the moon (1966)
927
1
            //1966-02-03 https://en.wikipedia.org/wiki/Luna_9
928
1
            (CommonDate::new(1966, 2, 3), CommonDate::new(-4, 8, 2)),
929
1
            // Two US astronauts become first humans to fly untethered in space (1984)
930
1
            //1984-02-07 https://en.wikipedia.org/wiki/STS-41-B
931
1
            // Launch date instead of untethered spacewalk date!
932
1
            (CommonDate::new(1984, 2, 3), CommonDate::new(15, 8, 2)),
933
1
            // Total lunar eclipse (1990)
934
1
            //1990-02-09 https://en.wikipedia.org/wiki/List_of_lunar_eclipses_in_the_20th_century
935
1
            // (CommonDate::new(1990, 2, 9), CommonDate::new(21, 8, 7)), //Incorrect??
936
1
            // Pope Gregory corrects the Julian calendar (1582) (See Julian test)
937
1
            // Italian philosopher Giordano Bruno burned at the stake for his heliocentric views (1600)
938
1
            //1600-02-17 https://en.wikipedia.org/wiki/Giordano_Bruno
939
1
            (CommonDate::new(1600, 2, 17), CommonDate::new(-370, 8, 16)),
940
1
            // The planet Pluto is discovered by Clyde Tombaught (1930)
941
1
            //1930-02-18 https://en.m.wikipedia.org/wiki/Pluto
942
1
            (CommonDate::new(1930, 2, 18), CommonDate::new(-40, 8, 17)),
943
1
            // John Glenn aboard the Friendship 7, becomes the first American to orbit Earth (1962)
944
1
            //1962-02-20 https://en.wikipedia.org/wiki/Mercury-Atlas_6
945
1
            (CommonDate::new(1962, 2, 20), CommonDate::new(-8, 8, 19)),
946
1
            // Sir James Chadwick of Great Britain announces the discovery of the neutron (1932)
947
1
            //1932-02-27 https://web.mit.edu/22.54/resources/Chadwick.pdf
948
1
            (CommonDate::new(1932, 2, 27), CommonDate::new(-38, 8, 26)),
949
1
            // The launch of Pioneer 10, first known Earth object to leave solar system (1972)
950
1
            //1972-03-03 https://en.wikipedia.org/wiki/Pioneer_10
951
1
            // (CommonDate::new(1972, 3, 3), CommonDate::new(3, 9, 1)), //Incorrect?
952
1
            // Sir William Herschel discovers Uranus (1781)
953
1
            // 1781-03-13 wiki:https://en.wikipedia.org/wiki/Uranus
954
1
            // (CommonDate::new(1781, 3, 13), CommonDate::new(-189, 9, 5)), //Incorrect?
955
1
            // The Ides of March, the day that Julius Caesar died (-44) (See Julian test)
956
1
            // Robert Goddard launches the first successful liquid-fuel rocket (1926)
957
1
            // ??
958
1
            // The US Congress authorizes conversion to standard time zones and daylight saving time (1918)
959
1
            // 1918-03-29 https://en.wikipedia.org/wiki/Standard_Time_Act
960
1
            // (CommonDate::new(1918, 3, 29), CommonDate::new(-12, 9, 18)), //Incorrect?
961
1
            // Vernal equinox. Serpent of light appears on the pyramid at Chichen Itza, Mexico (1990)
962
1
            // 1990-03-20 https://aa.usno.navy.mil/calculated/seasons?year=1990&tz=0.00&tz_sign=-1&tz_label=false&dst=false&submit=Get+Data
963
1
            (CommonDate::new(1990, 3, 20), CommonDate::new(21, 9, 19)),
964
1
            // Accident at Three Mile Island Nuclear Generating Station in Pennsylvania (1979)
965
1
            // 1979-03-28 https://en.wikipedia.org/wiki/Three_Mile_Island_accident
966
1
            (CommonDate::new(1979, 3, 28), CommonDate::new(10, 9, 27)),
967
1
            // Mariner 10 spacecraft approaches Mercury and sends 647 photos back to Earth (1974)
968
1
            // 1974-03-29 https://en.wikipedia.org/wiki/Mariner_10
969
1
            (CommonDate::new(1974, 3, 29), CommonDate::new(5, 9, 28)),
970
1
            // Samuel Morey patents the internal-combustion engine (1826)
971
1
            // 1826-04-01 https://www.ancientpages.com/2017/04/01/samuel-morey-patent/
972
1
            (CommonDate::new(1826, 4, 1), CommonDate::new(-144, 10, 3)),
973
1
            // First commerical communications satellite launched (US) (1965)
974
1
            // 1965-04-06 https://en.wikipedia.org/wiki/Communications_satellite
975
1
            // (CommonDate::new(1965, 4, 6), CommonDate::new(-5, 10, 6)), //Incorrect?
976
1
            // Robert E. Peary claims discovery of the North Pole (1909)
977
1
            // 1909-04-06 wiki:https://en.wikipedia.org/wiki/Robert_Peary
978
1
            (CommonDate::new(1909, 4, 6), CommonDate::new(-61, 10, 8)),
979
1
            // Cosmonaut Yuri Gagarin of the USSR orbits Earth, becoming the first human in space (1961)
980
1
            // 1961-04-12 https://en.wikipedia.org/wiki/Vostok_1
981
1
            (CommonDate::new(1961, 4, 12), CommonDate::new(-9, 10, 14)),
982
1
            // Two giant pandas, gifts from People's Republic of China, arrive at the National Zoo in Washington DC (1972)
983
1
            // 1972-04-16 wiki:https://en.wikipedia.org/wiki/Ling-Ling_and_Hsing-Hsing
984
1
            (CommonDate::new(1972, 4, 16), CommonDate::new(3, 10, 18)),
985
1
            // -284, 10, 19
986
1
            // Sir Isaac Newton presents Philosophiae naturalis principia mathematica to the Royal Society (1686)
987
1
            // ??
988
1
            // Francis Crick and James Watson report their discovery of the DNA double helix (1953)
989
1
            //1953-04-25 wiki:https://www.nature.com/articles/171737a0
990
1
            (CommonDate::new(1953, 04, 25), CommonDate::new(-17, 10, 27)),
991
1
            // Alan Shepard becomes the first American in space (1961)
992
1
            //1961-05-05 wiki:https://en.wikipedia.org/wiki/Mercury-Redstone_3
993
1
            (CommonDate::new(1961, 05, 05), CommonDate::new(-9, 11, 9)),
994
1
            // -174, 11, 18
995
1
            // Dr Edward Jenner conducts his first experiment with cow-pox vaccination (1796)
996
1
            // ??
997
1
            // Charles Lindbergh lands in Paris, becoming the first person to fly an airplane solo, nonstop across the Atlantic Ocean (1927)
998
1
            //1927-05-21 wiki:https://en.wikipedia.org/wiki/Spirit_of_St._Louis
999
1
            (CommonDate::new(1927, 05, 21), CommonDate::new(-43, 11, 25)),
1000
1
            // The Concorde supersonic transport makes its first transatlantic flight to USA (1976)
1001
1
            //1976-05-24 wiki:https://en.wikipedia.org/wiki/Concorde_operational_history
1002
1
            (CommonDate::new(1976, 05, 24), CommonDate::new(7, 11, 28)),
1003
1
            // Most famous ancient solar eclipse occurs during a battle between Lydians and Medes (585 BC) (see Julian test)
1004
1
            // -585-05-28 wiki:https://en.wikipedia.org/wiki/Eclipse_of_Thales
1005
1
            // You would think this is a Julian date but no, this is a Gregorian date without year 0
1006
1
            (CommonDate::new(-584, 5, 28), CommonDate::new(-2554, 12, 4)),
1007
1
            // US launches the Mariner 9, first spacecraft to orbit another planet (1971)
1008
1
            // 1971-05-30 https://en.wikipedia.org/wiki/Mariner_9
1009
1
            (CommonDate::new(1971, 5, 30), CommonDate::new(2, 12, 6)),
1010
1
            // Guglielmo Marconi is granted patent for the radio in Great Britain (1896)
1011
1
            // 1896-06-02 https://en.wikipedia.org/wiki/Guglielmo_Marconi
1012
1
            (CommonDate::new(1896, 6, 2), CommonDate::new(-74, 12, 9)),
1013
1
            // Byron Allen pedals Gossamer Albatross aircraft across the English Channel (1979)
1014
1
            // 1979-06-12 https://en.wikipedia.org/wiki/MacCready_Gossamer_Albatross
1015
1
            (CommonDate::new(1979, 6, 12), CommonDate::new(10, 12, 19)),
1016
1
            // Pioneer 10 exits solar system (1983)
1017
1
            // 1983-06-13 https://en.wikipedia.org/wiki/Pioneer_10
1018
1
            (CommonDate::new(1983, 6, 13), CommonDate::new(14, 12, 20)),
1019
1
            // Ben Franklin flies kite during a lightning storm and discovers electricity (1752)
1020
1
            //1752-06-15 https://en.wikipedia.org/wiki/Benjamin_Franklin
1021
1
            (CommonDate::new(1752, 6, 15), CommonDate::new(-218, 12, 22)),
1022
1
            // Sally Ride becomes first US woman in space (1983)
1023
1
            //1983-06-18 https://en.wikipedia.org/wiki/STS-7
1024
1
            (CommonDate::new(1983, 6, 18), CommonDate::new(14, 12, 25)),
1025
1
            // Summer solstice, longest day of year, Northern Hemisphere (1990)
1026
1
            //1990-06-21 https://aa.usno.navy.mil/calculated/seasons?year=1990&tz=0.00&tz_sign=-1&tz_label=false&dst=false&submit=Get+Data
1027
1
            (CommonDate::new(1990, 6, 21), CommonDate::new(21, 12, 28)),
1028
1
            // First reported UFO sighting using the term flying saucers (1947)
1029
1
            //1947-06-24 https://en.wikipedia.org/wiki/Kenneth_Arnold_UFO_sighting
1030
1
            (CommonDate::new(1947, 6, 24), CommonDate::new(-23, 13, 3)),
1031
1
            // -13, 13, 4
1032
1
            // CBS broadcasts first commercial color TV program (1957)
1033
1
            // ???
1034
1
            // Mysterious explosion devastates a huge forest in Tunguska, Siberia (1908)
1035
1
            // 1908-06-30 https://en.wikipedia.org/wiki/Tunguska_event
1036
1
            (CommonDate::new(1908, 6, 30), CommonDate::new(-62, 13, 9)),
1037
1
            // -83, 13, 15
1038
1
            // Louis Pasteur inoculates a boy with antirabies serum (1887)
1039
1
            // ???
1040
1
            // Skylab falls to Earth (1979)
1041
1
            // 1979-07-11 https://en.wikipedia.org/wiki/Skylab
1042
1
            (CommonDate::new(1979, 7, 11), CommonDate::new(10, 13, 20)),
1043
1
            // -8, 13, 22
1044
1
            // First transatlantic conversation using communications satellite (1962)
1045
1
            // 1962-07-23 wiki:https://en.wikipedia.org/wiki/Telstar
1046
1
            // (CommonDate::new(1962, 7, 23), CommonDate::new(-8, 13, 22)), //Incorrect?
1047
1
            // First atomic bomb is detonated, Trinity Site, New Mexico (1945)
1048
1
            // 1945-07-16 https://en.wikipedia.org/wiki/Trinity_(nuclear_test)
1049
1
            (CommonDate::new(1945, 7, 16), CommonDate::new(-25, 13, 25)),
1050
1
        ];
1051
59
        for 
pair58
in d_list {
1052
58
            let dg = Gregorian::try_from_common_date(pair.0).unwrap().to_fixed();
1053
58
            let dq = TranquilityMoment::try_from_common_date(pair.1)
1054
58
                .unwrap()
1055
58
                .to_fixed();
1056
58
            assert_eq!(dg.get_day_i(), dq.get_day_i(), 
"{:?}"0
, pair);
1057
        }
1058
1
    }
1059
1060
    // #[test]
1061
    // fn article_examples_julian() {
1062
    //     let d_list = [
1063
    //         // From Siggins' article
1064
    //         // Pope Gregory corrects the Julian calendar (1582)
1065
    //         // 1582-02-24 (Julian) wiki:https://en.wikipedia.org/wiki/Inter_gravissimas
1066
    //         // Off by 23, that's pretty bad
1067
    //         (CommonDate::new(1582, 2, 3), CommonDate::new(-388, 8, 12)),
1068
    //         // The Ides of March, the day that Julius Caesar died (-44)
1069
    //         // -44-03-15 (Julian) wiki:https://en.wikipedia.org/wiki/Julius_Caesar
1070
    //         // Off by 2, could this be caused by using a proleptic Julian calendar?
1071
    //         (CommonDate::new(-44, 3, 17), CommonDate::new(-2013, 9, 14)),
1072
    //     ];
1073
    //     for pair in d_list {
1074
    //         let dg = Julian::try_from_common_date(pair.0).unwrap().to_fixed();
1075
    //         let dq = TranquilityMoment::try_from_common_date(pair.1)
1076
    //             .unwrap()
1077
    //             .to_fixed();
1078
    //         assert_eq!(dg.get_day_i(), dq.get_day_i(), "{:?}", pair);
1079
    //     }
1080
    // }
1081
1082
    #[test]
1083
1
    fn orions_arm() {
1084
1
        let d_list = [
1085
1
            // Orion's Arm Encyclopaedia Galactica - Atomic Age
1086
1
            // https://www.orionsarm.com/eg-topic/460b135b0c6d8
1087
1
            // Orion's Arm Calendar Converter
1088
1
            // https://www.orionsarm.com/xcms.php?r=oa-calendar-converter
1089
1
            // Wikipedia
1090
1
            // https://en.wikipedia.org/wiki/Subrahmanyan_Chandrasekhar
1091
1
            // https://en.wikipedia.org/wiki/Albert_Einstein
1092
1
            // https://en.wikipedia.org/wiki/Yuri_Gagarin
1093
1
            // In cases where articles conflict with the calendar converter,
1094
1
            // the calendar converter is used. These cases are marked with *
1095
1
            (CommonDate::new(1910, 10, 19), -59), //Chandrasekhar
1096
1
            (CommonDate::new(1995, 8, 21), 27),   //Chandrasekhar*
1097
1
            (CommonDate::new(1879, 3, 14), -91),  //Einstein*
1098
1
            (CommonDate::new(1955, 4, 18), -15),  //Einstein*
1099
1
            (CommonDate::new(1934, 3, 9), -36),   //Gagarin*
1100
1
            (CommonDate::new(1968, 3, 27), -2),   //Gagarin*
1101
1
            (CommonDate::new(1912, 6, 23), -58),  //Turing*
1102
1
            (CommonDate::new(1954, 6, 7), -16),   //Turing*
1103
1
        ];
1104
9
        for 
pair8
in d_list {
1105
8
            let f = Gregorian::try_from_common_date(pair.0).unwrap().to_fixed();
1106
8
            let dq = TranquilityMoment::from_fixed(f);
1107
8
            assert_eq!(dq.year(), pair.1);
1108
        }
1109
1
    }
1110
1111
    proptest! {
1112
        #[test]
1113
        fn gregorian_lookup(t in FIXED_MIN..FIXED_MAX) {
1114
            // https://web.archive.org/web/20180818233025/https://en.wikipedia.org/wiki/Tranquility_calendar
1115
            let f = RataDie::new(t).to_fixed().to_day();
1116
            let g = Gregorian::from_fixed(f);
1117
            let gc = g.to_common_date();
1118
            let q = TranquilityMoment::from_fixed(f);
1119
            if q.try_month().is_some() {
1120
                let qm = q.try_month().unwrap();
1121
                let entry = match qm {
1122
                    TranquilityMonth::Archimedes => ((7, 21), (8, 17)),
1123
                    TranquilityMonth::Brahe => ((8, 18), (9, 14)),
1124
                    TranquilityMonth::Copernicus => ((9, 15), (10, 12)),
1125
                    TranquilityMonth::Darwin => ((10, 13), (11, 9)),
1126
                    TranquilityMonth::Einstein => ((11, 10), (12, 7)),
1127
                    TranquilityMonth::Faraday => ((12, 8), (1, 4)),
1128
                    TranquilityMonth::Galileo => ((1, 5), (2, 1)),
1129
                    TranquilityMonth::Hippocrates => ((2, 2), (3, 1)),
1130
                    TranquilityMonth::Imhotep => ((3, 2), (3, 29)),
1131
                    TranquilityMonth::Jung => ((3, 30), (4, 26)),
1132
                    TranquilityMonth::Kepler => ((4, 27), (5, 24)),
1133
                    TranquilityMonth::Lavoisier => ((5, 25), (6, 21)),
1134
                    TranquilityMonth::Mendel => ((6, 22), (7, 19)),
1135
                };
1136
                let mut y_min = gc.year;
1137
                let mut y_max = gc.year;
1138
                if qm == TranquilityMonth::Faraday {
1139
                    let in_new_year = gc.month == entry.1.0;
1140
                    y_min = if in_new_year { gc.year - 1 } else { gc.year };
1141
                    y_max = y_min + 1;
1142
                }
1143
                let gc_min = CommonDate::new(y_min, entry.0.0, entry.0.1);
1144
                let gc_max = CommonDate::new(y_max, entry.1.0, entry.1.1);
1145
                assert!(gc >= gc_min, "gc: {:?}, gc_min: {:?}, q: {:?}", gc, gc_min, q);
1146
                assert!(gc <= gc_max, "gc: {:?}, gc_max: {:?}, q: {:?}", gc, gc_max, q);
1147
            } else {
1148
                let qc = q.epagomenae().unwrap();
1149
                let entry = match qc {
1150
                    TranquilityComplementaryDay::MoonLandingDay => (7, 20),
1151
                    TranquilityComplementaryDay::ArmstrongDay => (7, 20),
1152
                    TranquilityComplementaryDay::AldrinDay => (2, 29)
1153
                };
1154
                assert_eq!(gc.month as i64, entry.0);
1155
                assert_eq!(gc.day as i64, entry.1);
1156
            }
1157
        }
1158
1159
        #[test]
1160
        fn gregorian_lookup_small(t in i8::MIN..i8::MAX) {
1161
            // https://web.archive.org/web/20180818233025/https://en.wikipedia.org/wiki/Tranquility_calendar
1162
            let e = TranquilityMoment::epoch().get_day_i();
1163
            let f = RataDie::cast_new(e + (t as i64)).to_fixed().to_day();
1164
            let g = Gregorian::from_fixed(f);
1165
            let gc = g.to_common_date();
1166
            let q = TranquilityMoment::from_fixed(f);
1167
            if q.try_month().is_some() {
1168
                let qm = q.try_month().unwrap();
1169
                let entry = match qm {
1170
                    TranquilityMonth::Archimedes => ((7, 21), (8, 17)),
1171
                    TranquilityMonth::Brahe => ((8, 18), (9, 14)),
1172
                    TranquilityMonth::Copernicus => ((9, 15), (10, 12)),
1173
                    TranquilityMonth::Darwin => ((10, 13), (11, 9)),
1174
                    TranquilityMonth::Einstein => ((11, 10), (12, 7)),
1175
                    TranquilityMonth::Faraday => ((12, 8), (1, 4)),
1176
                    TranquilityMonth::Galileo => ((1, 5), (2, 1)),
1177
                    TranquilityMonth::Hippocrates => ((2, 2), (3, 1)),
1178
                    TranquilityMonth::Imhotep => ((3, 2), (3, 29)),
1179
                    TranquilityMonth::Jung => ((3, 30), (4, 26)),
1180
                    TranquilityMonth::Kepler => ((4, 27), (5, 24)),
1181
                    TranquilityMonth::Lavoisier => ((5, 25), (6, 21)),
1182
                    TranquilityMonth::Mendel => ((6, 22), (7, 19)),
1183
                };
1184
                let mut y_min = gc.year;
1185
                let mut y_max = gc.year;
1186
                if qm == TranquilityMonth::Faraday {
1187
                    let in_new_year = gc.month == entry.1.0;
1188
                    y_min = if in_new_year { gc.year - 1 } else { gc.year };
1189
                    y_max = y_min + 1;
1190
                }
1191
                let gc_min = CommonDate::new(y_min, entry.0.0, entry.0.1);
1192
                let gc_max = CommonDate::new(y_max, entry.1.0, entry.1.1);
1193
                assert!(gc >= gc_min, "gc: {:?}, gc_min: {:?}, q: {:?}", gc, gc_min, q);
1194
                assert!(gc <= gc_max, "gc: {:?}, gc_max: {:?}, q: {:?}", gc, gc_max, q);
1195
            } else {
1196
                let qc = q.epagomenae().unwrap();
1197
                let entry = match qc {
1198
                    TranquilityComplementaryDay::MoonLandingDay => (7, 20),
1199
                    TranquilityComplementaryDay::ArmstrongDay => (7, 20),
1200
                    TranquilityComplementaryDay::AldrinDay => (2, 29)
1201
                };
1202
                assert_eq!(gc.month as i64, entry.0);
1203
                assert_eq!(gc.day as i64, entry.1);
1204
            }
1205
        }
1206
    }
1207
}