Render times in local and UTC

This commit is contained in:
Savanni D'Gerinel 2024-02-29 09:39:03 -05:00
parent 22b772a8c7
commit 245f9d0997
1 changed files with 122 additions and 33 deletions

View File

@ -1,28 +1,39 @@
use std::ops::Deref;
use chrono::{Datelike, FixedOffset, NaiveDate, Timelike};
use chrono_tz::Tz;
use icu::datetime::options::length;
use icu_locid::locale;
use chrono::{Datelike, FixedOffset, NaiveDate, TimeZone, Timelike};
use chrono_tz::{OffsetName, Tz};
use icu::{
datetime::options::length,
timezone::{CustomTimeZone, GmtOffset},
};
use icu_locid::{locale, Locale};
use icu_provider::DataLocale;
use sys_locale::get_locales;
use std::str::FromStr;
use sys_locale::get_locale;
#[derive(Clone, Copy, Debug)]
pub struct L10N {}
#[derive(Clone, Debug)]
pub struct L10N {
locale: Locale,
zone: chrono_tz::Tz,
}
impl Default for L10N {
fn default() -> Self {
Self {}
let lc = get_locale().unwrap();
let locale = Locale::try_from_bytes(lc.as_bytes()).unwrap();
let zone = chrono_tz::UTC;
Self { locale, zone }
}
}
impl L10N {
fn set_locale(&mut self, locale: String) {
unimplemented!()
let locale = Locale::try_from_bytes(locale.as_bytes()).unwrap();
self.locale = locale;
}
fn set_timezone(&mut self, zone: Tz) {
unimplemented!()
self.zone = zone;
}
// Need to take a message and turn it into a string in the current language. Except I don't
@ -39,7 +50,15 @@ impl L10N {
date_style: length::Date,
time_style: length::Time,
) -> String {
unimplemented!()
let time: DateTime = time.with_timezone(&chrono_tz::UTC).into();
let options = length::Bag::from_date_time_style(date_style, time_style);
let formatter = icu::datetime::DateTimeFormatter::try_new(
&DataLocale::from(&self.locale),
options.into(),
)
.unwrap();
let icu_time: icu::calendar::DateTime<icu::calendar::Gregorian> = time.into();
formatter.format_to_string(&icu_time.to_any()).unwrap()
}
fn format_date_time_local(
@ -48,27 +67,60 @@ impl L10N {
date_style: length::Date,
time_style: length::Time,
) -> String {
unimplemented!()
}
fn format_date_time_tz(
&self,
time: DateTime,
date_style: length::Date,
time_style: length::Time,
) -> String {
let time: DateTime = time.with_timezone(&self.zone).into();
let options = length::Bag::from_date_time_style(date_style, time_style);
let formatter = icu::datetime::DateTimeFormatter::try_new(
&DataLocale::from(locale!("en-US")),
&DataLocale::from(&self.locale),
options.into(),
)
.unwrap();
let icu_time: icu::calendar::DateTime<icu::calendar::Gregorian> = time.into();
let any = icu_time.to_any();
formatter.format_to_string(&any).unwrap()
formatter.format_to_string(&icu_time.to_any()).unwrap()
}
/*
* I have been unable to get from a chrono_tz::Tz to an ICU timezone. I have tried a variety of
* parsers on the CustomTimeZone object. I have not researched the data provider to see what is
* available there. The ZoneID for the reference date is US/Mountain, and the abbreviation is
* MST. I'll want to get to a CustomTimeZone so that the formatter can render MST or Mountain
* Standard Time or something similar.
fn format_date_time_tz(
&self,
time: DateTime,
date_style: length::Date,
time_style: length::Time,
) -> String {
let options = length::Bag::from_date_time_style(date_style, time_style);
let formatter = icu::datetime::ZonedDateTimeFormatter::try_new(
&DataLocale::from(&self.locale),
options.into(),
Default::default(),
)
.unwrap();
let icu_time: icu::calendar::DateTime<icu::calendar::Gregorian> = time.into();
let any = icu_time.to_any();
println!("{:?}", time.offset());
let zone_id: String = time.offset().abbreviation().to_owned();
println!("{:?}", zone_id);
let zone_id = icu::timezone::TimeZoneBcp47Id::from_str(&zone_id).unwrap();
let zone: CustomTimeZone = CustomTimeZone {
gmt_offset: None,
time_zone_id: Some(zone_id),
/*
icu::timezone::TimeZoneBcp47Id::from_str(time.offset().tz_id().parse().unwrap())
.unwrap(),
*/
metazone_id: None,
zone_variant: None,
};
formatter.format_to_string(&any, &zone).unwrap()
}
*/
fn format_date(
&self,
time: NaiveDate,
@ -83,6 +135,7 @@ impl L10N {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct DateTime(chrono::DateTime<Tz>);
impl Deref for DateTime {
@ -119,23 +172,59 @@ impl From<DateTime> for icu::calendar::DateTime<icu::calendar::Gregorian> {
mod tests {
use super::*;
#[test]
fn it_formats_a_time_according_to_locale() {
let l10n = L10N::default();
let now = NaiveDate::from_ymd_opt(2006, 1, 2)
fn reftime() -> DateTime {
NaiveDate::from_ymd_opt(2006, 1, 2)
.unwrap()
.and_hms_opt(3, 4, 5)
.unwrap()
.and_local_timezone(Tz::UTC)
.and_local_timezone(Tz::US__Mountain)
.unwrap()
.into();
.into()
}
#[test]
fn it_formats_a_time_in_utc() {
let mut l10n = L10N::default();
// Make sure we know the locale before the test begins. Some systems, such as my own, are
// not actually in English.
l10n.set_locale("en-US".to_owned());
l10n.set_timezone(chrono_tz::US::Eastern);
let now = reftime();
// 202f is the code-point for a narrow non-breaking space. Presumably this is used in
// particular to ensure that the am/pm marker doesn't get split off from the time
assert_eq!(
l10n.format_date_time_tz(now, length::Date::Long, length::Time::Medium),
"January 2, 2006, 3:04:05\u{202f}AM"
l10n.format_date_time_utc(now.clone(), length::Date::Long, length::Time::Medium),
"January 2, 2006, 10:04:05\u{202f}AM"
);
l10n.set_locale("eo-EO".to_owned());
assert_eq!(
l10n.format_date_time_utc(now.clone(), length::Date::Long, length::Time::Medium),
"2006-Januaro-02 10:04:05"
);
}
#[test]
fn it_formats_a_time_in_the_current_zone() {
let mut l10n = L10N::default();
// Make sure we know the locale before the test begins. Some systems, such as my own, are
// not actually in English.
l10n.set_locale("en-US".to_owned());
l10n.set_timezone(chrono_tz::US::Eastern);
let now = reftime();
// 202f is the code-point for a narrow non-breaking space. Presumably this is used in
// particular to ensure that the am/pm marker doesn't get split off from the time
assert_eq!(
l10n.format_date_time_local(now.clone(), length::Date::Long, length::Time::Medium),
"January 2, 2006, 5:04:05\u{202f}AM"
);
l10n.set_locale("eo-EO".to_owned());
assert_eq!(
l10n.format_date_time_local(now.clone(), length::Date::Long, length::Time::Medium),
"2006-Januaro-02 05:04:05"
);
}