100 lines
4.3 KiB
Rust
100 lines
4.3 KiB
Rust
//! Utility functions.
|
|
|
|
pub use time_core::util::{days_in_year, is_leap_year, weeks_in_year};
|
|
|
|
use crate::Month;
|
|
|
|
/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
|
|
pub(crate) enum DateAdjustment {
|
|
/// The previous day should be used.
|
|
Previous,
|
|
/// The next day should be used.
|
|
Next,
|
|
/// The date should be used as-is.
|
|
None,
|
|
}
|
|
|
|
/// Get the number of days in the month of a given year.
|
|
///
|
|
/// ```rust
|
|
/// # use time::{Month, util};
|
|
/// assert_eq!(util::days_in_year_month(2020, Month::February), 29);
|
|
/// ```
|
|
pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
|
|
use Month::*;
|
|
match month {
|
|
January | March | May | July | August | October | December => 31,
|
|
April | June | September | November => 30,
|
|
February if is_leap_year(year) => 29,
|
|
February => 28,
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "local-offset")]
|
|
/// Utility functions relating to the local UTC offset.
|
|
pub mod local_offset {
|
|
use core::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
/// Whether obtaining the local UTC offset is required to be sound.
|
|
static LOCAL_OFFSET_IS_SOUND: AtomicBool = AtomicBool::new(true);
|
|
|
|
/// The soundness of obtaining the local UTC offset.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum Soundness {
|
|
/// Obtaining the local UTC offset is required to be sound. Undefined behavior will never
|
|
/// occur. This is the default.
|
|
Sound,
|
|
/// Obtaining the local UTC offset is allowed to invoke undefined behavior. **Setting this
|
|
/// value is strongly discouraged.** To do so, you must comply with the safety requirements
|
|
/// of [`time::local_offset::set_soundness`](set_soundness).
|
|
Unsound,
|
|
}
|
|
|
|
/// Set whether obtaining the local UTC offset is allowed to invoke undefined behavior. **Use of
|
|
/// this function is heavily discouraged.**
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// If this method is called with [`Soundness::Sound`], the call is always sound. If this method
|
|
/// is called with [`Soundness::Unsound`], the following conditions apply.
|
|
///
|
|
/// - If the operating system provides a thread-safe environment, the call is sound.
|
|
/// - If the process is single-threaded, the call is sound.
|
|
/// - If the process is multi-threaded, no other thread may mutate the environment in any way at
|
|
/// the same time a call to a method that obtains the local UTC offset. This includes adding,
|
|
/// removing, or modifying an environment variable.
|
|
///
|
|
/// The first two conditions are automatically checked by `time`, such that you do not need to
|
|
/// declare your code unsound. Currently, the only known operating systems that does _not_
|
|
/// provide a thread-safe environment are some Unix-like OS's. All other operating systems
|
|
/// should succeed when attempting to obtain the local UTC offset.
|
|
///
|
|
/// Note that you must not only verify this safety condition for your code, but for **all** code
|
|
/// that will be included in the final binary. Notably, it applies to both direct and transitive
|
|
/// dependencies and to both Rust and non-Rust code. **For this reason it is not possible to
|
|
/// soundly pass [`Soundness::Unsound`] to this method if you are writing a library that may
|
|
/// used by others.**
|
|
///
|
|
/// If using this method is absolutely necessary, it is recommended to keep the time between
|
|
/// setting the soundness to [`Soundness::Unsound`] and setting it back to [`Soundness::Sound`]
|
|
/// as short as possible.
|
|
///
|
|
/// The following methods currently obtain the local UTC offset:
|
|
///
|
|
/// - [`OffsetDateTime::now_local`](crate::OffsetDateTime::now_local)
|
|
/// - [`UtcOffset::local_offset_at`](crate::UtcOffset::local_offset_at)
|
|
/// - [`UtcOffset::current_local_offset`](crate::UtcOffset::current_local_offset)
|
|
pub unsafe fn set_soundness(soundness: Soundness) {
|
|
LOCAL_OFFSET_IS_SOUND.store(soundness == Soundness::Sound, Ordering::Release);
|
|
}
|
|
|
|
/// Obtains the soundness of obtaining the local UTC offset. If it is [`Soundness::Unsound`],
|
|
/// it is allowed to invoke undefined behavior when obtaining the local UTC offset.
|
|
pub fn get_soundness() -> Soundness {
|
|
match LOCAL_OFFSET_IS_SOUND.load(Ordering::Acquire) {
|
|
false => Soundness::Unsound,
|
|
true => Soundness::Sound,
|
|
}
|
|
}
|
|
}
|