time_core/
util.rs

1//! Utility functions.
2
3use crate::hint;
4
5/// Returns if the provided year is a leap year in the proleptic Gregorian calendar. Uses
6/// [astronomical year numbering](https://en.wikipedia.org/wiki/Astronomical_year_numbering).
7///
8/// ```rust
9/// # use time::util::is_leap_year;
10/// assert!(!is_leap_year(1900));
11/// assert!(is_leap_year(2000));
12/// assert!(is_leap_year(2004));
13/// assert!(!is_leap_year(2005));
14/// assert!(!is_leap_year(2100));
15/// ```
16// https://www.benjoffe.com/fast-leap-year
17#[inline]
18pub const fn is_leap_year(year: i32) -> bool {
19    const CEN_MUL: u32 = 42_949_673;
20    const CEN_CUTOFF: u32 = CEN_MUL * 4;
21    const CEN_BIAS: u32 = CEN_MUL / 2 * 100;
22
23    let low = (year as u32).wrapping_add(CEN_BIAS).wrapping_mul(CEN_MUL);
24    let maybe_cen = low < CEN_CUTOFF;
25    year & if maybe_cen { 15 } else { 3 } == 0
26}
27
28/// Get the number of calendar days in a given year.
29///
30/// The returned value will always be either 365 or 366.
31///
32/// ```rust
33/// # use time::util::days_in_year;
34/// assert_eq!(days_in_year(1900), 365);
35/// assert_eq!(days_in_year(2000), 366);
36/// assert_eq!(days_in_year(2004), 366);
37/// assert_eq!(days_in_year(2005), 365);
38/// assert_eq!(days_in_year(2100), 365);
39/// ```
40#[inline]
41pub const fn days_in_year(year: i32) -> u16 {
42    if is_leap_year(year) {
43        366
44    } else {
45        365
46    }
47}
48
49/// Get the number of weeks in the ISO year.
50///
51/// The returned value will always be either 52 or 53.
52///
53/// ```rust
54/// # use time::util::weeks_in_year;
55/// assert_eq!(weeks_in_year(2019), 52);
56/// assert_eq!(weeks_in_year(2020), 53);
57/// ```
58#[inline]
59pub const fn weeks_in_year(year: i32) -> u8 {
60    match year % 400 {
61        -396 | -391 | -385 | -380 | -374 | -368 | -363 | -357 | -352 | -346 | -340 | -335
62        | -329 | -324 | -318 | -312 | -307 | -301 | -295 | -289 | -284 | -278 | -272 | -267
63        | -261 | -256 | -250 | -244 | -239 | -233 | -228 | -222 | -216 | -211 | -205 | -199
64        | -193 | -188 | -182 | -176 | -171 | -165 | -160 | -154 | -148 | -143 | -137 | -132
65        | -126 | -120 | -115 | -109 | -104 | -97 | -92 | -86 | -80 | -75 | -69 | -64 | -58
66        | -52 | -47 | -41 | -36 | -30 | -24 | -19 | -13 | -8 | -2 | 4 | 9 | 15 | 20 | 26 | 32
67        | 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99 | 105 | 111 | 116 | 122
68        | 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178 | 184 | 189 | 195 | 201
69        | 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257 | 263 | 268 | 274 | 280
70        | 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336 | 342 | 348 | 353 | 359
71        | 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
72        _ => 52,
73    }
74}
75
76/// Get the number of days in the month of a given year.
77///
78/// ```rust
79/// # use time_core::util::days_in_month;
80/// assert_eq!(days_in_month(2, 2020), 29);
81/// ```
82///
83/// Note: This function is not exposed by the `time` crate. It is an implementation detail.
84#[inline]
85pub const fn days_in_month(month: u8, year: i32) -> u8 {
86    debug_assert!(month >= 1);
87    debug_assert!(month <= 12);
88
89    if hint::unlikely(month == 2) {
90        if is_leap_year(year) {
91            29
92        } else {
93            28
94        }
95    } else {
96        30 | month ^ (month >> 3)
97    }
98}