cftime_rs/datetimes/
standard.rs

1use crate::calendars::Calendar;
2use crate::datetimes::traits::{CalendarDatetime, IsLeap};
3use crate::timezone::Tz;
4use crate::utils::{
5    get_timestamp_from_hms, get_timestamp_from_ymd, get_ymd_hms_from_timestamp, is_leap_gregorian,
6    is_leap_julian,
7};
8
9use super::traits::CalendarDatetimeCreator;
10pub struct StandardDatetime {
11    pub timestamp: i64,
12    pub nanoseconds: u32,
13    pub tz: Tz,
14    pub calendar: Calendar,
15}
16
17impl StandardDatetime {
18    pub fn new(timestamp: i64, nanoseconds: u32, tz: Tz) -> Self {
19        Self {
20            timestamp,
21            nanoseconds,
22            tz,
23            calendar: Calendar::Standard,
24        }
25    }
26}
27impl IsLeap for StandardDatetime {
28    fn is_leap(year: i64) -> bool {
29        if year < 1582 {
30            is_leap_julian(year)
31        } else {
32            is_leap_gregorian(year)
33        }
34    }
35}
36
37impl CalendarDatetime for StandardDatetime {
38    fn timestamp(&self) -> i64 {
39        self.timestamp
40    }
41    fn nanoseconds(&self) -> u32 {
42        self.nanoseconds
43    }
44    fn calendar(&self) -> Calendar {
45        self.calendar
46    }
47    fn timezone(&self) -> Tz {
48        self.tz
49    }
50    fn ymd_hms(&self) -> Result<(i64, u8, u8, u8, u8, u8), crate::errors::Error> {
51        let gregorian_begin = get_timestamp_from_ymd::<StandardDatetime>(1582, 10, 15)?;
52        let mut timestamp = self.timestamp;
53        if self.timestamp < gregorian_begin {
54            let seconds_in_10_days = 10 * 24 * 60 * 60;
55            timestamp -= seconds_in_10_days
56        }
57        Ok(get_ymd_hms_from_timestamp::<StandardDatetime>(timestamp))
58    }
59}
60
61impl CalendarDatetimeCreator for StandardDatetime {
62    fn from_timestamp(timestamp: i64, _nanoseconds: u32) -> Self {
63        Self {
64            timestamp,
65            nanoseconds: 0,
66            tz: Tz::new(0, 0).unwrap(),
67            calendar: Calendar::Standard,
68        }
69    }
70    fn from_ymd_hms(
71        year: i64,
72        month: u8,
73        day: u8,
74        hour: u8,
75        minute: u8,
76        second: f32,
77    ) -> Result<Self, crate::errors::Error> {
78        let (mut timestamp, nanoseconds) = get_timestamp_from_hms(hour, minute, second)?;
79        if year == 1582
80            && month == 10
81            && ((day == 4 && (hour > 0 || minute > 0 || second > 0.0)) || (5..15).contains(&day))
82        {
83            return Err(crate::errors::Error::InvalidDate(
84                "Date between 1582-10-04 and 1582-10-15 are not defined in the standard calendar"
85                    .to_string(),
86            ));
87        }
88        if year < 1582 || (year == 1582 && month < 10) || (year == 1582 && month == 10 && day < 15)
89        {
90            // Add 10 days from julian / gregorian break
91            timestamp += 10 * 24 * 60 * 60
92        }
93
94        timestamp += get_timestamp_from_ymd::<StandardDatetime>(year, month, day)?;
95        Ok(Self {
96            timestamp,
97            nanoseconds,
98            tz: Tz::new(0, 0).unwrap(),
99            calendar: Calendar::Standard,
100        })
101    }
102}