use chrono::{Datelike, Local, NaiveDate, Utc};
use icu::datetime::input::{DateInput, IsoTimeInput};
use icu_calendar::{ethiopian::EthiopianEraStyle, types::Era, AsCalendar};
use std::str::FromStr;
use crate::julian::JD2NOON;
#[derive(Debug, Default, Clone, Copy)]
pub struct EarthDate {
pub year: i32,
pub month: u32,
pub day: u32,
}
impl EarthDate {
pub fn now() -> Self {
let now = chrono::Utc::now();
Self {
year: now.year(),
month: now.month(),
day: now.day(),
}
}
pub fn julian_epoch() -> Self {
let epoch = crate::julian::Julian.jd2greg_named(JD2NOON);
Self {
year: epoch.date.year,
month: epoch.date.month,
day: epoch.date.day,
}
}
}
#[derive(Debug, Default)]
pub struct EarthCodes {
pub year: String,
pub month: String,
pub day: String,
}
#[derive(Debug, Default, Copy, Clone)]
pub struct EarthTime {
pub hour: u8,
pub minute: u8,
pub second: u8,
}
#[derive(Debug, Default)]
pub struct EarthDateTime {
pub date: EarthDate,
pub codes: EarthCodes,
pub time: EarthTime,
}
impl EarthDateTime {
pub fn set_datetime(input: String) -> Vec<(String, String)> {
if let Ok(time) = chrono_tz::Tz::from_str(input.as_str()) {
let time = chrono::DateTime::with_timezone(&Utc::now(), &time).format("%Y/%m/%d %r %Z");
vec![(input, time.to_string())]
} else {
let name = Local::now()
.with_timezone(&Local::now().timezone())
.to_string();
let time = Local::now().format("%Y/%m/%d %r %Z");
vec![(name, time.to_string())]
}
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct EarthTimeZones;
impl EarthTimeZones {
pub fn all_timezones(mut list: Vec<String>) -> Vec<String> {
for variant in chrono_tz::TZ_VARIANTS.iter() {
list.push(variant.to_string())
}
list
}
}
#[macro_export]
macro_rules! set_datetimes {
($($location: expr), *) => {
$(
EarthDateTime::set_datetime($location.clone());
)*
};
}
#[macro_export]
macro_rules! getcal {
($cal: ty) => {};
}
#[macro_export]
macro_rules! get_icu {
(gregorian $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_gregorian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(julian $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_julian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(indian $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_indian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(iso $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_iso_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(chinese $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_chinese_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::chinese::Chinese::default(),
)
.unwrap(),
)
};
(roc $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_roc_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(ethiopian $n: expr, $era: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_ethiopian_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(japanese $n: expr, $era: expr ) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_japanese_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::japanese::Japanese::default(),
)
.unwrap(),
)
};
(persian $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_persian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(coptic $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_coptic_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(hebrew $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_hebrew_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::hebrew::Hebrew::new_always_calculating(),
)
.unwrap(),
)
};
(buddhist $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_buddhist_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap(),
)
};
(islamic_civil $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_islamic_civil_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicCivil::new_always_calculating(),
)
.unwrap(),
)
};
(islamic_observational $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_observational_islamic_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicObservational::new_always_calculating(),
)
.unwrap(),
)
};
(islamic_tabular $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_islamic_tabular_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicTabular::new_always_calculating(),
)
.unwrap(),
)
};
(islamic_umm_al_qura $n: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_ummalqura_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicUmmAlQura::new_always_calculating(),
)
.unwrap(),
)
};
(japanese_extended $n: expr, $era: expr) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_japanese_extended_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::japanese::JapaneseExtended::default(),
)
.unwrap(),
)
};
}
#[macro_export]
macro_rules! transport_icu {
(gregorian $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_gregorian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(julian $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_julian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(indian $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_indian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(iso $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_iso_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(chinese $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_chinese_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::chinese::Chinese::default(),
)
.unwrap()
.to_calendar($cal),
)
};
(roc $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_roc_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(ethiopian $n: expr, $era: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_ethiopian_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(japanese $n: expr, $era: expr, $cal: ident ) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_japanese_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::japanese::Japanese::default(),
)
.unwrap()
.to_calendar($cal),
)
};
(persian $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_persian_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(coptic $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_coptic_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(hebrew $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_hebrew_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::hebrew::Hebrew::new_always_calculating(),
)
.unwrap()
.to_calendar($cal),
)
};
(buddhist $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_buddhist_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
)
.unwrap()
.to_calendar($cal),
)
};
(islamic_civil $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_islamic_civil_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicCivil::new_always_calculating(),
)
.unwrap()
.to_calendar($cal),
)
};
(islamic_observational $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_observational_islamic_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicObservational::new_always_calculating(),
)
.unwrap()
.to_calendar($cal),
)
};
(islamic_tabular $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_islamic_tabular_datetime_with_calendar(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicTabular::new_always_calculating(),
)
.unwrap()
.to_calendar($cal),
)
};
(islamic_umm_al_qura $n: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_ummalqura_datetime(
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::islamic::IslamicUmmAlQura::new_always_calculating(),
)
.unwrap()
.to_calendar($cal),
)
};
(japanese_extended $n: expr, $era: expr, $cal: ident) => {
RustSolarCalendar.earth_maker(
icu_calendar::DateTime::try_new_japanese_extended_datetime(
$era,
$n.date.year,
$n.date.month as u8,
$n.date.day as u8,
$n.time.hour,
$n.time.minute,
$n.time.second,
icu_calendar::japanese::JapaneseExtended::default(),
)
.unwrap()
.to_calendar($cal),
)
};
}
#[derive(Debug, Default, Clone, Copy)]
pub struct RustSolarCalendar;
impl RustSolarCalendar {
pub fn get_cc<T: AsCalendar>(self, d: T) -> T {
d
}
pub fn earth_maker<T: AsCalendar>(self, date: icu_calendar::DateTime<T>) -> EarthDateTime {
EarthDateTime {
date: EarthDate {
year: date.year().unwrap().number,
month: date.month().unwrap().ordinal,
day: date.day_of_month().unwrap().0,
},
codes: EarthCodes {
year: date.year().unwrap().era.0.to_string(),
month: date.month().unwrap().code.0.to_string(),
day: format!("{:?}", date.iso_weekday().unwrap()),
},
time: EarthTime {
hour: date.hour().unwrap().number(),
minute: date.minute().unwrap().number(),
second: date.second().unwrap().number(),
},
}
}
pub fn construct_calendar(
self,
input: EarthDate,
calendar_type: &'static str,
) -> EarthDateTime {
let date: NaiveDate = NaiveDate::from_ymd_opt(input.year, input.month, input.day).unwrap();
let date = EarthDateTime {
date: EarthDate {
year: date.year(),
month: date.month(),
day: date.day(),
},
..Default::default()
};
match calendar_type {
"gregorian" => get_icu! {gregorian date},
"julian" => get_icu!(julian date),
"indian" => get_icu!(indian date),
"iso" => get_icu!(iso date),
"chinese" => get_icu!(chinese date),
"roc" => get_icu!(roc date),
"ethiopian_alem" => get_icu!(ethiopian date, EthiopianEraStyle::AmeteAlem),
"ethiopian_mihret" => get_icu!(ethiopian date, EthiopianEraStyle::AmeteMihret),
"japanese_heisei" => get_icu!(japanese date, Era::from_str("heisei").unwrap()),
"japanese_reiwa" => get_icu!(japanese date, Era::from_str("reiwa").unwrap()),
"japanese_meiji" => get_icu!(japanese date, Era::from_str("meiji").unwrap()),
"japanese_taisho" => get_icu!(japanese date, Era::from_str("taisho").unwrap()),
"japanese_showa" => get_icu!(japanese date, Era::from_str("showa").unwrap()),
"japanese_extended" => {
get_icu!(japanese_extended date, Era::from_str("kansei-1789").unwrap())
}
"persian" => get_icu!(persian date),
"coptic" => get_icu!(coptic date),
"hewbrew" => get_icu!(hebrew date),
"buddhist" => get_icu!(buddhist date),
"islamic_civil" => get_icu!(islamic_civil date),
"islamic_observational" => get_icu!(islamic_observational date),
"islamic_tabular" => get_icu!(islamic_tabular date),
"islamic_umm_al_qura" => get_icu!(islamic_umm_al_qura date),
_ => EarthDateTime::default(),
}
}
pub fn to_calendar<T: AsCalendar>(
self,
input: EarthDate,
calendar_type: &'static str,
conversion_type: T,
) -> EarthDateTime {
let date: NaiveDate = NaiveDate::from_ymd_opt(input.year, input.month, input.day).unwrap();
let date = EarthDateTime {
date: EarthDate {
year: date.year(),
month: date.month(),
day: date.day(),
},
..Default::default()
};
match calendar_type {
"gregorian" => transport_icu! {gregorian date, conversion_type},
"julian" => transport_icu!(julian date, conversion_type),
"indian" => transport_icu!(indian date, conversion_type),
"iso" => transport_icu!(iso date, conversion_type),
"chinese" => transport_icu!(chinese date, conversion_type),
"roc" => transport_icu!(roc date, conversion_type),
"ethiopian_alem" => {
transport_icu!(ethiopian date, EthiopianEraStyle::AmeteAlem, conversion_type)
}
"ethiopian_mihret" => {
transport_icu!(ethiopian date, EthiopianEraStyle::AmeteMihret, conversion_type)
}
"japanese_heisei" => {
transport_icu!(japanese date, Era::from_str("heisei").unwrap(), conversion_type)
}
"japanese_reiwa" => {
transport_icu!(japanese date, Era::from_str("reiwa").unwrap(), conversion_type)
}
"japanese_meiji" => {
transport_icu!(japanese date, Era::from_str("meiji").unwrap(), conversion_type)
}
"japanese_taisho" => {
transport_icu!(japanese date, Era::from_str("taisho").unwrap(), conversion_type)
}
"japanese_showa" => {
transport_icu!(japanese date, Era::from_str("showa").unwrap(), conversion_type)
}
"japanese_extended" => {
transport_icu!(japanese_extended date, Era::from_str("kansei-1789").unwrap(),conversion_type)
}
"persian" => transport_icu!(persian date, conversion_type),
"coptic" => transport_icu!(coptic date, conversion_type),
"hewbrew" => transport_icu!(hebrew date, conversion_type),
"buddhist" => transport_icu!(buddhist date, conversion_type),
"islamic_civil" => transport_icu!(islamic_civil date, conversion_type),
"islamic_observational" => transport_icu!(islamic_observational date, conversion_type),
"islamic_tabular" => transport_icu!(islamic_tabular date, conversion_type),
"islamic_umm_al_qura" => transport_icu!(islamic_umm_al_qura date, conversion_type),
_ => EarthDateTime::default(),
}
}
}