1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Excel の日付の数を、年月日に直すところ
use folio::date::{self, Moment};
/// 時刻のない日付
fn day(year: i64, month: u32, number: u32) -> Moment {
Moment {year, month, day: number, hour: 0, minute: 0, second: 0}
}
/// 次の日。暦の決まりをここで書き直して、folio の計算と突き合わせる
fn next_day(one: Moment) -> Moment {
let leap = (one.year % 4 == 0 && one.year % 100 != 0) || one.year % 400 == 0;
let length = match one.month {
2 => if leap {29} else {28},
4 | 6 | 9 | 11 => 30,
_ => 31,
};
if one.day < length {
return Moment {day: one.day + 1, ..one};
}
if one.month < 12 {
return Moment {month: one.month + 1, day: 1, ..one};
}
Moment {year: one.year + 1, month: 1, day: 1, ..one}
}
#[test]
fn the_known_landmarks_match() {
// Excel が入っていれば、どの版でもこの対応になる
assert_eq!(date::moment(1.0, false), day(1900, 1, 1));
assert_eq!(date::moment(59.0, false), day(1900, 2, 28));
assert_eq!(date::moment(61.0, false), day(1900, 3, 1));
assert_eq!(date::moment(25569.0, false), day(1970, 1, 1));
assert_eq!(date::moment(45000.0, false), day(2023, 3, 15));
}
#[test]
fn the_1904_system_starts_four_years_later() {
assert_eq!(date::moment(0.0, true), day(1904, 1, 1));
assert_eq!(date::moment(1.0, true), day(1904, 1, 2));
assert_eq!(date::moment(24107.0, true), day(1970, 1, 1));
}
#[test]
fn the_fraction_becomes_the_time_of_day() {
let noon = date::moment(45000.5, false);
assert_eq!(noon, Moment {year: 2023, month: 3, day: 15, hour: 12, minute: 0, second: 0});
let when = date::moment(45000.0 + (13.0 * 3600.0 + 45.0 * 60.0 + 30.0) / 86400.0, false);
assert_eq!(when, Moment {year: 2023, month: 3, day: 15, hour: 13, minute: 45, second: 30});
}
#[test]
fn consecutive_numbers_are_consecutive_days() {
// 1900 年のずれをまたいで、1 日ずつ確かめる
let mut previous = date::moment(1.0, false);
for serial in 2..60000 {
// 60 は Excel にしかない 1900-02-29 で、folio は 2 月 28 日として返す
if serial == 60 {
assert_eq!(date::moment(60.0, false), day(1900, 2, 28));
continue;
}
let when = date::moment(serial as f64, false);
assert_eq!(when, next_day(previous), "{serial}");
previous = when;
}
}
#[test]
fn the_1904_system_is_1462_days_behind() {
for serial in 0..60000 {
let one = date::moment(serial as f64, true);
assert_eq!(one, date::moment(serial as f64 + 1462.0, false), "{serial}");
}
}