| 1 | //! Utility functions, including updating time zone information. |
| 2 | |
| 3 | pub use time_core::util::{days_in_year, is_leap_year, weeks_in_year}; |
| 4 | |
| 5 | use crate::Month; |
| 6 | |
| 7 | /// Whether to adjust the date, and in which direction. Useful when implementing arithmetic. |
| 8 | pub(crate) enum DateAdjustment { |
| 9 | /// The previous day should be used. |
| 10 | Previous, |
| 11 | /// The next day should be used. |
| 12 | Next, |
| 13 | /// The date should be used as-is. |
| 14 | None, |
| 15 | } |
| 16 | |
| 17 | /// Get the number of days in the month of a given year. |
| 18 | /// |
| 19 | /// ```rust |
| 20 | /// # use time::{Month, util}; |
| 21 | /// assert_eq!(util::days_in_month(Month::February, 2020), 29); |
| 22 | /// ``` |
| 23 | pub const fn days_in_month(month: Month, year: i32) -> u8 { |
| 24 | month.length(year) |
| 25 | } |
| 26 | |
| 27 | /// Get the number of days in the month of a given year. |
| 28 | /// |
| 29 | /// ```rust |
| 30 | /// # #![allow (deprecated)] |
| 31 | /// # use time::{Month, util}; |
| 32 | /// assert_eq!(util::days_in_year_month(2020, Month::February), 29); |
| 33 | /// ``` |
| 34 | #[deprecated ( |
| 35 | since = "0.3.37" , |
| 36 | note = "use `days_in_month` or `Month::length` instead" |
| 37 | )] |
| 38 | pub const fn days_in_year_month(year: i32, month: Month) -> u8 { |
| 39 | month.length(year) |
| 40 | } |
| 41 | |
| 42 | /// Update time zone information from the system. |
| 43 | /// |
| 44 | /// For a version of this function that is guaranteed to be sound, see [`refresh_tz`]. |
| 45 | /// |
| 46 | /// # Safety |
| 47 | /// |
| 48 | /// This is a system call with specific requirements. The following is from POSIX's description of |
| 49 | /// `tzset`: |
| 50 | /// |
| 51 | /// > If a thread accesses `tzname`, `daylight`, or `timezone` directly while another thread is in a |
| 52 | /// > call to `tzset()`, or to any function that is required or allowed to set timezone information |
| 53 | /// > as if by calling `tzset()`, the behavior is undefined. |
| 54 | /// |
| 55 | /// Effectively, this translates to the requirement that at least one of the following must be true: |
| 56 | /// |
| 57 | /// - The operating system provides a thread-safe environment. |
| 58 | /// - The process is single-threaded. |
| 59 | /// - The process is multi-threaded **and** no other thread is mutating the environment in any way |
| 60 | /// at the same time a call to a method that obtains the local UTC offset. This includes adding, |
| 61 | /// removing, or modifying an environment variable. |
| 62 | /// |
| 63 | /// ## Soundness is global |
| 64 | /// |
| 65 | /// You must not only verify this safety conditions for your code, but for **all** code that will be |
| 66 | /// included in the final binary. Notably, it applies to both direct and transitive dependencies and |
| 67 | /// to both Rust and non-Rust code. **For this reason it is not possible for a library to soundly |
| 68 | /// call this method.** |
| 69 | /// |
| 70 | /// ## Forward compatibility |
| 71 | /// |
| 72 | /// This currently only does anything on Unix-like systems. On other systems, it is a no-op. This |
| 73 | /// may change in the future if necessary, expanding the safety requirements. It is expected that, |
| 74 | /// at a minimum, calling this method when the process is single-threaded will remain sound. |
| 75 | #[cfg (feature = "local-offset" )] |
| 76 | pub unsafe fn refresh_tz_unchecked() { |
| 77 | // Safety: The caller must uphold the safety requirements. |
| 78 | unsafe { crate::sys::refresh_tz_unchecked() }; |
| 79 | } |
| 80 | |
| 81 | /// Attempt to update time zone information from the system. |
| 82 | /// |
| 83 | /// Returns `None` if the call is not known to be sound. |
| 84 | #[cfg (feature = "local-offset" )] |
| 85 | pub fn refresh_tz() -> Option<()> { |
| 86 | crate::sys::refresh_tz() |
| 87 | } |
| 88 | |
| 89 | #[doc (hidden)] |
| 90 | #[cfg (feature = "local-offset" )] |
| 91 | #[allow (clippy::missing_const_for_fn)] |
| 92 | #[deprecated (since = "0.3.37" , note = "no longer needed; TZ is refreshed manually" )] |
| 93 | pub mod local_offset { |
| 94 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 95 | pub enum Soundness { |
| 96 | Sound, |
| 97 | Unsound, |
| 98 | } |
| 99 | |
| 100 | pub unsafe fn set_soundness(_: Soundness) {} |
| 101 | |
| 102 | pub fn get_soundness() -> Soundness { |
| 103 | Soundness::Sound |
| 104 | } |
| 105 | } |
| 106 | |