1use core::fmt;
2
3#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
4use rkyv::{Archive, Deserialize, Serialize};
5
6use crate::OutOfRange;
7
8#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord)]
32#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
33#[cfg_attr(
34 any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
35 derive(Archive, Deserialize, Serialize),
36 archive(compare(PartialEq, PartialOrd)),
37 archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
38)]
39#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
40#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(arbitrary::Arbitrary))]
41pub enum Month {
42 January = 0,
44 February = 1,
46 March = 2,
48 April = 3,
50 May = 4,
52 June = 5,
54 July = 6,
56 August = 7,
58 September = 8,
60 October = 9,
62 November = 10,
64 December = 11,
66}
67
68impl Month {
69 #[inline]
75 #[must_use]
76 pub const fn succ(&self) -> Month {
77 match *self {
78 Month::January => Month::February,
79 Month::February => Month::March,
80 Month::March => Month::April,
81 Month::April => Month::May,
82 Month::May => Month::June,
83 Month::June => Month::July,
84 Month::July => Month::August,
85 Month::August => Month::September,
86 Month::September => Month::October,
87 Month::October => Month::November,
88 Month::November => Month::December,
89 Month::December => Month::January,
90 }
91 }
92
93 #[inline]
99 #[must_use]
100 pub const fn pred(&self) -> Month {
101 match *self {
102 Month::January => Month::December,
103 Month::February => Month::January,
104 Month::March => Month::February,
105 Month::April => Month::March,
106 Month::May => Month::April,
107 Month::June => Month::May,
108 Month::July => Month::June,
109 Month::August => Month::July,
110 Month::September => Month::August,
111 Month::October => Month::September,
112 Month::November => Month::October,
113 Month::December => Month::November,
114 }
115 }
116
117 #[inline]
123 #[must_use]
124 pub const fn number_from_month(&self) -> u32 {
125 match *self {
126 Month::January => 1,
127 Month::February => 2,
128 Month::March => 3,
129 Month::April => 4,
130 Month::May => 5,
131 Month::June => 6,
132 Month::July => 7,
133 Month::August => 8,
134 Month::September => 9,
135 Month::October => 10,
136 Month::November => 11,
137 Month::December => 12,
138 }
139 }
140
141 #[must_use]
149 pub const fn name(&self) -> &'static str {
150 match *self {
151 Month::January => "January",
152 Month::February => "February",
153 Month::March => "March",
154 Month::April => "April",
155 Month::May => "May",
156 Month::June => "June",
157 Month::July => "July",
158 Month::August => "August",
159 Month::September => "September",
160 Month::October => "October",
161 Month::November => "November",
162 Month::December => "December",
163 }
164 }
165}
166
167impl TryFrom<u8> for Month {
168 type Error = OutOfRange;
169
170 fn try_from(value: u8) -> Result<Self, Self::Error> {
171 match value {
172 1 => Ok(Month::January),
173 2 => Ok(Month::February),
174 3 => Ok(Month::March),
175 4 => Ok(Month::April),
176 5 => Ok(Month::May),
177 6 => Ok(Month::June),
178 7 => Ok(Month::July),
179 8 => Ok(Month::August),
180 9 => Ok(Month::September),
181 10 => Ok(Month::October),
182 11 => Ok(Month::November),
183 12 => Ok(Month::December),
184 _ => Err(OutOfRange::new()),
185 }
186 }
187}
188
189impl num_traits::FromPrimitive for Month {
190 #[inline]
197 fn from_u64(n: u64) -> Option<Month> {
198 Self::from_u32(n as u32)
199 }
200
201 #[inline]
202 fn from_i64(n: i64) -> Option<Month> {
203 Self::from_u32(n as u32)
204 }
205
206 #[inline]
207 fn from_u32(n: u32) -> Option<Month> {
208 match n {
209 1 => Some(Month::January),
210 2 => Some(Month::February),
211 3 => Some(Month::March),
212 4 => Some(Month::April),
213 5 => Some(Month::May),
214 6 => Some(Month::June),
215 7 => Some(Month::July),
216 8 => Some(Month::August),
217 9 => Some(Month::September),
218 10 => Some(Month::October),
219 11 => Some(Month::November),
220 12 => Some(Month::December),
221 _ => None,
222 }
223 }
224}
225
226#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
228#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(arbitrary::Arbitrary))]
229pub struct Months(pub(crate) u32);
230
231impl Months {
232 pub const fn new(num: u32) -> Self {
234 Self(num)
235 }
236
237 #[inline]
239 pub const fn as_u32(&self) -> u32 {
240 self.0
241 }
242}
243
244#[derive(Clone, PartialEq, Eq)]
246pub struct ParseMonthError {
247 pub(crate) _dummy: (),
248}
249
250#[cfg(feature = "std")]
251impl std::error::Error for ParseMonthError {}
252
253impl fmt::Display for ParseMonthError {
254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255 write!(f, "ParseMonthError {{ .. }}")
256 }
257}
258
259impl fmt::Debug for ParseMonthError {
260 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
261 write!(f, "ParseMonthError {{ .. }}")
262 }
263}
264
265#[cfg(feature = "serde")]
266mod month_serde {
267 use super::Month;
268 use serde::{de, ser};
269
270 use core::fmt;
271
272 impl ser::Serialize for Month {
273 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
274 where
275 S: ser::Serializer,
276 {
277 serializer.collect_str(self.name())
278 }
279 }
280
281 struct MonthVisitor;
282
283 impl<'de> de::Visitor<'de> for MonthVisitor {
284 type Value = Month;
285
286 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
287 f.write_str("Month")
288 }
289
290 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
291 where
292 E: de::Error,
293 {
294 value.parse().map_err(|_| E::custom("short (3-letter) or full month names expected"))
295 }
296 }
297
298 impl<'de> de::Deserialize<'de> for Month {
299 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
300 where
301 D: de::Deserializer<'de>,
302 {
303 deserializer.deserialize_str(MonthVisitor)
304 }
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use super::Month;
311 use crate::{Datelike, Months, OutOfRange, TimeZone, Utc};
312
313 #[test]
314 fn test_month_enum_try_from() {
315 assert_eq!(Month::try_from(1), Ok(Month::January));
316 assert_eq!(Month::try_from(2), Ok(Month::February));
317 assert_eq!(Month::try_from(12), Ok(Month::December));
318 assert_eq!(Month::try_from(13), Err(OutOfRange::new()));
319
320 let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
321 assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October));
322
323 let month = Month::January;
324 let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap();
325 assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
326 }
327
328 #[test]
329 fn test_month_enum_primitive_parse() {
330 use num_traits::FromPrimitive;
331
332 let jan_opt = Month::from_u32(1);
333 let feb_opt = Month::from_u64(2);
334 let dec_opt = Month::from_i64(12);
335 let no_month = Month::from_u32(13);
336 assert_eq!(jan_opt, Some(Month::January));
337 assert_eq!(feb_opt, Some(Month::February));
338 assert_eq!(dec_opt, Some(Month::December));
339 assert_eq!(no_month, None);
340
341 let date = Utc.with_ymd_and_hms(2019, 10, 28, 9, 10, 11).unwrap();
342 assert_eq!(Month::from_u32(date.month()), Some(Month::October));
343
344 let month = Month::January;
345 let dt = Utc.with_ymd_and_hms(2019, month.number_from_month(), 28, 9, 10, 11).unwrap();
346 assert_eq!((dt.year(), dt.month(), dt.day()), (2019, 1, 28));
347 }
348
349 #[test]
350 fn test_month_enum_succ_pred() {
351 assert_eq!(Month::January.succ(), Month::February);
352 assert_eq!(Month::December.succ(), Month::January);
353 assert_eq!(Month::January.pred(), Month::December);
354 assert_eq!(Month::February.pred(), Month::January);
355 }
356
357 #[test]
358 fn test_month_partial_ord() {
359 assert!(Month::January <= Month::January);
360 assert!(Month::January < Month::February);
361 assert!(Month::January < Month::December);
362 assert!(Month::July >= Month::May);
363 assert!(Month::September > Month::March);
364 }
365
366 #[test]
367 fn test_months_as_u32() {
368 assert_eq!(Months::new(0).as_u32(), 0);
369 assert_eq!(Months::new(1).as_u32(), 1);
370 assert_eq!(Months::new(u32::MAX).as_u32(), u32::MAX);
371 }
372
373 #[test]
374 #[cfg(feature = "serde")]
375 fn test_serde_serialize() {
376 use serde_json::to_string;
377 use Month::*;
378
379 let cases: Vec<(Month, &str)> = vec![
380 (January, "\"January\""),
381 (February, "\"February\""),
382 (March, "\"March\""),
383 (April, "\"April\""),
384 (May, "\"May\""),
385 (June, "\"June\""),
386 (July, "\"July\""),
387 (August, "\"August\""),
388 (September, "\"September\""),
389 (October, "\"October\""),
390 (November, "\"November\""),
391 (December, "\"December\""),
392 ];
393
394 for (month, expected_str) in cases {
395 let string = to_string(&month).unwrap();
396 assert_eq!(string, expected_str);
397 }
398 }
399
400 #[test]
401 #[cfg(feature = "serde")]
402 fn test_serde_deserialize() {
403 use serde_json::from_str;
404 use Month::*;
405
406 let cases: Vec<(&str, Month)> = vec![
407 ("\"january\"", January),
408 ("\"jan\"", January),
409 ("\"FeB\"", February),
410 ("\"MAR\"", March),
411 ("\"mar\"", March),
412 ("\"april\"", April),
413 ("\"may\"", May),
414 ("\"june\"", June),
415 ("\"JULY\"", July),
416 ("\"august\"", August),
417 ("\"september\"", September),
418 ("\"October\"", October),
419 ("\"November\"", November),
420 ("\"DECEmbEr\"", December),
421 ];
422
423 for (string, expected_month) in cases {
424 let month = from_str::<Month>(string).unwrap();
425 assert_eq!(month, expected_month);
426 }
427
428 let errors: Vec<&str> =
429 vec!["\"not a month\"", "\"ja\"", "\"Dece\"", "Dec", "\"Augustin\""];
430
431 for string in errors {
432 from_str::<Month>(string).unwrap_err();
433 }
434 }
435
436 #[test]
437 #[cfg(feature = "rkyv-validation")]
438 fn test_rkyv_validation() {
439 let month = Month::January;
440 let bytes = rkyv::to_bytes::<_, 1>(&month).unwrap();
441 assert_eq!(rkyv::from_bytes::<Month>(&bytes).unwrap(), month);
442 }
443}