chrono_simpletz/
lib.rs

1//! Simple Zero Sized Typed Utc timezones for [`chrono`].
2//! This needs const generic (for rust >= 1.51 in stable).
3//! ```rust
4//! use chrono::*;
5//! use chrono_simpletz::TimeZoneZst;
6//! use chrono_simpletz::known_timezones::*;
7//! use std::mem::size_of_val;
8//!
9//! //construct by new() or Default::default()
10//! let p9 = UtcP9::new();
11//! //size of UtcP9 is zero
12//! assert_eq!(size_of_val(&p9), 0);
13//! assert_eq!(&p9.to_string(), "+09:00");
14//! assert_eq!(UtcP9::IS_IN_VALID_RANGE, true);
15//!
16//! let time = p9.with_ymd_and_hms(2000, 1, 1,12, 00, 00).unwrap();
17//! let naive_time = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms(3, 0, 0);
18//! assert_eq!(time.naive_utc(), naive_time);
19//! //same size as naive datetime
20//! assert_eq!(size_of_val(&time),size_of_val(&naive_time));
21//!
22//! let fixed = time.with_timezone(&p9.fix());
23//! assert_eq!(time, fixed);
24//! //same Display with FixedOffset
25//! assert_eq!(time.to_string(), fixed.to_string());
26//! // smaller size than FixedOffset size
27//! assert!(size_of_val(&time) < size_of_val(&fixed) )
28//! ```
29//!
30//! # features
31//! ## std (default)
32//! with std
33//!
34//! ## clock (default)
35//! Adds today and now function for TimeZoneZst.
36//!
37//! ## serde
38//! ### serde_ts_(seconds|milliseconds|nanoseconds)(|_option)
39//! Adds modules for de/serialize functions to use with de/serialize_with function.
40//!
41//! ### serde_ts_rfc3339(|_option)
42//! Adds modules for de/serialize functions to use with de/serialize_with function.
43//! You need this when you want to de/serialize like `DateTime<Utc>`, because `DateTime<UtcZtc<H,M>>` cannot impl De/Serialize.
44//!
45#![cfg_attr(not(feature = "std"), no_std)]
46#![cfg_attr(doc_cfg, feature(doc_cfg))]
47
48use chrono::*;
49
50const HOUR_TO_SEC: i32 = 3600;
51const MIN_TO_SEC: i32 = 60;
52pub mod known_timezones;
53#[cfg(feature = "serde")]
54#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
55pub mod serde;
56
57/// Represent Fixed Timezone with zero sized type and const generics.
58/// `HOUR` and `MINUTE` must be in valid range`(-23 <= HOUR <= 23 & MINUTE < 60)`, otherwise compile error will occur.
59/// ```compile_fail
60/// # use chrono::*;
61/// # use chrono_simpletz::*;
62/// let tz = TimeZoneZst::<26, 0>::new();
63/// ```
64#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
65pub struct TimeZoneZst<const HOUR: i32, const MINUTE: u32>;
66
67#[deprecated(since = "0.2.0", note = "Use `TimeZoneZst` instead.")]
68pub type UtcZst<const HOUR: i32, const MINUTE: u32> = TimeZoneZst<HOUR, MINUTE>;
69
70impl<const HOUR: i32, const MINUTE: u32> TimeZoneZst<HOUR, MINUTE> {
71    /// Gets the offset seconds. Should use [`FIXED_OFFSET`](`Self::FIXED_OFFSET`) instead of using this directory.
72    pub const OFFSET_SECS: i32 =
73        HOUR * HOUR_TO_SEC + if HOUR < 0 { -1 } else { 1 } * (MINUTE as i32) * MIN_TO_SEC;
74    /// Checks whether the `HOUR` and `MINUTE` is in valid range`(-23 <= HOUR <= 23 & MINUTE < 60)`. This does not check whether the timezone is known.
75    pub const IS_IN_VALID_RANGE: bool = (HOUR >= -23) & (HOUR <= 23) & (MINUTE < 60);
76    /// Gets the `FixedOffset` without creating a instance.
77    pub const FIXED_OFFSET: FixedOffset = match (
78        FixedOffset::east_opt(Self::OFFSET_SECS),
79        Self::IS_IN_VALID_RANGE,
80    ) {
81        (Some(fix), true) => fix,
82        _ => panic!("Invalid TimeZone"),
83    };
84    /// Creates new `TimeZoneZst`
85    pub const fn new() -> Self {
86        // Check whether the time zone is in valid range.
87        let _ = Self::FIXED_OFFSET;
88        TimeZoneZst
89    }
90    #[cfg(feature = "clock")]
91    #[deprecated(since = "0.3.0")]
92    #[allow(deprecated)]
93    /// Returns a Date which corresponds to the current date. Only available with clock feature.
94    pub fn today() -> Date<Self> {
95        Utc::today().with_timezone(&Self::new())
96    }
97    #[cfg(feature = "clock")]
98    /// Returns a DateTime which corresponds to the current date. Only available with clock feature.
99    pub fn now() -> DateTime<Self> {
100        Utc::now().with_timezone(&Self::new())
101    }
102}
103
104impl<const HOUR: i32, const MINUTE: u32> Offset for TimeZoneZst<HOUR, MINUTE> {
105    fn fix(&self) -> FixedOffset {
106        Self::FIXED_OFFSET
107    }
108}
109
110impl<const HOUR: i32, const MINUTE: u32> TimeZone for TimeZoneZst<HOUR, MINUTE> {
111    type Offset = Self;
112    fn from_offset(offset: &Self::Offset) -> Self {
113        *offset
114    }
115    fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult<Self::Offset> {
116        LocalResult::Single(*self)
117    }
118    fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult<Self::Offset> {
119        LocalResult::Single(*self)
120    }
121    fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Self::Offset {
122        *self
123    }
124    fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Self::Offset {
125        *self
126    }
127}
128
129impl<const HOUR: i32, const MINUTE: u32> Default for TimeZoneZst<HOUR, MINUTE> {
130    fn default() -> Self {
131        Self::new()
132    }
133}
134
135impl<const HOUR: i32, const MINUTE: u32> core::fmt::Debug for TimeZoneZst<HOUR, MINUTE> {
136    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
137        write!(f, "{:+03}:{:02}", HOUR, MINUTE)
138    }
139}
140
141impl<const HOUR: i32, const MINUTE: u32> core::fmt::Display for TimeZoneZst<HOUR, MINUTE> {
142    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
143        write!(f, "{:+03}:{:02}", HOUR, MINUTE)
144    }
145}
146
147#[cfg(test)]
148#[cfg(feature = "std")]
149mod tests {
150    use crate::known_timezones::*;
151    use crate::*;
152    #[test]
153    fn display() {
154        let p9 = UtcP9::default();
155        assert_eq!(&p9.to_string(), "+09:00");
156        assert_eq!(std::mem::size_of_val(&p9), 0);
157        assert_eq!(UtcP9::IS_IN_VALID_RANGE, true);
158        let n = p9.with_ymd_and_hms(2000, 1, 1, 12, 00, 00).unwrap();
159        assert_eq!(
160            n.naive_utc(),
161            NaiveDate::from_ymd_opt(2000, 1, 1)
162                .unwrap()
163                .and_hms_opt(3, 0, 0)
164                .unwrap()
165        );
166        let m9 = UtcM9::default();
167        assert_eq!(&m9.to_string(), "-09:00");
168        let n = m9.with_ymd_and_hms(2000, 1, 1, 12, 00, 00).unwrap();
169        assert_eq!(
170            n.naive_utc(),
171            NaiveDate::from_ymd_opt(2000, 1, 1)
172                .unwrap()
173                .and_hms_opt(21, 0, 0)
174                .unwrap()
175        );
176        let p9 = UtcP9_30::default();
177        let n = p9.with_ymd_and_hms(2000, 1, 1, 12, 00, 00).unwrap();
178        assert_eq!(
179            n.naive_utc(),
180            NaiveDate::from_ymd_opt(2000, 1, 1)
181                .unwrap()
182                .and_hms_opt(2, 30, 0)
183                .unwrap()
184        );
185        let m9 = UtcM9_30::default();
186        let n = m9.with_ymd_and_hms(2000, 1, 1, 12, 00, 00).unwrap();
187        assert_eq!(
188            n.naive_utc(),
189            NaiveDate::from_ymd_opt(2000, 1, 1)
190                .unwrap()
191                .and_hms_opt(21, 30, 0)
192                .unwrap()
193        );
194    }
195}