spinoso_time/time/tzrs/parts.rs
1use super::Time;
2use crate::MICROS_IN_NANO;
3
4// Parts
5impl Time {
6 /// Returns the number of nanoseconds for _time_.
7 ///
8 /// The lowest digits of `to_f` and nsec are different because IEEE 754
9 /// double is not accurate enough to represent the exact number of
10 /// nanoseconds since the Epoch.
11 ///
12 /// Can be used to implement [`Time#nsec`] and [`Time#tv_nsec`].
13 ///
14 /// # Examples
15 ///
16 /// ```
17 /// # use spinoso_time::{NANOS_IN_SECOND, tzrs::{Time, TimeError}};
18 /// # fn example() -> Result<(), TimeError> {
19 /// let t = Time::utc(2022, 1, 1, 12, 0, 0, 1)?;
20 /// let t_float = t.to_float();
21 /// let float_nanos = (t_float - t_float.round()) * NANOS_IN_SECOND as f64;
22 /// assert_ne!(float_nanos, 1f64);
23 /// assert_eq!(t.nanoseconds(), 1);
24 /// # Ok(())
25 /// # }
26 /// # example().unwrap()
27 /// ```
28 ///
29 /// [`Time#nsec`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-nsec
30 /// [`Time#tv_nsec`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-tv_nsec
31 #[inline]
32 #[must_use]
33 pub fn nanoseconds(&self) -> u32 {
34 self.inner.nanoseconds()
35 }
36
37 /// Returns the number of microseconds for _time_.
38 ///
39 /// Can be used to implement [`Time#usec`] and [`Time#tv_usec`].
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// # use spinoso_time::{MICROS_IN_NANO, tzrs::{Time, TimeError}};
45 /// # fn example() -> Result<(), TimeError> {
46 /// let t = Time::utc(2022, 1, 1, 12, 0, 0, 1 * MICROS_IN_NANO)?;
47 /// assert_eq!(t.microseconds(), 1);
48 /// # Ok(())
49 /// # }
50 /// # example().unwrap()
51 /// ```
52 ///
53 /// [`Time#usec`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-usec
54 /// [`Time#tv_usec`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-tv_usec
55 #[inline]
56 #[must_use]
57 pub fn microseconds(&self) -> u32 {
58 self.inner.nanoseconds() / MICROS_IN_NANO
59 }
60
61 /// Returns the second of the minute `0..=60` for _time_.
62 ///
63 /// Seconds range from zero to 60 to allow the system to inject [leap
64 /// seconds].
65 ///
66 /// Can be used to implement [`Time#sec`].
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// # use spinoso_time::tzrs::{Time, TimeError};
72 /// # fn example() -> Result<(), TimeError> {
73 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
74 /// let second_of_minute = now.second();
75 /// assert_eq!(second_of_minute, 56);
76 /// # Ok(())
77 /// # }
78 /// # example().unwrap()
79 /// ```
80 ///
81 /// [`Time#sec`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-sec
82 /// [leap seconds]: https://en.wikipedia.org/wiki/Leap_second
83 #[inline]
84 #[must_use]
85 pub fn second(&self) -> u8 {
86 self.inner.second()
87 }
88
89 /// Returns the minute of the hour `0..=59` for _time_.
90 ///
91 /// Can be used to implement [`Time#min`].
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// # use spinoso_time::tzrs::{Time, TimeError};
97 /// # fn example() -> Result<(), TimeError> {
98 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
99 /// let minute_of_hour = now.minute();
100 /// assert_eq!(minute_of_hour, 34);
101 /// # Ok(())
102 /// # }
103 /// # example().unwrap()
104 /// ```
105 ///
106 /// [`Time#min`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-min
107 #[inline]
108 #[must_use]
109 pub fn minute(&self) -> u8 {
110 self.inner.minute()
111 }
112
113 /// Returns the hour of the day `0..=23` for _time_.
114 ///
115 /// Can be used to implement [`Time#hour`].
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// # use spinoso_time::tzrs::{Time, TimeError};
121 /// # fn example() -> Result<(), TimeError> {
122 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
123 /// let hour_of_day = now.hour();
124 /// assert_eq!(hour_of_day, 12);
125 /// # Ok(())
126 /// # }
127 /// # example().unwrap()
128 /// ```
129 ///
130 /// [`Time#hour`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-hour
131 #[inline]
132 #[must_use]
133 pub fn hour(&self) -> u8 {
134 self.inner.hour()
135 }
136
137 /// Returns the day of the month `1..=n` for _time_.
138 ///
139 /// Can be used to implement [`Time#day`] and [`Time#mday`].
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// # use spinoso_time::tzrs::{Time, TimeError};
145 /// # fn example() -> Result<(), TimeError> {
146 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
147 /// let day_of_month = now.day();
148 /// assert_eq!(day_of_month, 8);
149 /// # Ok(())
150 /// # }
151 /// # example().unwrap()
152 /// ```
153 ///
154 /// [`Time#day`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-day
155 /// [`Time#mday`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-mday
156 #[inline]
157 #[must_use]
158 pub fn day(&self) -> u8 {
159 self.inner.month_day()
160 }
161
162 /// Returns the month of the year `1..=12` for _time_.
163 ///
164 /// Can be used to implement [`Time#mon`] and [`Time#month`].
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// # use spinoso_time::tzrs::{Time, TimeError};
170 /// # fn example() -> Result<(), TimeError> {
171 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
172 /// let month_of_year = now.month();
173 /// assert_eq!(month_of_year, 7);
174 /// # Ok(())
175 /// # }
176 /// # example().unwrap()
177 /// ```
178 ///
179 /// [`Time#mon`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-mon
180 /// [`Time#month`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-mon
181 #[inline]
182 #[must_use]
183 pub fn month(&self) -> u8 {
184 self.inner.month()
185 }
186
187 /// Returns the year for _time_ (including the century).
188 ///
189 /// Can be used to implement [`Time#year`].
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// # use spinoso_time::tzrs::{Time, TimeError};
195 /// # fn example() -> Result<(), TimeError> {
196 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
197 /// assert_eq!(now.year(), 2022);
198 /// # Ok(())
199 /// # }
200 /// # example().unwrap()
201 /// ```
202 ///
203 /// [`Time#year`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-year
204 #[inline]
205 #[must_use]
206 pub fn year(&self) -> i32 {
207 self.inner.year()
208 }
209
210 /// Returns the name of the time zone as a string.
211 ///
212 /// **Note**: For some offset variants, UTC may return an empty string from
213 /// this method due to the [UTC `LocaleTimeType`][tzrs-utc] being constructed
214 /// with [`None`], which is later coerced into an [empty string].
215 ///
216 /// # Examples
217 /// ```
218 /// # use spinoso_time::tzrs::{Time, TimeError};
219 /// # fn example() -> Result<(), TimeError> {
220 /// let now_utc = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
221 /// assert_eq!("UTC", now_utc.time_zone());
222 /// # Ok(())
223 /// # }
224 /// # example().unwrap()
225 /// ```
226 ///
227 /// [tzrs-utc]: https://docs.rs/tz-rs/0.6.10/src/tz/timezone/mod.rs.html#180
228 /// [empty string]: https://docs.rs/tz-rs/0.6.10/src/tz/timezone/mod.rs.html#210
229 #[inline]
230 #[must_use]
231 pub fn time_zone(&self) -> &str {
232 // We can usually get the name from wrapped `DateTime`, however UTC is a
233 // special case which is an empty string, thus the `OffsetType` is safer.
234 //
235 // Note: The offset cannot be relied upon for the timezone name, as it
236 // may contain many options (e.g. CEST/CET)
237 if self.offset.is_utc() {
238 "UTC"
239 } else {
240 self.inner.local_time_type().time_zone_designation()
241 }
242 }
243
244 /// Returns true if the time zone is UTC.
245 ///
246 /// Can be used to implement [`Time#utc?`] and [`Time#gmt?`].
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// # use spinoso_time::tzrs::{Time, TimeError};
252 /// # fn example() -> Result<(), TimeError> {
253 /// let now_utc = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
254 /// assert!(now_utc.is_utc());
255 /// # Ok(())
256 /// # }
257 /// # example().unwrap()
258 /// ```
259 ///
260 /// [`Time#utc?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-utc-3F
261 /// [`Time#gmt?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-gmt-3F
262 #[inline]
263 #[must_use]
264 pub fn is_utc(&self) -> bool {
265 self.offset.is_utc()
266 }
267
268 /// Returns the offset in seconds between the timezone of _time_ and UTC.
269 ///
270 /// Can be used to implement [`Time#utc_offset`] and [`Time#gmt_offset`].
271 ///
272 /// # Examples
273 ///
274 /// ```
275 /// # use spinoso_time::tzrs::{Time, TimeError};
276 /// # fn example() -> Result<(), TimeError> {
277 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
278 /// assert_eq!(now.utc_offset(), 0);
279 /// # Ok(())
280 /// # }
281 /// # example().unwrap()
282 /// ```
283 ///
284 /// [`Time#utc_offset`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-utc_offset
285 /// [`Time#gmt_offset`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-gmt_offset
286 #[inline]
287 #[must_use]
288 pub fn utc_offset(&self) -> i32 {
289 self.inner.local_time_type().ut_offset()
290 }
291
292 /// Returns `true` if _time_ occurs during Daylight Saving Time in its time
293 /// zone.
294 ///
295 /// Can be used to implement [`Time#dst?`] and [`Time#isdst`].
296 ///
297 /// # Examples
298 ///
299 /// ```
300 /// # use spinoso_time::tzrs::{Time, Offset, TimeError};
301 /// # fn example() -> Result<(), TimeError> {
302 /// use tzdb::time_zone::{europe::AMSTERDAM, pacific::AUCKLAND};
303 /// let now_ams = Time::new(2022, 5, 18, 16, 0, 0, 0, Offset::from(AMSTERDAM))?;
304 /// assert!(now_ams.is_dst());
305 /// let now_auckland = Time::new(2022, 5, 18, 16, 0, 0, 0, Offset::from(AUCKLAND))?;
306 /// assert!(!now_auckland.is_dst());
307 /// # Ok(())
308 /// # }
309 /// # example().unwrap()
310 /// ```
311 ///
312 /// [`Time#dst?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-dst-3F
313 /// [`Time#isdst`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-isdst
314 #[inline]
315 #[must_use]
316 pub fn is_dst(&self) -> bool {
317 self.inner.local_time_type().is_dst()
318 }
319
320 /// Returns an integer representing the day of the week, `0..=6`, with
321 /// `Sunday == 0`.
322 ///
323 /// Can be used to implement [`Time#wday`].
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use spinoso_time::tzrs::{Time, TimeError};
329 /// # fn example() -> Result<(), TimeError> {
330 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
331 /// assert_eq!(now.day_of_week(), 5);
332 /// # Ok(())
333 /// # }
334 /// # example().unwrap()
335 /// ```
336 ///
337 /// [`Time#wday`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-wday
338 #[inline]
339 #[must_use]
340 pub fn day_of_week(&self) -> u8 {
341 self.inner.week_day()
342 }
343
344 /// Returns `true` if _time_ represents Sunday.
345 ///
346 /// Can be used to implement [`Time#sunday?`].
347 ///
348 /// # Examples
349 ///
350 /// ```
351 /// # use spinoso_time::tzrs::{Time, TimeError};
352 /// # fn example() -> Result<(), TimeError> {
353 /// use spinoso_time::tzrs::Time;
354 /// let now = Time::utc(1970, 1, 4, 0, 0, 0, 0)?;
355 /// assert!(now.is_sunday());
356 /// # Ok(())
357 /// # }
358 /// # example().unwrap()
359 /// ```
360 ///
361 /// [`Time#sunday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-sunday-3F
362 #[inline]
363 #[must_use]
364 pub fn is_sunday(&self) -> bool {
365 self.day_of_week() == 0
366 }
367
368 /// Returns `true` if _time_ represents Monday.
369 ///
370 /// Can be used to implement [`Time#monday?`].
371 ///
372 /// # Examples
373 ///
374 /// ```
375 /// # use spinoso_time::tzrs::{Time, TimeError};
376 /// # fn example() -> Result<(), TimeError> {
377 /// use spinoso_time::tzrs::Time;
378 /// let now = Time::utc(1970, 1, 5, 0, 0, 0, 0)?;
379 /// assert!(now.is_monday());
380 /// # Ok(())
381 /// # }
382 /// # example().unwrap()
383 /// ```
384 ///
385 /// [`Time#monday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-sunday-3F
386 #[inline]
387 #[must_use]
388 pub fn is_monday(&self) -> bool {
389 self.day_of_week() == 1
390 }
391
392 /// Returns `true` if _time_ represents Tuesday.
393 ///
394 /// Can be used to implement [`Time#tuesday?`].
395 ///
396 /// # Examples
397 ///
398 /// ```
399 /// # use spinoso_time::tzrs::{Time, TimeError};
400 /// # fn example() -> Result<(), TimeError> {
401 /// use spinoso_time::tzrs::Time;
402 /// let now = Time::utc(1970, 1, 6, 0, 0, 0, 0)?;
403 /// assert!(now.is_tuesday());
404 /// # Ok(())
405 /// # }
406 /// # example().unwrap()
407 /// ```
408 ///
409 /// [`Time#tuesday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-sunday-3F
410 #[inline]
411 #[must_use]
412 pub fn is_tuesday(&self) -> bool {
413 self.day_of_week() == 2
414 }
415
416 /// Returns `true` if _time_ represents Wednesday.
417 ///
418 /// Can be used to implement [`Time#wednesday?`].
419 ///
420 /// # Examples
421 ///
422 /// ```
423 /// # use spinoso_time::tzrs::{Time, TimeError};
424 /// # fn example() -> Result<(), TimeError> {
425 /// use spinoso_time::tzrs::Time;
426 /// let now = Time::utc(1970, 1, 7, 0, 0, 0, 0)?;
427 /// assert!(now.is_wednesday());
428 /// # Ok(())
429 /// # }
430 /// # example().unwrap()
431 /// ```
432 ///
433 /// [`Time#wednesday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-wednesday-3F
434 #[inline]
435 #[must_use]
436 pub fn is_wednesday(&self) -> bool {
437 self.day_of_week() == 3
438 }
439
440 /// Returns `true` if _time_ represents Thursday.
441 ///
442 /// Can be used to implement [`Time#thursday?`].
443 ///
444 /// # Examples
445 ///
446 /// ```
447 /// # use spinoso_time::tzrs::{Time, TimeError};
448 /// # fn example() -> Result<(), TimeError> {
449 /// use spinoso_time::tzrs::Time;
450 /// let now = Time::utc(1970, 1, 1, 0, 0, 0, 0)?;
451 /// assert!(now.is_thursday());
452 /// # Ok(())
453 /// # }
454 /// # example().unwrap()
455 /// ```
456 ///
457 /// [`Time#thursday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-thursday-3F
458 #[inline]
459 #[must_use]
460 pub fn is_thursday(&self) -> bool {
461 self.day_of_week() == 4
462 }
463
464 /// Returns `true` if _time_ represents Friday.
465 ///
466 /// Can be used to implement [`Time#friday?`].
467 ///
468 /// # Examples
469 ///
470 /// ```
471 /// # use spinoso_time::tzrs::{Time, TimeError};
472 /// # fn example() -> Result<(), TimeError> {
473 /// let now = Time::utc(1970, 1, 2, 0, 0, 0, 0)?;
474 /// assert!(now.is_friday());
475 /// # Ok(())
476 /// # }
477 /// # example().unwrap()
478 /// ```
479 ///
480 /// [`Time#friday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-friday-3F
481 #[inline]
482 #[must_use]
483 pub fn is_friday(&self) -> bool {
484 self.day_of_week() == 5
485 }
486
487 /// Returns `true` if _time_ represents Saturday.
488 ///
489 /// Can be used to implement [`Time#saturday?`].
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// # use spinoso_time::tzrs::{Time, TimeError};
495 /// # fn example() -> Result<(), TimeError> {
496 /// use spinoso_time::tzrs::Time;
497 /// let now = Time::utc(1970, 1, 3, 0, 0, 0, 0)?;
498 /// assert!(now.is_saturday());
499 /// # Ok(())
500 /// # }
501 /// # example().unwrap()
502 /// ```
503 ///
504 /// [`Time#saturday?`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-saturday-3F
505 #[inline]
506 #[must_use]
507 pub fn is_saturday(&self) -> bool {
508 self.day_of_week() == 6
509 }
510
511 /// Returns an integer representing the day of the year, `1..=366`.
512 ///
513 /// Can be used to implement [`Time#yday`].
514 ///
515 /// # Examples
516 ///
517 /// ```
518 /// # use spinoso_time::tzrs::{Time, TimeError};
519 /// # fn example() -> Result<(), TimeError> {
520 /// let now = Time::utc(2022, 7, 8, 12, 34, 56, 0)?;
521 /// assert_eq!(now.day_of_year(), 189);
522 /// # Ok(())
523 /// # }
524 /// # example().unwrap()
525 /// ```
526 ///
527 /// [`Time#yday`]: https://ruby-doc.org/core-3.1.2/Time.html#method-i-yday
528 #[inline]
529 #[must_use]
530 pub fn day_of_year(&self) -> u16 {
531 self.inner.year_day() + 1
532 }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538
539 #[test]
540 fn all_parts() {
541 let dt = Time::utc(2022, 7, 8, 12, 34, 56, 1910).unwrap();
542 assert_eq!(2022, dt.year());
543 assert_eq!(7, dt.month());
544 assert_eq!(8, dt.day());
545 assert_eq!(12, dt.hour());
546 assert_eq!(34, dt.minute());
547 assert_eq!(56, dt.second());
548 assert_eq!(1910, dt.nanoseconds());
549 assert_eq!(1, dt.microseconds());
550 assert_eq!("UTC", dt.time_zone());
551 assert!(dt.is_utc());
552 }
553
554 #[test]
555 fn yday() {
556 // ```
557 // [3.1.2] > Time.new(2022, 7, 8, 12, 34, 56, 0).yday
558 // => 189
559 // [3.1.2] > Time.new(2022, 1, 1, 12, 34, 56, 0).yday
560 // => 1
561 // [3.1.2] > Time.new(2022, 12, 31, 12, 34, 56, 0).yday
562 // => 365
563 // [3.1.2] > Time.new(2020, 12, 31, 12, 34, 56, 0).yday
564 // => 366
565 // ```
566 let time = Time::utc(2022, 7, 8, 12, 34, 56, 0).unwrap();
567 assert_eq!(time.day_of_year(), 189);
568
569 let start_2022 = Time::utc(2022, 1, 1, 12, 34, 56, 0).unwrap();
570 assert_eq!(start_2022.day_of_year(), 1);
571
572 let end_2022 = Time::utc(2022, 12, 31, 12, 34, 56, 0).unwrap();
573 assert_eq!(end_2022.day_of_year(), 365);
574
575 let end_leap_year = Time::utc(2020, 12, 31, 12, 34, 56, 0).unwrap();
576 assert_eq!(end_leap_year.day_of_year(), 366);
577 }
578}