mailpot/web/src/cal.rs

245 lines
7.3 KiB
Rust

// MIT License
//
// Copyright (c) 2021 sadnessOjisan
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use chrono::*;
#[allow(dead_code)]
/// Generate a calendar view of the given date's month.
///
/// Each vector element is an array of seven numbers representing weeks
/// (starting on Sundays), and each value is the numeric date.
/// A value of zero means a date that not exists in the current month.
///
/// # Examples
/// ```
/// use chrono::*;
/// use mailpot_web::calendarize;
///
/// let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
/// // Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
/// println!("{:?}", calendarize(date));
/// // [0, 0, 0, 0, 0, 1, 2],
/// // [3, 4, 5, 6, 7, 8, 9],
/// // [10, 11, 12, 13, 14, 15, 16],
/// // [17, 18, 19, 20, 21, 22, 23],
/// // [24, 25, 26, 27, 28, 29, 30],
/// // [31, 0, 0, 0, 0, 0, 0]
/// ```
pub fn calendarize(date: NaiveDate) -> Vec<[u32; 7]> {
calendarize_with_offset(date, 0)
}
/// Generate a calendar view of the given date's month and offset.
///
/// Each vector element is an array of seven numbers representing weeks
/// (starting on Sundays), and each value is the numeric date.
/// A value of zero means a date that not exists in the current month.
///
/// Offset means the number of days from sunday.
/// For example, 1 means monday, 6 means saturday.
///
/// # Examples
/// ```
/// use chrono::*;
/// use mailpot_web::calendarize_with_offset;
///
/// let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
/// // Week = [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
/// println!("{:?}", calendarize_with_offset(date, 1));
/// // [0, 0, 0, 0, 1, 2, 3],
/// // [4, 5, 6, 7, 8, 9, 10],
/// // [11, 12, 13, 14, 15, 16, 17],
/// // [18, 19, 20, 21, 22, 23, 24],
/// // [25, 26, 27, 28, 29, 30, 0],
/// ```
pub fn calendarize_with_offset(date: NaiveDate, offset: u32) -> Vec<[u32; 7]> {
let mut monthly_calendar: Vec<[u32; 7]> = Vec::with_capacity(6);
let year = date.year();
let month = date.month();
let num_days_from_sunday = NaiveDate::from_ymd_opt(year, month, 1)
.unwrap()
.weekday()
.num_days_from_sunday();
let mut first_date_day;
if num_days_from_sunday < offset {
first_date_day = num_days_from_sunday + (7 - offset);
} else {
first_date_day = num_days_from_sunday - offset;
}
let end_date = NaiveDate::from_ymd_opt(year, month + 1, 1)
.unwrap_or_else(|| NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap())
.pred_opt()
.unwrap()
.day();
let mut date: u32 = 0;
while date < end_date {
let mut week: [u32; 7] = [0; 7];
for day in first_date_day..7 {
date += 1;
week[day as usize] = date;
if date >= end_date {
break;
}
}
first_date_day = 0;
monthly_calendar.push(week);
}
monthly_calendar
}
#[test]
fn january() {
let date = NaiveDate::parse_from_str("2021-01-02", "%Y-%m-%d").unwrap();
let actual = calendarize(date);
assert_eq!(
vec![
[0, 0, 0, 0, 0, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30],
[31, 0, 0, 0, 0, 0, 0]
],
actual
);
}
#[test]
// Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
fn with_offset_from_sunday() {
let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
let actual = calendarize_with_offset(date, 0);
assert_eq!(
vec![
[0, 0, 0, 0, 0, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30],
],
actual
);
}
#[test]
// Week = [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
fn with_offset_from_monday() {
let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
let actual = calendarize_with_offset(date, 1);
assert_eq!(
vec![
[0, 0, 0, 0, 1, 2, 3],
[4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, 0],
],
actual
);
}
#[test]
// Week = [Sat, Sun, Mon, Tue, Wed, Thu, Fri]
fn with_offset_from_saturday() {
let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
let actual = calendarize_with_offset(date, 6);
assert_eq!(
vec![
[0, 0, 0, 0, 0, 0, 1],
[2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22],
[23, 24, 25, 26, 27, 28, 29],
[30, 0, 0, 0, 0, 0, 0]
],
actual
);
}
#[test]
// Week = [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
fn with_offset_from_sunday_with7() {
let date = NaiveDate::parse_from_str("2019-11-01", "%Y-%m-%d").unwrap();
let actual = calendarize_with_offset(date, 7);
assert_eq!(
vec![
[0, 0, 0, 0, 0, 1, 2],
[3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16],
[17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30],
],
actual
);
}
#[test]
fn april() {
let date = NaiveDate::parse_from_str("2021-04-02", "%Y-%m-%d").unwrap();
let actual = calendarize(date);
assert_eq!(
vec![
[0, 0, 0, 0, 1, 2, 3],
[4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30, 0]
],
actual
);
}
#[test]
fn uruudoshi() {
let date = NaiveDate::parse_from_str("2020-02-02", "%Y-%m-%d").unwrap();
let actual = calendarize(date);
assert_eq!(
vec![
[0, 0, 0, 0, 0, 0, 1],
[2, 3, 4, 5, 6, 7, 8],
[9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22],
[23, 24, 25, 26, 27, 28, 29]
],
actual
);
}
#[test]
fn uruwanaidoshi() {
let date = NaiveDate::parse_from_str("2021-02-02", "%Y-%m-%d").unwrap();
let actual = calendarize(date);
assert_eq!(
vec![
[0, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12, 13],
[14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27],
[28, 0, 0, 0, 0, 0, 0]
],
actual
);
}