add parse

This commit is contained in:
2020-05-30 01:01:50 +08:00
parent 7eca5520d7
commit 38d8f7c3cf

View File

@@ -1,6 +1,9 @@
#[macro_use] extern crate quick_error; #[macro_use] extern crate quick_error;
use chrono::{ Local,prelude::*, }; use chrono::{ Local,prelude::*, };
use std::str::Chars;
use std::iter::Peekable;
quick_error! { quick_error! {
#[derive(Debug)] #[derive(Debug)]
pub enum ParseError { pub enum ParseError {
@@ -10,42 +13,108 @@ quick_error! {
} }
} }
#[derive(Debug)]
enum SimpleDateFormatPart { enum SimpleDateFormatPart {
Year, YearLower(usize),
Month, YearUpper(usize),
MonthLower(usize),
MonthUpper(usize),
Day, Day,
Hour, Hour,
Minute, Minute,
Second, Second,
LiteralChar(char),
Literal(String), Literal(String),
} }
#[derive(Debug)]
pub struct SimpleDateFormat { pub struct SimpleDateFormat {
parts: Vec<SimpleDateFormatPart>, parts: Vec<SimpleDateFormatPart>,
} }
impl SimpleDateFormat { impl SimpleDateFormat {
fn format_local(&self, date_time: &DateTime<Local>) -> String { pub fn format_local(&self, date_time: &DateTime<Local>) -> String {
let mut ret = String::with_capacity(512); let mut ret = String::with_capacity(512);
ret.push_str(&format!("{}", date_time.year()));
ret.push('-'); for part in &self.parts {
ret.push_str(&format!("{}", date_time.month())); match part {
ret.push('-'); SimpleDateFormatPart::LiteralChar(c) => ret.push(*c),
ret.push_str(&format!("{}", date_time.day())); SimpleDateFormatPart::Literal(s) => ret.push_str(s),
SimpleDateFormatPart::YearLower(cnt) => ret.push_str(&format_str(date_time.year(), *cnt)),
SimpleDateFormatPart::MonthLower(cnt) => ret.push_str(&format_str(date_time.month() as i32, *cnt)),
_ => (),
}
}
ret ret
} }
} }
pub fn fmt(f: &str) -> Result<SimpleDateFormat, ParseError> { pub fn fmt(f: &str) -> Result<SimpleDateFormat, ParseError> {
Ok(SimpleDateFormat{ parts: vec![] }) let mut parts = vec![];
let mut is_in_quotation_mark = false;
let mut literal = String::new();
let mut chars = f.chars().peekable();
while let Some(c) = chars.next() {
if is_in_quotation_mark && c != '\'' {
literal.push(c);
continue;
}
match c {
'\'' => if is_in_quotation_mark {
if let Some('\'') = chars.peek() {
literal.push(c);
chars.next(); // eat '\''
} else {
is_in_quotation_mark = false;
parts.push(SimpleDateFormatPart::Literal(literal));
literal = String::new();
}
} else {
is_in_quotation_mark = true;
},
',' | '.' | ':' | '-' | ' ' => parts.push(SimpleDateFormatPart::LiteralChar(c)),
'y' => parts.push(SimpleDateFormatPart::YearLower(get_all_chars(c, &mut chars))),
'Y' => parts.push(SimpleDateFormatPart::YearUpper(get_all_chars(c, &mut chars))),
'm' => parts.push(SimpleDateFormatPart::MonthLower(get_all_chars(c, &mut chars))),
'M' => parts.push(SimpleDateFormatPart::MonthUpper(get_all_chars(c, &mut chars))),
_ => (),
}
}
Ok(SimpleDateFormat{ parts })
// Err(ParseError::Format(f.into())) // Err(ParseError::Format(f.into()))
} }
fn format_str(n: i32, cnt: usize) -> String {
let ret = format!("{}", n);
if cnt > ret.len() {
"0".repeat(cnt - ret.len()) + &ret
} else {
ret
}
}
fn get_all_chars(c: char, chars: &mut Peekable<Chars>) -> usize {
let mut cnt = 1_usize;
while let Some(next_char) = chars.peek() {
if *next_char == c {
cnt += 1;
chars.next();
} else {
break;
}
}
cnt
}
#[test] #[test]
fn it_works() { fn it_works() {
println!("test output: {}", fmt("").unwrap().format_local(&Local::now())); // println!("test output: {}", fmt("").unwrap().format_local(&Local::now()));
println!("{:?}", fmt("y yy-mm 'mm '''"));
println!("{:?}", fmt("y yy-mm'(-'m')' '[mm]'").unwrap().format_local(&Local::now()));
assert_eq!(2 + 2, 4); assert_eq!(2 + 2, 4);
} }