///|
/// A month of the year.
pub(all) enum Month {
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
} derive(Eq, Compare, Hash, @debug.Debug)
///|
pub extend Month with Eq::{equal}
///|
pub extend Month with Eq::{not_equal}
///|
pub extend Month with Compare::{compare, op_lt, op_gt, op_le, op_ge}
///|
pub extend Month with Hash::{hash, hash_combine}
///|
pub extend Month with @debug.Debug::{to_repr}
///|
/// The next month, wrapping from `Dec` back to `Jan`.
pub fn Month::succ(self : Month) -> Month {
match self {
Jan => Feb
Feb => Mar
Mar => Apr
Apr => May
May => Jun
Jun => Jul
Jul => Aug
Aug => Sep
Sep => Oct
Oct => Nov
Nov => Dec
Dec => Jan
}
}
///|
/// The month `n` months after `self` (before it, for a negative `n`),
/// wrapping around the year in either direction.
pub fn Month::add_months(self : Month, n : Int) -> Month {
let index = (self.number() - 1 + n % 12 + 12) % 12
Month::from_number(index + 1).unwrap()
}
///|
/// The previous month, wrapping from `Jan` back to `Dec`.
pub fn Month::pred(self : Month) -> Month {
match self {
Jan => Dec
Feb => Jan
Mar => Feb
Apr => Mar
May => Apr
Jun => May
Jul => Jun
Aug => Jul
Sep => Aug
Oct => Sep
Nov => Oct
Dec => Nov
}
}
///|
/// Month-of-year number counting from `Jan = 1`.
pub fn Month::number(self : Month) -> Int {
match self {
Jan => 1
Feb => 2
Mar => 3
Apr => 4
May => 5
Jun => 6
Jul => 7
Aug => 8
Sep => 9
Oct => 10
Nov => 11
Dec => 12
}
}
///|
/// The English name of the month.
pub fn Month::name(self : Month) -> String {
match self {
Jan => "January"
Feb => "February"
Mar => "March"
Apr => "April"
May => "May"
Jun => "June"
Jul => "July"
Aug => "August"
Sep => "September"
Oct => "October"
Nov => "November"
Dec => "December"
}
}
///|
pub impl Show for Month with fn output(self, logger) {
logger.write_string(self.name())
}
///|
pub extend Month with Show::{to_string, output}
///|
/// The month named by `name`: its full English name (`"January"`) or its
/// three-letter abbreviation (`"Jan"`), ignoring ASCII letter case, or
/// `None` for anything else (including a prefix, an abbreviation of another
/// length such as `"Sept"`, surrounding whitespace, or non-ASCII text).
pub fn Month::from_name(name : String) -> Month? {
let key = ascii_lower(name)
for number in 1..<=12 {
let month = Month::from_number(number).unwrap()
if key == ascii_lower(month.name()) ||
key == ascii_lower(month.short_name()) {
return Some(month)
}
}
None
}
///|
/// The month for a 1-based month-of-year number, or `None` if `n` is
/// outside `1..=12`.
pub fn Month::from_number(n : Int) -> Month? {
match n {
1 => Some(Jan)
2 => Some(Feb)
3 => Some(Mar)
4 => Some(Apr)
5 => Some(May)
6 => Some(Jun)
7 => Some(Jul)
8 => Some(Aug)
9 => Some(Sep)
10 => Some(Oct)
11 => Some(Nov)
12 => Some(Dec)
_ => None
}
}
///|
/// The number of days in the month for the given (proleptic Gregorian)
/// `year`, accounting for leap years in `Feb`. A month alone does not know the
/// year, hence the argument; see `NaiveDate::num_days_in_month` for the month
/// of a date.
pub fn Month::num_days(self : Month, year : Int) -> Int {
match self {
Jan => 31
Feb => if is_leap_year(year) { 29 } else { 28 }
Mar => 31
Apr => 30
May => 31
Jun => 30
Jul => 31
Aug => 31
Sep => 30
Oct => 31
Nov => 30
Dec => 31
}
}