| 1 | //! The `Month` enum and its associated `impl`s. |
| 2 | |
| 3 | use core::fmt; |
| 4 | use core::num::NonZeroU8; |
| 5 | use core::str::FromStr; |
| 6 | |
| 7 | use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay}; |
| 8 | |
| 9 | use self::Month::*; |
| 10 | use crate::{error, util}; |
| 11 | |
| 12 | /// Months of the year. |
| 13 | #[repr (u8)] |
| 14 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 15 | pub enum Month { |
| 16 | #[allow (missing_docs)] |
| 17 | January = 1, |
| 18 | #[allow (missing_docs)] |
| 19 | February = 2, |
| 20 | #[allow (missing_docs)] |
| 21 | March = 3, |
| 22 | #[allow (missing_docs)] |
| 23 | April = 4, |
| 24 | #[allow (missing_docs)] |
| 25 | May = 5, |
| 26 | #[allow (missing_docs)] |
| 27 | June = 6, |
| 28 | #[allow (missing_docs)] |
| 29 | July = 7, |
| 30 | #[allow (missing_docs)] |
| 31 | August = 8, |
| 32 | #[allow (missing_docs)] |
| 33 | September = 9, |
| 34 | #[allow (missing_docs)] |
| 35 | October = 10, |
| 36 | #[allow (missing_docs)] |
| 37 | November = 11, |
| 38 | #[allow (missing_docs)] |
| 39 | December = 12, |
| 40 | } |
| 41 | |
| 42 | impl Month { |
| 43 | /// Create a `Month` from its numerical value. |
| 44 | pub(crate) const fn from_number(n: NonZeroU8) -> Result<Self, error::ComponentRange> { |
| 45 | match n.get() { |
| 46 | 1 => Ok(January), |
| 47 | 2 => Ok(February), |
| 48 | 3 => Ok(March), |
| 49 | 4 => Ok(April), |
| 50 | 5 => Ok(May), |
| 51 | 6 => Ok(June), |
| 52 | 7 => Ok(July), |
| 53 | 8 => Ok(August), |
| 54 | 9 => Ok(September), |
| 55 | 10 => Ok(October), |
| 56 | 11 => Ok(November), |
| 57 | 12 => Ok(December), |
| 58 | n => Err(error::ComponentRange { |
| 59 | name: "month" , |
| 60 | minimum: 1, |
| 61 | maximum: 12, |
| 62 | value: n as _, |
| 63 | conditional_range: false, |
| 64 | }), |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | /// Get the number of days in the month of a given year. |
| 69 | /// |
| 70 | /// ```rust |
| 71 | /// # use time::Month; |
| 72 | /// assert_eq!(Month::February.length(2020), 29); |
| 73 | /// ``` |
| 74 | pub const fn length(self, year: i32) -> u8 { |
| 75 | match self { |
| 76 | January | March | May | July | August | October | December => 31, |
| 77 | April | June | September | November => 30, |
| 78 | February if util::is_leap_year(year) => 29, |
| 79 | February => 28, |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | /// Get the previous month. |
| 84 | /// |
| 85 | /// ```rust |
| 86 | /// # use time::Month; |
| 87 | /// assert_eq!(Month::January.previous(), Month::December); |
| 88 | /// ``` |
| 89 | pub const fn previous(self) -> Self { |
| 90 | match self { |
| 91 | January => December, |
| 92 | February => January, |
| 93 | March => February, |
| 94 | April => March, |
| 95 | May => April, |
| 96 | June => May, |
| 97 | July => June, |
| 98 | August => July, |
| 99 | September => August, |
| 100 | October => September, |
| 101 | November => October, |
| 102 | December => November, |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /// Get the next month. |
| 107 | /// |
| 108 | /// ```rust |
| 109 | /// # use time::Month; |
| 110 | /// assert_eq!(Month::January.next(), Month::February); |
| 111 | /// ``` |
| 112 | pub const fn next(self) -> Self { |
| 113 | match self { |
| 114 | January => February, |
| 115 | February => March, |
| 116 | March => April, |
| 117 | April => May, |
| 118 | May => June, |
| 119 | June => July, |
| 120 | July => August, |
| 121 | August => September, |
| 122 | September => October, |
| 123 | October => November, |
| 124 | November => December, |
| 125 | December => January, |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /// Get n-th next month. |
| 130 | /// |
| 131 | /// ```rust |
| 132 | /// # use time::Month; |
| 133 | /// assert_eq!(Month::January.nth_next(4), Month::May); |
| 134 | /// assert_eq!(Month::July.nth_next(9), Month::April); |
| 135 | /// ``` |
| 136 | pub const fn nth_next(self, n: u8) -> Self { |
| 137 | match (self as u8 - 1 + n % 12) % 12 { |
| 138 | 0 => January, |
| 139 | 1 => February, |
| 140 | 2 => March, |
| 141 | 3 => April, |
| 142 | 4 => May, |
| 143 | 5 => June, |
| 144 | 6 => July, |
| 145 | 7 => August, |
| 146 | 8 => September, |
| 147 | 9 => October, |
| 148 | 10 => November, |
| 149 | val => { |
| 150 | debug_assert!(val == 11); |
| 151 | December |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /// Get n-th previous month. |
| 157 | /// |
| 158 | /// ```rust |
| 159 | /// # use time::Month; |
| 160 | /// assert_eq!(Month::January.nth_prev(4), Month::September); |
| 161 | /// assert_eq!(Month::July.nth_prev(9), Month::October); |
| 162 | /// ``` |
| 163 | pub const fn nth_prev(self, n: u8) -> Self { |
| 164 | match self as i8 - 1 - (n % 12) as i8 { |
| 165 | 1 | -11 => February, |
| 166 | 2 | -10 => March, |
| 167 | 3 | -9 => April, |
| 168 | 4 | -8 => May, |
| 169 | 5 | -7 => June, |
| 170 | 6 | -6 => July, |
| 171 | 7 | -5 => August, |
| 172 | 8 | -4 => September, |
| 173 | 9 | -3 => October, |
| 174 | 10 | -2 => November, |
| 175 | 11 | -1 => December, |
| 176 | val => { |
| 177 | debug_assert!(val == 0); |
| 178 | January |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | mod private { |
| 185 | #[non_exhaustive ] |
| 186 | #[derive (Debug, Clone, Copy)] |
| 187 | pub struct MonthMetadata; |
| 188 | } |
| 189 | use private::MonthMetadata; |
| 190 | |
| 191 | impl SmartDisplay for Month { |
| 192 | type Metadata = MonthMetadata; |
| 193 | |
| 194 | fn metadata(&self, _: FormatterOptions) -> Metadata<Self> { |
| 195 | match self { |
| 196 | January => Metadata::new(7, self, MonthMetadata), |
| 197 | February => Metadata::new(8, self, MonthMetadata), |
| 198 | March => Metadata::new(5, self, MonthMetadata), |
| 199 | April => Metadata::new(5, self, MonthMetadata), |
| 200 | May => Metadata::new(3, self, MonthMetadata), |
| 201 | June => Metadata::new(4, self, MonthMetadata), |
| 202 | July => Metadata::new(4, self, MonthMetadata), |
| 203 | August => Metadata::new(6, self, MonthMetadata), |
| 204 | September => Metadata::new(9, self, MonthMetadata), |
| 205 | October => Metadata::new(7, self, MonthMetadata), |
| 206 | November => Metadata::new(8, self, MonthMetadata), |
| 207 | December => Metadata::new(8, self, MonthMetadata), |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 212 | f.pad(match self { |
| 213 | January => "January" , |
| 214 | February => "February" , |
| 215 | March => "March" , |
| 216 | April => "April" , |
| 217 | May => "May" , |
| 218 | June => "June" , |
| 219 | July => "July" , |
| 220 | August => "August" , |
| 221 | September => "September" , |
| 222 | October => "October" , |
| 223 | November => "November" , |
| 224 | December => "December" , |
| 225 | }) |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | impl fmt::Display for Month { |
| 230 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 231 | SmartDisplay::fmt(self, f) |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | impl FromStr for Month { |
| 236 | type Err = error::InvalidVariant; |
| 237 | |
| 238 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 239 | match s { |
| 240 | "January" => Ok(January), |
| 241 | "February" => Ok(February), |
| 242 | "March" => Ok(March), |
| 243 | "April" => Ok(April), |
| 244 | "May" => Ok(May), |
| 245 | "June" => Ok(June), |
| 246 | "July" => Ok(July), |
| 247 | "August" => Ok(August), |
| 248 | "September" => Ok(September), |
| 249 | "October" => Ok(October), |
| 250 | "November" => Ok(November), |
| 251 | "December" => Ok(December), |
| 252 | _ => Err(error::InvalidVariant), |
| 253 | } |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | impl From<Month> for u8 { |
| 258 | fn from(month: Month) -> Self { |
| 259 | month as _ |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | impl TryFrom<u8> for Month { |
| 264 | type Error = error::ComponentRange; |
| 265 | |
| 266 | fn try_from(value: u8) -> Result<Self, Self::Error> { |
| 267 | match NonZeroU8::new(value) { |
| 268 | Some(value: NonZero) => Self::from_number(value), |
| 269 | None => Err(error::ComponentRange { |
| 270 | name: "month" , |
| 271 | minimum: 1, |
| 272 | maximum: 12, |
| 273 | value: 0, |
| 274 | conditional_range: false, |
| 275 | }), |
| 276 | } |
| 277 | } |
| 278 | } |
| 279 | |