qubit_clock/zoned.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit 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 qubit_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 qubit_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 qubit_clock::{SystemClock, Zoned};
97 /// use chrono_tz::Asia::Shanghai;
98 ///
99 /// let clock = Zoned::new(SystemClock::new(), Shanghai);
100 /// ```
101 ///
102 #[inline]
103 pub fn new(clock: C, timezone: Tz) -> Self {
104 Zoned { clock, timezone }
105 }
106
107 /// Returns a reference to the inner clock.
108 ///
109 /// # Returns
110 ///
111 /// A reference to the wrapped clock.
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use qubit_clock::{Clock, SystemClock, Zoned};
117 /// use chrono_tz::Asia::Shanghai;
118 ///
119 /// let clock = Zoned::new(SystemClock::new(), Shanghai);
120 /// let inner = clock.inner();
121 /// let millis = inner.millis();
122 /// ```
123 ///
124 #[inline]
125 pub fn inner(&self) -> &C {
126 &self.clock
127 }
128
129 /// Consumes the `Zoned` wrapper and returns the inner clock.
130 ///
131 /// # Returns
132 ///
133 /// The wrapped clock.
134 ///
135 /// # Examples
136 ///
137 /// ```
138 /// use qubit_clock::{SystemClock, Zoned};
139 /// use chrono_tz::Asia::Shanghai;
140 ///
141 /// let clock = Zoned::new(SystemClock::new(), Shanghai);
142 /// let inner = clock.into_inner();
143 /// ```
144 ///
145 #[inline]
146 pub fn into_inner(self) -> C {
147 self.clock
148 }
149}
150
151impl<C: Clock> Clock for Zoned<C> {
152 #[inline]
153 fn millis(&self) -> i64 {
154 self.clock.millis()
155 }
156
157 #[inline]
158 fn time(&self) -> DateTime<Utc> {
159 self.clock.time()
160 }
161}
162
163impl<C: Clock> ZonedClock for Zoned<C> {
164 #[inline]
165 fn timezone(&self) -> Tz {
166 self.timezone
167 }
168
169 #[inline]
170 fn local_time(&self) -> DateTime<Tz> {
171 self.timezone.from_utc_datetime(&self.time().naive_utc())
172 }
173}
174
175impl<C: Clock> Deref for Zoned<C> {
176 type Target = C;
177
178 #[inline]
179 fn deref(&self) -> &Self::Target {
180 &self.clock
181 }
182}