pub mod parsers {
use std::{time,fmt};
use chrono::{Local, DateTime, FixedOffset, ParseError, NaiveTime, NaiveDate, Datelike, TimeZone, Timelike, Utc, Duration};
use crate::errors::errors::{TError, TErrorKind, TResult};
use std::ops::Add;
pub struct DateParser {
pub action:String,
pub clock:String,
pub day_time:i8,
}
impl DateParser {
pub fn new() -> DateParser {
DateParser{
action: String::from(""),
clock: String::from(""),
day_time: 0
}
}
pub fn parser(&mut self, date_format:&str) -> TResult<()> {
let mut date_split = date_format.split(" ").collect::<Vec<&str>>();
if date_split.len() < 2 {
return Err(TError::new(TErrorKind::BadFormat));
}
self.action = String::from(date_split[0].to_lowercase());
match self.action.as_str() {
"day" => {
self.clock = String::from(date_split[1])
}
"week" | "month" => {
if date_split.len() < 3 {
return Err(TError::new(TErrorKind::BadFormat));
}
self.clock = String::from(date_split[2]);
let rv = date_split[1].parse();
match rv {
Ok(value) => { self.day_time = value }
Err(e) => { return Err(TError::new(TErrorKind::Other(e.to_string().clone()))) }
}
}
_ => {}
}
Ok(())
}
}
pub fn getMonthDay(year:i32,month:i32) -> Option<i32> {
let m_wday = vec![31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if month == 2 && (year%4) == 0 && ( year % 100 != 0 || year % 400 == 0) {
Some(29)
}else {
let index = (month - 1) as usize;
let r = m_wday.get(index);
match r {
Some(v) => { Some(*v) }
None => None
}
}
}
fn next_date_time(year:i32, month:u32, day:u32, time_format:&str) -> TResult<DateTime<Local>> {
let vt = NaiveTime::parse_from_str(time_format, "%T");
match vt {
Ok(time_tt) => {
let ndt = Local.ymd(year, month,day )
.and_hms(time_tt.hour(),time_tt.minute(),time_tt.second());
Ok(ndt)
}
Err(ve) => {
Err(TError::new(TErrorKind::Other(ve.to_string())))
}
}
}
fn next_date_timeUtc(year:i32, month:u32, day:u32, time_format:&str) -> TResult<DateTime<Utc>> {
let vt = NaiveTime::parse_from_str(time_format, "%T");
match vt {
Ok(time_tt) => {
let ndt = Utc.ymd(year, month,day )
.and_hms(time_tt.hour(),time_tt.minute(),time_tt.second());
Ok(ndt)
}
Err(ve) => {
Err(TError::new(TErrorKind::Other(ve.to_string())))
}
}
}
fn atNowTime(time_format:&str) -> TResult<DateTime<Local>> {
let now_time = Local::now();
let vt = NaiveTime::parse_from_str(time_format, "%T");
match vt {
Ok(time_tt) => {
let ndt = Local.ymd(now_time.year(), now_time.month(), now_time.day())
.and_hms(time_tt.hour(),time_tt.minute(),time_tt.second());
Ok(ndt)
}
Err(ve) => {
Err(TError::new(TErrorKind::Other(ve.to_string())))
}
}
}
fn atUtcNowTime(time_format:&str) -> TResult<DateTime<Utc>> {
let now_time = Utc::now();
let vt = NaiveTime::parse_from_str(time_format, "%T");
match vt {
Ok(time_tt) => {
let ndt = Utc.ymd(now_time.year(), now_time.month(), now_time.day())
.and_hms(time_tt.hour(),time_tt.minute(),time_tt.second());
Ok(ndt)
}
Err(ve) => {
Err(TError::new(TErrorKind::Other(ve.to_string())))
}
}
}
pub fn parser_next(timeStr:&str) -> TResult<chrono::DateTime<Local>> {
let mut date_pv = DateParser::new();
date_pv.parser(timeStr)?;
let nowTime = Local::now();
if "day" == date_pv.action {
let mut atTime = atNowTime(&date_pv.clock)?;
if nowTime.timestamp() >= atTime.timestamp() {
atTime = atTime + Duration::days(1);
}
return Ok(atTime);
}else if "week" == date_pv.action {
let mut atTime = atNowTime(&date_pv.clock)?;
if date_pv.day_time >= 7 || date_pv.day_time < 0 {
return Err(TError::new(TErrorKind::WeekDay));
}
let weekDayNow = nowTime.weekday().num_days_from_sunday() as i8;
let mut weekOffset = date_pv.day_time - weekDayNow;
if weekOffset < 0 {
weekOffset += 7;
}
if weekOffset != 0 ||nowTime.timestamp() >= atTime.timestamp() {
atTime = atTime +Duration::days(weekOffset as i64);
}
return Ok(atTime);
}else if "month" == date_pv.action {
let maxDay = getMonthDay(nowTime.year(),nowTime.month() as i32).unwrap();
if date_pv.day_time as i32 > maxDay {
return Err(TError::new(TErrorKind::DateOverflow));
}
let mut nextTime = next_date_time(nowTime.year(),
nowTime.month(),date_pv.day_time as u32,
&date_pv.clock)?;
if nowTime.timestamp() >= nextTime.timestamp() {
nextTime = next_date_time(nowTime.year(),
nowTime.month()+1,date_pv.day_time as u32,
&date_pv.clock)?;
}
return Ok(nextTime);
}else {
return Err(TError::new(TErrorKind::BadFormat));
}
Err(TError::new(TErrorKind::BadFormat))
}
pub fn parser_timestamp(timeStr:&str) -> TResult<i64> {
let date_now = parser_next(timeStr)?;
Ok(date_now.timestamp())
}
pub fn parser_nextUtc(timeStr:&str) -> TResult<chrono::DateTime<Utc>> {
let mut date_pv = DateParser::new();
date_pv.parser(timeStr)?;
let nowTime = Utc::now();
if "day" == date_pv.action {
let mut atTime = atUtcNowTime(&date_pv.clock)?;
if nowTime.timestamp() >= atTime.timestamp() {
atTime = atTime + Duration::days(1);
}
return Ok(atTime);
}else if "week" == date_pv.action {
let mut atTime = atUtcNowTime(&date_pv.clock)?;
if date_pv.day_time >= 7 || date_pv.day_time < 0 {
return Err(TError::new(TErrorKind::WeekDay));
}
let weekDayNow = nowTime.weekday().num_days_from_sunday() as i8;
let mut weekOffset = date_pv.day_time - weekDayNow;
if weekOffset < 0 {
weekOffset += 7;
}
if weekOffset != 0 ||nowTime.timestamp() >= atTime.timestamp() {
atTime = atTime +Duration::days(weekOffset as i64);
}
return Ok(atTime);
}else if "month" == date_pv.action {
let maxDay = getMonthDay(nowTime.year(),nowTime.month() as i32).unwrap();
if date_pv.day_time as i32 > maxDay {
return Err(TError::new(TErrorKind::DateOverflow));
}
let mut nextTime = next_date_timeUtc(nowTime.year(),
nowTime.month(),date_pv.day_time as u32,
&date_pv.clock)?;
if nowTime.timestamp() >= nextTime.timestamp() {
nextTime = next_date_timeUtc(nowTime.year(),
nowTime.month()+1,date_pv.day_time as u32,
&date_pv.clock)?;
}
return Ok(nextTime);
}else {
return Err(TError::new(TErrorKind::BadFormat));
}
Err(TError::new(TErrorKind::BadFormat))
}
pub fn parser_timestampUtc(timeStr:&str) -> TResult<i64> {
let date_now = parser_nextUtc(timeStr)?;
Ok(date_now.timestamp())
}
#[test]
fn test_parser_date() {
let mut datep = DateParser::new();
datep.parser("Day 00:00:00");
assert_eq!(datep.action,"day");
assert_eq!(datep.clock,"00:00:00");
datep.parser("Week 1 00:00:00");
assert_eq!(datep.action,"week");
assert_eq!(datep.day_time,1);
assert_eq!(datep.clock,"00:00:00");
}
#[test]
fn test_utils() {
let gDay = getMonthDay(2009,1);
let timeFtm = atNowTime("05:00:00").unwrap();
println!("day:{}",gDay.unwrap());
println!("fmt:{}",timeFtm.format("%Y-%m-%d %H:%M:%S"));
println!("unix time:{}",timeFtm.timestamp())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parsers::parsers::{getMonthDay, parser_next, parser_timestamp, parser_nextUtc, parser_timestampUtc};
use chrono::Local;
#[test]
fn test_parser_next() {
let next_date = parser_next("Day 05:00:00").unwrap();
let next_tick = parser_timestamp("Day 05:00:00").unwrap();
let next_weekDAY = parser_next("WEEK 2 06:00:00").unwrap();
let next_weekTick = parser_timestamp("WEEK 2 06:00:00").unwrap();
let next_monthDAY = parser_next("Month 2 06:00:00").unwrap();
let next_monthTick = parser_timestamp("Month 2 06:00:00").unwrap();
println!("day {} - unix:{}",next_date,next_tick);
println!("week {} - unix:{}",next_weekDAY,next_weekTick);
println!("month {} - unix:{}",next_monthDAY,next_monthTick);
}
#[test]
fn test_parser_utc() {
let next_date = parser_nextUtc("Day 05:00:00").unwrap();
let next_tick = parser_timestampUtc("Day 05:00:00").unwrap();
let next_weekDAY = parser_nextUtc("WEEK 2 06:00:00").unwrap();
let next_weekTick = parser_timestampUtc("WEEK 2 06:00:00").unwrap();
let next_monthDAY = parser_nextUtc("Month 2 06:00:00").unwrap();
let next_monthTick = parser_timestampUtc("Month 2 06:00:00").unwrap();
println!("utc day {} - unix:{}",next_date,next_tick);
println!("utc week {} - unix:{}",next_weekDAY,next_weekTick);
println!("utc month {} - unix:{}",next_monthDAY,next_monthTick);
}
}