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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::{
ops::{Add, Sub},
time::{Duration, SystemTime},
};
use super::{
convert::{month_to_ymdays, ts_to_d_units},
leap::is_leap_year,
};
use crate::{DateTime, Unit};
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ApplyType {
Add,
Sub,
}
pub(crate) fn apply_unit(old: &DateTime, amount: u64, unit: Unit, atype: ApplyType) -> DateTime {
match unit {
Unit::Year => {
let (year, month, mut day) = ts_to_d_units(old.timestamp());
if is_leap_year(year) && month == 2 && day == 29 {
day = 28;
}
let target_year = match atype {
ApplyType::Add => year + amount,
ApplyType::Sub => year - amount,
};
DateTime::from_ymd(target_year, month, day).unwrap()
}
Unit::Month => {
let (year, month, day) = ts_to_d_units(old.timestamp());
let target_year = match atype {
ApplyType::Add => (year * 12 + month + amount - 1) / 12,
ApplyType::Sub => (year * 12 + month - amount - 1) / 12,
};
let target_month = match atype {
ApplyType::Add => {
if (month + amount) % 12 == 0 {
12
} else {
(month + amount) % 12
}
}
ApplyType::Sub => {
if (month - amount) % 12 == 0 {
12
} else {
(month - amount) % 12
}
}
};
let target_day = match day {
day if day < 29 => day,
_ => {
let (_, mdays) = month_to_ymdays(target_year, target_month).unwrap();
if day > mdays {
mdays
} else {
day
}
}
};
DateTime::from_ymd(target_year, target_month, target_day).unwrap()
}
Unit::Day => {
let dur = Duration::new(amount * 60 * 60 * 24, 0);
apply_duration(old, dur, atype)
}
Unit::Hour => {
let dur = Duration::new(amount * 60 * 60, 0);
apply_duration(old, dur, atype)
}
Unit::Min => {
let dur = Duration::new(amount * 60, 0);
apply_duration(old, dur, atype)
}
Unit::Sec => {
let dur = Duration::new(amount, 0);
apply_duration(old, dur, atype)
}
Unit::Milli => {
let dur = Duration::new(0, (amount * 1000000) as u32);
apply_duration(old, dur, atype)
}
Unit::Micro => {
let dur = Duration::new(0, (amount * 1000) as u32);
apply_duration(old, dur, atype)
}
Unit::Nano => {
let dur = Duration::new(0, amount as u32);
apply_duration(old, dur, atype)
}
}
}
pub(crate) fn apply_duration(old: &DateTime, duration: Duration, atype: ApplyType) -> DateTime {
match atype {
ApplyType::Add => DateTime::from(SystemTime::from(old).add(duration)),
ApplyType::Sub => DateTime::from(SystemTime::from(old).sub(duration)),
}
}