PHASEXave/interface/date/
mod.rs

1/*
2 * Copyright 2024 Stanislav Mikhailov (xavetar)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 */
28
29pub use crate::types::data::date::{Date};
30
31use crate::types::{
32    data::{
33        time::{Time},
34        zone::{Sign, Zone}
35    },
36    planets::{
37        earth::{
38            calendar::{
39                view::{CalendarView},
40                constants::{
41                    months::{Months},
42                }
43            }
44        },
45    },
46};
47
48#[cfg(any(
49    feature = "platform_specific_functions_darwin",
50    feature = "platform_specific_functions_unix",
51    feature = "platform_specific_functions_windows"
52))]
53use crate::{
54    platform::{
55        tz::{local_timezone}
56    }
57};
58 
59impl Date {
60    pub fn utc(view: CalendarView) -> Date {
61        return Self::of(
62            view,
63            Time::unix().as_secs() as u128,
64            Zone {
65                sign: Sign::Unsigned,
66                hours: 0, minutes: 0,
67                seconds: 0
68            },
69            true
70        );
71    }
72
73    pub fn now(view: CalendarView, time_zone: Zone) -> Date {
74        return Self::of(view, Time::unix().as_secs() as u128, time_zone, false);
75    }
76
77    #[cfg(any(
78        feature = "platform_specific_functions_darwin",
79        feature = "platform_specific_functions_unix",
80        feature = "platform_specific_functions_windows"
81    ))]
82    pub fn local(view: CalendarView) -> Date {
83        return Self::of(view, Time::unix().as_secs() as u128, local_timezone(), false);
84    }
85
86    pub fn from(view: CalendarView, unix_time: u128, time_zone: Zone, zone_in_unix: bool) -> Date {
87        return Self::of(view, unix_time, time_zone, zone_in_unix);
88    }
89
90    pub fn month(&self) -> Months {
91        return Months::from(self.month);
92    }
93}
94
95#[cfg(test)]
96mod tests {
97
98    use super::{
99        CalendarView,
100        Date, Sign, Zone,
101        local_timezone
102    };
103
104    use libc::{
105        time_t, tm,
106        gmtime_r, localtime_r
107    };
108
109    use crate::{
110        types::{
111            planets::{
112                earth::{
113                    calendar::{
114                        constants::{
115                            seconds::{SECONDS_IN_DAY}
116                        }
117                    }
118                }
119            }
120        }
121    };
122
123    #[test]
124    fn test_gmt_date_from_libc() {
125        let mut date_struct_libc: tm = unsafe { std::mem::zeroed::<tm>() };
126
127        let gmt_time_zone: Zone = Zone { sign: Sign::Unsigned, hours: 0_u8, minutes: 0_u8, seconds: 0_u8 };
128
129        let current_seconds: u64 = Date::now(CalendarView::Gregorian, gmt_time_zone).unix_time as u64;
130
131        for unix_time in (0..=current_seconds).step_by(SECONDS_IN_DAY as usize) {
132            let time_c: time_t = unix_time as time_t;
133
134            if unsafe { gmtime_r(&time_c, &mut date_struct_libc) } == std::ptr::null_mut() {
135                panic!("[ERROR]: Pointer is NULL (gmtime_r)!")
136            }
137
138            let date: Date = Date::from(CalendarView::Gregorian, unix_time as u128, gmt_time_zone, false);
139
140            assert_eq!(
141                (
142                    (date_struct_libc.tm_year + 1900) as u64,
143                    (date_struct_libc.tm_mon + 1) as u8,
144                    (date_struct_libc.tm_mday) as u8,
145                    date_struct_libc.tm_gmtoff.unsigned_abs() as u32
146                ),
147                (
148                    date.year,
149                    date.month,
150                    date.day,
151                    date.time_zone.to_seconds()
152                )
153            )
154        }
155    }
156
157    #[test]
158    #[cfg(any(
159        feature = "platform_specific_functions_darwin",
160        feature = "platform_specific_functions_unix",
161        feature = "platform_specific_functions_windows"
162    ))]
163    fn test_fuzz_date_with_libc() {
164        let (mut date, mut sign): (Date, Sign);
165
166        let mut date_struct_libc: tm = unsafe { std::mem::zeroed::<tm>() };
167
168        let current_seconds: u64 = Date::now(CalendarView::Gregorian, local_timezone()).unix_time as u64;
169
170        for unix_time in (0..=current_seconds).step_by(SECONDS_IN_DAY as usize) {
171            let time_c: time_t = unix_time as time_t;
172
173            if unsafe { localtime_r(&time_c, &mut date_struct_libc) } == std::ptr::null_mut() {
174                panic!("[ERROR]: Pointer is NULL (localtime_r)!")
175            }
176
177            if date_struct_libc.tm_gmtoff < 0 { sign = Sign::Signed } else { sign = Sign::Unsigned };
178
179            date = Date::from(CalendarView::Gregorian, unix_time as u128, Zone::from_seconds(sign, date_struct_libc.tm_gmtoff.unsigned_abs() as u32), false);
180
181            assert_eq!(
182                (
183                    (date_struct_libc.tm_year + 1900) as u64,
184                    (date_struct_libc.tm_mon + 1) as u8,
185                    (date_struct_libc.tm_mday) as u8,
186                    (date_struct_libc.tm_gmtoff).unsigned_abs() as u32
187                ),
188                (
189                    date.year,
190                    date.month,
191                    date.day,
192                    date.time_zone.to_seconds()
193                )
194            )
195        }
196    }
197}