1//! Utility functions, including updating time zone information.
23use core::num::NonZero;
45pub(crate) use time_core::util::{days_in_month_leap, range_validated};
6pub use time_core::util::{days_in_year, is_leap_year, weeks_in_year};
78use crate::Month;
910/// Which direction arithmetic overflow occurred in.
11#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Overflow {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Overflow::Positive => "Positive",
Overflow::Negative => "Negative",
})
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Overflow { }
#[automatically_derived]
impl ::core::clone::Clone for Overflow {
#[inline]
fn clone(&self) -> Overflow { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Overflow { }Copy)]
12pub(crate) enum Overflow {
13/// The overflow was positive (i.e. towards positive infinity).
14Positive,
15/// The overflow was negative (i.e. towards negative infinity).
16Negative,
17}
1819/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
20pub(crate) enum DateAdjustment {
21/// The previous day should be used.
22Previous,
23/// The next day should be used.
24Next,
25/// The date should be used as-is.
26None,
27}
2829/// 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]
36pub const fn days_in_month(month: Month, year: i32) -> u8 {
37 time_core::util::days_in_month(monthas u8, year)
38}
3940/// 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]
52pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
53days_in_month(month, year)
54}
5556/// Given whether a year is a leap year and the ordinal day, return the month and day of the month.
57#[inline]
58pub(crate) const fn leap_ordinal_to_month_day(leap: bool, ordinal: u16) -> (Month, u8) {
59let ordinal = ordinalas u32;
60let jan_feb_len = 59 + leapas u32;
6162let (month_adj, ordinal_adj) = if ordinal <= jan_feb_len {
63 (0, 0)
64 } else {
65 (2, jan_feb_len)
66 };
6768let ordinal = ordinal - ordinal_adj;
69let month = (ordinal * 268 + 8031) >> 13;
70let days_in_preceding_months = (month * 3917 - 3866) >> 7;
71let day = ordinal - days_in_preceding_months;
72let month = month + month_adj;
7374 (
75// Safety: `month` is guaranteed to be between 1 and 12 inclusive.
76unsafe {
77match Month::from_number(NonZero::new_unchecked(monthas u8)) {
78Ok(month) => month,
79Err(_) => core::hint::unreachable_unchecked(),
80 }
81 },
82dayas u8,
83 )
84}
8586/// 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]
121pub unsafe fn refresh_tz_unchecked() {
122// Safety: The caller must uphold the safety requirements.
123unsafe { crate::sys::refresh_tz_unchecked() };
124}
125126/// 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]
131pub fn refresh_tz() -> Option<()> {
132crate::sys::refresh_tz()
133}
134135#[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")]
142pub mod local_offset {
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub enum Soundness {
145 Sound,
146 Unsound,
147 }
148149#[inline]
150pub unsafe fn set_soundness(_: Soundness) {}
151152#[inline]
153pub fn get_soundness() -> Soundness {
154 Soundness::Sound
155 }
156}