prism3_clock/
zoned.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! Timezone wrapper for clocks.
10//!
11//! This module provides [`Zoned`], a generic wrapper that adds timezone
12//! support to any clock implementation.
13//!
14//! # Author
15//!
16//! Haixing Hu
17
18use crate::{Clock, ZonedClock};
19use chrono::{DateTime, TimeZone, Utc};
20use chrono_tz::Tz;
21use std::ops::Deref;
22
23/// A wrapper that adds timezone support to any clock.
24///
25/// `Zoned<C>` wraps any clock implementing [`Clock`] and adds timezone
26/// functionality by implementing [`ZonedClock`]. It can convert UTC time to
27/// local time in the specified timezone.
28///
29/// # Deref Behavior
30///
31/// This type implements [`Deref`] to allow direct access to the wrapped
32/// clock's methods. This is particularly useful when wrapping controllable
33/// clocks like [`MockClock`](crate::MockClock).
34///
35/// # Examples
36///
37/// ```
38/// use prism3_clock::{Clock, ZonedClock, SystemClock, Zoned};
39/// use chrono_tz::Asia::Shanghai;
40///
41/// // Wrap a SystemClock with Shanghai timezone
42/// let clock = Zoned::new(SystemClock::new(), Shanghai);
43/// let local = clock.local_time();
44/// println!("Local time in Shanghai: {}", local);
45/// ```
46///
47/// ## Using with MockClock
48///
49/// ```
50/// use prism3_clock::{
51///     Clock, ZonedClock, ControllableClock, MockClock, Zoned
52/// };
53/// use chrono::{DateTime, Utc};
54/// use chrono_tz::Asia::Shanghai;
55///
56/// let mock = MockClock::new();
57/// let clock = Zoned::new(mock, Shanghai);
58///
59/// // Can use ZonedClock methods
60/// let local = clock.local_time();
61///
62/// // Can also use ControllableClock methods via Deref
63/// let time = DateTime::parse_from_rfc3339(
64///     "2024-01-01T00:00:00Z"
65/// ).unwrap().with_timezone(&Utc);
66/// clock.set_time(time);
67/// ```
68///
69/// # Author
70///
71/// Haixing Hu
72#[derive(Debug, Clone)]
73pub struct Zoned<C: Clock> {
74    /// The wrapped clock.
75    clock: C,
76    /// The timezone for this clock.
77    timezone: Tz,
78}
79
80impl<C: Clock> Zoned<C> {
81    /// Creates a new `Zoned` clock wrapping the given clock with the
82    /// specified timezone.
83    ///
84    /// # Arguments
85    ///
86    /// * `clock` - The clock to wrap.
87    /// * `timezone` - The timezone to use for local time conversions.
88    ///
89    /// # Returns
90    ///
91    /// A new `Zoned<C>` instance.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use prism3_clock::{SystemClock, Zoned};
97    /// use chrono_tz::Asia::Shanghai;
98    ///
99    /// let clock = Zoned::new(SystemClock::new(), Shanghai);
100    /// ```
101    ///
102    pub fn new(clock: C, timezone: Tz) -> Self {
103        Zoned { clock, timezone }
104    }
105
106    /// Returns a reference to the inner clock.
107    ///
108    /// # Returns
109    ///
110    /// A reference to the wrapped clock.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use prism3_clock::{Clock, SystemClock, Zoned};
116    /// use chrono_tz::Asia::Shanghai;
117    ///
118    /// let clock = Zoned::new(SystemClock::new(), Shanghai);
119    /// let inner = clock.inner();
120    /// let millis = inner.millis();
121    /// ```
122    ///
123    pub fn inner(&self) -> &C {
124        &self.clock
125    }
126
127    /// Consumes the `Zoned` wrapper and returns the inner clock.
128    ///
129    /// # Returns
130    ///
131    /// The wrapped clock.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use prism3_clock::{SystemClock, Zoned};
137    /// use chrono_tz::Asia::Shanghai;
138    ///
139    /// let clock = Zoned::new(SystemClock::new(), Shanghai);
140    /// let inner = clock.into_inner();
141    /// ```
142    ///
143    pub fn into_inner(self) -> C {
144        self.clock
145    }
146}
147
148impl<C: Clock> Clock for Zoned<C> {
149    fn millis(&self) -> i64 {
150        self.clock.millis()
151    }
152
153    fn time(&self) -> DateTime<Utc> {
154        self.clock.time()
155    }
156}
157
158impl<C: Clock> ZonedClock for Zoned<C> {
159    fn timezone(&self) -> Tz {
160        self.timezone
161    }
162
163    fn local_time(&self) -> DateTime<Tz> {
164        self.timezone.from_utc_datetime(&self.time().naive_utc())
165    }
166}
167
168impl<C: Clock> Deref for Zoned<C> {
169    type Target = C;
170
171    fn deref(&self) -> &Self::Target {
172        &self.clock
173    }
174}