spinoso_time/time/tzrs/
timezone.rs

1use tz::datetime::DateTime;
2
3use super::{Offset, Result, Time};
4
5// Timezone conversions (returns new Time)
6impl Time {
7    /// Returns a new Time object representing _time_ based on the provided
8    /// offset.
9    ///
10    /// Can be used to implement [`Time#getlocal`] with a string/number
11    /// parameter.
12    ///
13    /// # Examples
14    ///
15    /// ```
16    /// use tzdb::time_zone::europe::AMSTERDAM;
17    /// # use spinoso_time::tzrs::{Offset, Time, TimeError};
18    /// # fn example() -> Result<(), TimeError> {
19    /// let ams_offset = Offset::from(AMSTERDAM);
20    /// let now_utc = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
21    /// let now_ams = now_utc.to_offset(ams_offset)?;
22    /// assert!(!now_ams.is_utc());
23    /// # Ok(())
24    /// # }
25    /// # example().unwrap()
26    /// ```
27    ///
28    /// # Errors
29    ///
30    /// Can produce a [`TimeError`], might come as a result of an offset causing
31    /// the `unix_time` to exceed `i64::MAX`.
32    ///
33    /// [`Time#getlocal`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-getlocal
34    /// [`TimeError`]: super::TimeError
35    #[inline]
36    pub fn to_offset(&self, offset: Offset) -> Result<Self> {
37        Self::with_timespec_and_offset(self.inner.unix_time(), self.inner.nanoseconds(), offset)
38    }
39
40    /// Returns a new _time_ in UTC.
41    ///
42    /// Can be used to implement [`Time#getutc`] and [`Time#getgm`].
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// # use spinoso_time::tzrs::{Time, TimeError};
48    /// # fn example() -> Result<(), TimeError> {
49    /// let now_local = Time::now()?;
50    /// let now_utc = now_local.to_utc()?;
51    /// assert_eq!(now_utc.utc_offset(), 0);
52    /// assert!(now_utc.is_utc());
53    /// # Ok(())
54    /// # }
55    /// # example().unwrap()
56    /// ```
57    ///
58    /// # Errors
59    ///
60    /// Can produce a [`TimeError`], might come as a result of an offset causing
61    /// the `unix_time` to exceed `i64::MAX`.
62    ///
63    ///
64    /// [`Time#getutc`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-getutc
65    /// [`Time#getgm`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-getgm
66    /// [`TimeError`]: super::TimeError
67    #[inline]
68    pub fn to_utc(&self) -> Result<Self> {
69        self.to_offset(Offset::utc())
70    }
71
72    /// Returns a new Time object representing _time_ in local time (using the
73    /// local time zone in effect for this process).
74    ///
75    /// Can be used to implement [`Time#getlocal`].
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// # use spinoso_time::tzrs::{Time, TimeError};
81    /// # fn example() -> Result<(), TimeError> {
82    /// let now_utc = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
83    /// let now_local = Time::local(2022, 7, 8, 12, 34, 56, 0)?;
84    /// assert_eq!(now_utc.to_local()?.utc_offset(), now_local.utc_offset());
85    /// # Ok(())
86    /// # }
87    /// # example().unwrap()
88    /// ```
89    ///
90    /// # Errors
91    ///
92    /// Can produce a [`TimeError`], might come as a result of an offset causing
93    /// the `unix_time` to exceed `i64::MAX`.
94    ///
95    /// [`Time#getlocal`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-getlocal
96    /// [`TimeError`]: super::TimeError
97    #[inline]
98    pub fn to_local(&self) -> Result<Self> {
99        self.to_offset(Offset::local())
100    }
101}
102
103// Timezone mutations
104impl Time {
105    /// Converts _time_ to the provided time zone, modifying the receiver.
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// # use spinoso_time::tzrs::{Time, Offset, TimeError};
111    /// # fn example() -> Result<(), TimeError> {
112    /// let mut now = Time::utc(2022, 6, 8, 12, 0, 0, 0)?;
113    /// let gmt_plus_one = Offset::try_from(3600)?;
114    /// now.set_offset(gmt_plus_one);
115    /// assert_eq!(13, now.hour());
116    /// # Ok(())
117    /// # }
118    /// # example().unwrap()
119    /// ```
120    ///
121    /// # Errors
122    ///
123    /// Can produce a [`TimeError`], might come as a result of an offset causing
124    /// the `unix_time` to exceed `i64::MAX`.
125    ///
126    /// [`TimeError`]: super::TimeError
127    #[inline]
128    pub fn set_offset(&mut self, offset: Offset) -> Result<()> {
129        let time_zone_ref = offset.time_zone_ref();
130
131        let time = self.inner.project(time_zone_ref)?;
132        self.inner = time;
133        self.offset = offset;
134        Ok(())
135    }
136
137    /// Converts _time_ to local time (using the local time zone in effective at
138    /// the creation time of _time_), modifying the receiver.
139    ///
140    /// Can be used to implement [`Time#localtime`] without a parameter.
141    ///
142    /// # Examples
143    ///
144    /// ```
145    /// # use spinoso_time::tzrs::{Time, Offset, TimeError};
146    /// # fn example() -> Result<(), TimeError> {
147    /// let mut now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
148    /// let now_utc_unix = now.to_int();
149    /// now.set_local();
150    /// assert!(!now.is_utc());
151    /// let now_local_unix = now.to_int();
152    /// assert_eq!(now_utc_unix, now_local_unix);
153    /// # Ok(())
154    /// # }
155    /// # example().unwrap()
156    /// ```
157    ///
158    /// # Errors
159    ///
160    /// Can produce a [`TimeError`], might come as a result of an offset causing
161    /// the `unix_time` to exceed `i64::MAX`.
162    ///
163    /// [`Time#localtime`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-localtime
164    /// [`TimeError`]: super::TimeError
165    #[inline]
166    pub fn set_local(&mut self) -> Result<()> {
167        self.set_offset(Offset::local())
168    }
169
170    /// Converts _time_ to UTC (GMT), modifying the receiver.
171    ///
172    /// Can be used to implement [`Time#utc`] and [`Time#gmtime`].
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// # use spinoso_time::tzrs::{Time, Offset, TimeError};
178    /// # fn example() -> Result<(), TimeError> {
179    /// let mut now = Time::local(2022, 7, 8, 12, 34, 56, 0)?;
180    /// let now_local_unix = now.to_int();
181    /// now.set_utc();
182    /// assert!(now.is_utc());
183    /// let now_utc_unix = now.to_int();
184    /// assert_eq!(now_local_unix, now_utc_unix);
185    /// # Ok(())
186    /// # }
187    /// # example().unwrap()
188    /// ```
189    ///
190    /// # Errors
191    ///
192    /// Can produce a [`TimeError`], might come as a result of an offset causing
193    /// the `unix_time` to exceed `i64::MAX`.
194    ///
195    /// [`Time#utc`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-utc
196    /// [`Time#gmtime`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-gmtime
197    /// [`TimeError`]: super::TimeError
198    #[inline]
199    pub fn set_utc(&mut self) -> Result<()> {
200        self.set_offset(Offset::utc())
201    }
202
203    /// Converts _time_ to the GMT time zone with the provided offset.
204    ///
205    /// Can be used to implement [`Time#localtime`] with an offset parameter.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # use spinoso_time::tzrs::{Time, Offset, TimeError};
211    /// # fn example() -> Result<(), TimeError> {
212    /// let mut now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
213    /// assert!(now.is_utc());
214    /// let offset = Offset::try_from(3600)?;
215    /// now.set_offset_from_utc(offset);
216    /// assert!(!now.is_utc());
217    /// assert_eq!(now.utc_offset(), 3600);
218    /// # Ok(())
219    /// # }
220    /// # example().unwrap()
221    /// ```
222    ///
223    /// # Errors
224    ///
225    /// Can produce a [`TimeError`], might come as a result of an offset causing
226    /// the `unix_time` to exceed `i64::MAX`.
227    ///
228    /// [`Time#localtime`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-localtime
229    /// [`TimeError`]: super::TimeError
230    #[inline]
231    pub fn set_offset_from_utc(&mut self, offset: Offset) -> Result<()> {
232        let time_zone_ref = offset.time_zone_ref();
233
234        self.inner = DateTime::from_timespec(self.to_int(), self.nanoseconds(), time_zone_ref)?;
235        self.offset = offset;
236
237        Ok(())
238    }
239}