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}