use crate::times::DateRange;
use chrono::{Date, DateTime, Datelike, FixedOffset, Local, TimeZone};
use std::env;
use std::io::{ErrorKind, Read};
use std::fs::{self, File, Metadata, OpenOptions};
use std::path::Path;
use std::time::SystemTime;
use regex::Regex;
pub fn get_metadata_created(metadata: Metadata) -> DateTime<FixedOffset> {
match metadata.created() {
Ok(created_at) => system_time_to_datetime(&created_at),
Err(e) => panic!("err getting session metadata: {:?}", e),
}
}
pub fn system_time_to_datetime(time: &SystemTime) -> DateTime<FixedOffset> {
match time.duration_since(SystemTime::UNIX_EPOCH) {
Ok(duration) => local_to_fixed_offset(Local.timestamp(duration.as_secs() as i64, 0)),
Err(e) => panic!("error getting SystemTime seconds: {}", e),
}
}
pub fn format_datetime(time: &DateTime<FixedOffset>) -> String {
time.to_rfc3339()
}
pub fn datetime_from_str(time: &str) -> DateTime<FixedOffset> {
DateTime::parse_from_rfc3339(time)
.unwrap_or_else(|e| panic!("failed to parse datetime {}: {}", time, e))
}
pub fn get_home_dir() -> String {
env::var("HOME").unwrap_or_else(|e| panic!("error getting $HOME env variable: {}", e))
}
pub fn create_dir(dir: &str) {
fs::create_dir_all(&dir).unwrap_or_else(|e| {
if e.kind() != ErrorKind::AlreadyExists {
panic!("could not create {} directory: {}", dir, e);
}
});
}
pub fn create_or_open_file(path: &str) -> File {
OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.expect(&format!("Error opening {}", &path))
}
pub fn get_length_hours(start: &DateTime<FixedOffset>, end: &DateTime<FixedOffset>) -> f64 {
((end.timestamp() - start.timestamp()) as f64) / 3600.0
}
pub fn get_file_contents(path: &Path) -> String {
let mut file = match File::open(&path) {
Ok(file) => file,
Err(e) => {
eprintln!("error opening {}: {}", path.display(), e);
std::process::exit(1);
}
};
let mut contents = String::new();
if let Err(e) = file.read_to_string(&mut contents) {
eprintln!("error reading {}: {}", path.display(), e);
std::process::exit(1);
}
contents
}
pub fn datetime_to_readable_str(date: &DateTime<FixedOffset>) -> String {
date.format("%Y-%m-%d %H:%M:%S").to_string()
}
pub fn get_start_date() -> DateTime<FixedOffset> {
local_to_fixed_offset(Local.ymd(1970, 1, 1).and_hms(0, 0, 0))
}
pub fn get_date_from_arg(date_arg: &str, end: bool) -> DateTime<FixedOffset> {
let get_time = |dt: Date<Local>| {
if !end {
dt.and_hms(0, 0, 0)
} else {
dt.and_hms(23, 59, 59)
}
};
if date_arg == "today" {
return local_to_fixed_offset(get_time(Local::today()));
}
let re = Regex::new(r"^(\d{4}-)?(\d{1,2})-(\d{1,2})$").unwrap();
let caps = re
.captures(date_arg)
.expect(&format!("{} is not a valid date", date_arg));
let year = match caps.get(1) {
Some(_) => caps[1][0..4].parse().unwrap(),
None => Local::today().year(),
};
let month: u32 = caps[2].parse().unwrap();
let day: u32 = caps[3].parse().unwrap();
local_to_fixed_offset(get_time(Local.ymd(year, month, day)))
}
pub fn local_to_fixed_offset(date: DateTime<Local>) -> DateTime<FixedOffset> {
DateTime::parse_from_rfc3339(&date.to_rfc3339()).unwrap()
}
pub fn parse_date_range(date_range: &str) -> Result<DateRange, &str> {
let dates = date_range.split("..").collect::<Vec<&str>>();
let start_date = get_start_date();
if dates.len() == 1 {
Ok(DateRange(start_date, get_date_from_arg(dates[0], true)))
} else if dates.len() == 2 {
match (dates[0], dates[1]) {
("", "") => Err("Invalid date-range provided"),
("", _) => Ok(DateRange(start_date, get_date_from_arg(dates[1], true))),
(_, "") => Ok(DateRange(
get_date_from_arg(dates[0], false),
get_date_from_arg("today", true),
)),
(_, _) => Ok(DateRange(
get_date_from_arg(dates[0], false),
get_date_from_arg(dates[1], true),
)),
}
} else {
Err("Invalid date-range provided")
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_date_range() {
let DateRange(start, end) = parse_date_range("2021-12-01..2021-12-13").unwrap();
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local.ymd(2021, 12, 13).and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_end_only() {
let DateRange(start, end) = parse_date_range("2021-12-01").unwrap();
assert_eq!(
Local.ymd(1970, 1, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_start_only() {
let DateRange(start, end) = parse_date_range("2021-12-01..").unwrap();
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local::today().and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_end_only_with_dots() {
let DateRange(start, end) = parse_date_range("..12-01").unwrap();
assert_eq!(
Local.ymd(1970, 1, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_today() {
let DateRange(start, end) = parse_date_range("today").unwrap();
assert_eq!(
Local.ymd(1970, 1, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local::today().and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_today_2() {
let DateRange(start, end) = parse_date_range("today..2021-12-31").unwrap();
assert_eq!(
Local::today().and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local.ymd(2021, 12, 31).and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_date_range_today_3() {
let DateRange(start, end) = parse_date_range("2021-12-1..today").unwrap();
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(0, 0, 0).timestamp(),
start.timestamp()
);
assert_eq!(
Local::today().and_hms(23, 59, 59).timestamp(),
end.timestamp()
);
}
#[test]
fn test_get_date_from_arg() {
let d = get_date_from_arg("2021-12-01", false);
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(0, 0, 0).timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_end() {
let d = get_date_from_arg("2021-12-01", true);
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(23, 59, 59).timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_one_digit_day() {
let d = get_date_from_arg("2021-12-1", false);
assert_eq!(
Local.ymd(2021, 12, 1).and_hms(0, 0, 0).timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_one_digit_month() {
let d = get_date_from_arg("2021-1-10", false);
assert_eq!(
Local.ymd(2021, 1, 10).and_hms(0, 0, 0).timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_one_digit_month_and_day() {
let d = get_date_from_arg("2021-1-1", false);
assert_eq!(
Local.ymd(2021, 1, 1).and_hms(0, 0, 0).timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_no_year() {
let d = get_date_from_arg("12-01", false);
assert_eq!(
Local
.ymd(Local::today().year(), 12, 1)
.and_hms(0, 0, 0)
.timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_no_year_one_digit_day() {
let d = get_date_from_arg("12-5", false);
assert_eq!(
Local
.ymd(Local::today().year(), 12, 5)
.and_hms(0, 0, 0)
.timestamp(),
d.timestamp()
);
}
#[test]
fn test_get_date_from_arg_today() {
let d = get_date_from_arg("today", false);
assert_eq!(Local::today().and_hms(0, 0, 0).timestamp(), d.timestamp());
}
}