/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.55/src/util.rs
Line | Count | Source |
1 | | //! Utility functions, including updating time zone information. |
2 | | |
3 | | use core::num::NonZero; |
4 | | |
5 | | pub(crate) use time_core::util::{days_in_month_leap, range_validated}; |
6 | | pub use time_core::util::{days_in_year, is_leap_year, weeks_in_year}; |
7 | | |
8 | | use crate::Month; |
9 | | |
10 | | /// Which direction arithmetic overflow occurred in. |
11 | | #[derive(Debug, Clone, Copy)] |
12 | | pub(crate) enum Overflow { |
13 | | /// The overflow was positive (i.e. towards positive infinity). |
14 | | Positive, |
15 | | /// The overflow was negative (i.e. towards negative infinity). |
16 | | Negative, |
17 | | } |
18 | | |
19 | | /// Whether to adjust the date, and in which direction. Useful when implementing arithmetic. |
20 | | pub(crate) enum DateAdjustment { |
21 | | /// The previous day should be used. |
22 | | Previous, |
23 | | /// The next day should be used. |
24 | | Next, |
25 | | /// The date should be used as-is. |
26 | | None, |
27 | | } |
28 | | |
29 | | /// Get the number of days in the month of a given year. |
30 | | /// |
31 | | /// ```rust |
32 | | /// # use time::{Month, util}; |
33 | | /// assert_eq!(util::days_in_month(Month::February, 2020), 29); |
34 | | /// ``` |
35 | | #[inline] |
36 | 6.33k | pub const fn days_in_month(month: Month, year: i32) -> u8 { |
37 | 6.33k | time_core::util::days_in_month(month as u8, year) |
38 | 6.33k | } |
39 | | |
40 | | /// Get the number of days in the month of a given year. |
41 | | /// |
42 | | /// ```rust |
43 | | /// # #![expect(deprecated)] |
44 | | /// # use time::{Month, util}; |
45 | | /// assert_eq!(util::days_in_year_month(2020, Month::February), 29); |
46 | | /// ``` |
47 | | #[deprecated( |
48 | | since = "0.3.37", |
49 | | note = "use `days_in_month` or `Month::length` instead" |
50 | | )] |
51 | | #[inline] |
52 | 0 | pub const fn days_in_year_month(year: i32, month: Month) -> u8 { |
53 | 0 | days_in_month(month, year) |
54 | 0 | } |
55 | | |
56 | | /// Given whether a year is a leap year and the ordinal day, return the month and day of the month. |
57 | | #[inline] |
58 | 0 | pub(crate) const fn leap_ordinal_to_month_day(leap: bool, ordinal: u16) -> (Month, u8) { |
59 | 0 | let ordinal = ordinal as u32; |
60 | 0 | let jan_feb_len = 59 + leap as u32; |
61 | | |
62 | 0 | let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len { |
63 | 0 | (0, 0) |
64 | | } else { |
65 | 0 | (2, jan_feb_len) |
66 | | }; |
67 | | |
68 | 0 | let ordinal = ordinal - ordinal_adj; |
69 | 0 | let month = (ordinal * 268 + 8031) >> 13; |
70 | 0 | let days_in_preceding_months = (month * 3917 - 3866) >> 7; |
71 | 0 | let day = ordinal - days_in_preceding_months; |
72 | 0 | let month = month + month_adj; |
73 | | |
74 | | ( |
75 | | // Safety: `month` is guaranteed to be between 1 and 12 inclusive. |
76 | | unsafe { |
77 | 0 | match Month::from_number(NonZero::new_unchecked(month as u8)) { |
78 | 0 | Ok(month) => month, |
79 | 0 | Err(_) => core::hint::unreachable_unchecked(), |
80 | | } |
81 | | }, |
82 | 0 | day as u8, |
83 | | ) |
84 | 0 | } |
85 | | |
86 | | /// Update time zone information from the system. |
87 | | /// |
88 | | /// For a version of this function that is guaranteed to be sound, see [`refresh_tz`]. |
89 | | /// |
90 | | /// # Safety |
91 | | /// |
92 | | /// This is a system call with specific requirements. The following is from POSIX's description of |
93 | | /// `tzset`: |
94 | | /// |
95 | | /// > If a thread accesses `tzname`, `daylight`, or `timezone` directly while another thread is in a |
96 | | /// > call to `tzset()`, or to any function that is required or allowed to set timezone information |
97 | | /// > as if by calling `tzset()`, the behavior is undefined. |
98 | | /// |
99 | | /// Effectively, this translates to the requirement that at least one of the following must be true: |
100 | | /// |
101 | | /// - The operating system provides a thread-safe environment. |
102 | | /// - The process is single-threaded. |
103 | | /// - The process is multi-threaded **and** no other thread is mutating the environment in any way |
104 | | /// at the same time a call to a method that obtains the local UTC offset. This includes adding, |
105 | | /// removing, or modifying an environment variable. |
106 | | /// |
107 | | /// ## Soundness is global |
108 | | /// |
109 | | /// You must not only verify this safety conditions for your code, but for **all** code that will be |
110 | | /// included in the final binary. Notably, it applies to both direct and transitive dependencies and |
111 | | /// to both Rust and non-Rust code. **For this reason it is not possible for a library to soundly |
112 | | /// call this method.** |
113 | | /// |
114 | | /// ## Forward compatibility |
115 | | /// |
116 | | /// This currently only does anything on Unix-like systems. On other systems, it is a no-op. This |
117 | | /// may change in the future if necessary, expanding the safety requirements. It is expected that, |
118 | | /// at a minimum, calling this method when the process is single-threaded will remain sound. |
119 | | #[cfg(feature = "local-offset")] |
120 | | #[inline] |
121 | | pub unsafe fn refresh_tz_unchecked() { |
122 | | // Safety: The caller must uphold the safety requirements. |
123 | | unsafe { crate::sys::refresh_tz_unchecked() }; |
124 | | } |
125 | | |
126 | | /// Attempt to update time zone information from the system. |
127 | | /// |
128 | | /// Returns `None` if the call is not known to be sound. |
129 | | #[cfg(feature = "local-offset")] |
130 | | #[inline] |
131 | | pub fn refresh_tz() -> Option<()> { |
132 | | crate::sys::refresh_tz() |
133 | | } |
134 | | |
135 | | #[doc(hidden)] |
136 | | #[cfg(feature = "local-offset")] |
137 | | #[expect( |
138 | | clippy::missing_const_for_fn, |
139 | | reason = "no longer used; original implementation was not const" |
140 | | )] |
141 | | #[deprecated(since = "0.3.37", note = "no longer needed; TZ is refreshed manually")] |
142 | | pub mod local_offset { |
143 | | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
144 | | pub enum Soundness { |
145 | | Sound, |
146 | | Unsound, |
147 | | } |
148 | | |
149 | | #[inline] |
150 | | pub unsafe fn set_soundness(_: Soundness) {} |
151 | | |
152 | | #[inline] |
153 | | pub fn get_soundness() -> Soundness { |
154 | | Soundness::Sound |
155 | | } |
156 | | } |