use crate::date::Date;
use crate::datetime::DateTime;
use crate::time::Time;
pub trait TimeFormat {
fn format(&self, fmt: &str) -> String;
}
impl TimeFormat for DateTime {
fn format(&self, fmt: &str) -> String {
format_datetime(self, fmt)
}
}
impl TimeFormat for Date {
fn format(&self, fmt: &str) -> String {
let dt = DateTime::new(
*self,
Time {
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
},
);
format_datetime(&dt, fmt)
}
}
impl TimeFormat for Time {
fn format(&self, fmt: &str) -> String {
format_time(self, fmt)
}
}
fn format_datetime(dt: &DateTime, fmt: &str) -> String {
let mut result = String::new();
let mut i = 0;
let chars: Vec<char> = fmt.chars().collect();
while i < chars.len() {
if chars[i] == '{' {
let mut end = i + 1;
while end < chars.len() && chars[end] != '}' {
end += 1;
}
if end < chars.len() && end > i + 1 {
let token: String = chars[i + 1..end].iter().collect();
result.push_str(&resolve_token_datetime(dt, &token));
i = end + 1;
continue;
}
}
result.push(chars[i]);
i += 1;
}
result
}
fn format_time(t: &Time, fmt: &str) -> String {
let dt = DateTime::new(Date::new(2000, 1, 1), *t);
format_datetime(&dt, fmt)
}
fn resolve_token_datetime(dt: &DateTime, token: &str) -> String {
let t = &dt.time;
let d = &dt.date;
match token {
"YYYY" => format!("{:04}", d.year),
"YY" => format!("{:02}", d.year % 100),
"MM" => format!("{:02}", d.month),
"M" => format!("{}", d.month),
"DD" => format!("{:02}", d.day),
"D" => format!("{}", d.day),
"HH" => format!("{:02}", t.hour),
"H" => format!("{}", t.hour),
"hh" => {
let (h, _) = t.hour12();
format!("{:02}", h)
}
"h" => {
let (h, _) = t.hour12();
format!("{}", h)
}
"mm" => format!("{:02}", t.minute),
"m" => format!("{}", t.minute),
"ss" => format!("{:02}", t.second),
"s" => format!("{}", t.second),
"SSS" => format!("{:03}", t.millisecond),
"W" => {
let wd = d.weekday();
match wd {
crate::date::Weekday::Monday => "Mon",
crate::date::Weekday::Tuesday => "Tue",
crate::date::Weekday::Wednesday => "Wed",
crate::date::Weekday::Thursday => "Thu",
crate::date::Weekday::Friday => "Fri",
crate::date::Weekday::Saturday => "Sat",
crate::date::Weekday::Sunday => "Sun",
}
.to_string()
}
"WW" => format!("{}", d.weekday()),
"AMPM" => {
if t.is_pm() {
"PM"
} else {
"AM"
}
.to_string()
}
"ampm" => {
if t.is_pm() {
"pm"
} else {
"am"
}
.to_string()
}
_ => format!("{{{}}}", token),
}
}
pub const ISO8601: &str = "{YYYY}-{MM}-{DD}T{HH}:{mm}:{ss}";
pub const ISO8601_DATE: &str = "{YYYY}-{MM}-{DD}";
pub const ISO8601_TIME: &str = "{HH}:{mm}:{ss}";
pub const RFC2822: &str = "{W}, {DD} {MM} {YYYY} {HH}:{mm}:{ss}";
pub const CHINESE_DATE: &str = "{YYYY}年{MM}月{DD}日";
pub const CHINESE_DATETIME: &str = "{YYYY}年{MM}月{DD}日 {HH}:{mm}:{ss}";