Render times in local and UTC
This commit is contained in:
parent
22b772a8c7
commit
245f9d0997
155
l10n/src/lib.rs
155
l10n/src/lib.rs
|
@ -1,28 +1,39 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use chrono::{Datelike, FixedOffset, NaiveDate, Timelike};
|
use chrono::{Datelike, FixedOffset, NaiveDate, TimeZone, Timelike};
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::{OffsetName, Tz};
|
||||||
use icu::datetime::options::length;
|
use icu::{
|
||||||
use icu_locid::locale;
|
datetime::options::length,
|
||||||
|
timezone::{CustomTimeZone, GmtOffset},
|
||||||
|
};
|
||||||
|
use icu_locid::{locale, Locale};
|
||||||
use icu_provider::DataLocale;
|
use icu_provider::DataLocale;
|
||||||
use sys_locale::get_locales;
|
use std::str::FromStr;
|
||||||
|
use sys_locale::get_locale;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct L10N {}
|
pub struct L10N {
|
||||||
|
locale: Locale,
|
||||||
|
zone: chrono_tz::Tz,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for L10N {
|
impl Default for L10N {
|
||||||
fn default() -> Self {
|
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 {
|
impl L10N {
|
||||||
fn set_locale(&mut self, locale: String) {
|
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) {
|
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
|
// 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,
|
date_style: length::Date,
|
||||||
time_style: length::Time,
|
time_style: length::Time,
|
||||||
) -> String {
|
) -> 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(
|
fn format_date_time_local(
|
||||||
|
@ -48,27 +67,60 @@ impl L10N {
|
||||||
date_style: length::Date,
|
date_style: length::Date,
|
||||||
time_style: length::Time,
|
time_style: length::Time,
|
||||||
) -> String {
|
) -> String {
|
||||||
unimplemented!()
|
let time: DateTime = time.with_timezone(&self.zone).into();
|
||||||
}
|
|
||||||
|
|
||||||
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 options = length::Bag::from_date_time_style(date_style, time_style);
|
||||||
let formatter = icu::datetime::DateTimeFormatter::try_new(
|
let formatter = icu::datetime::DateTimeFormatter::try_new(
|
||||||
&DataLocale::from(locale!("en-US")),
|
&DataLocale::from(&self.locale),
|
||||||
options.into(),
|
options.into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let icu_time: icu::calendar::DateTime<icu::calendar::Gregorian> = time.into();
|
let icu_time: icu::calendar::DateTime<icu::calendar::Gregorian> = time.into();
|
||||||
let any = icu_time.to_any();
|
formatter.format_to_string(&icu_time.to_any()).unwrap()
|
||||||
|
|
||||||
formatter.format_to_string(&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(
|
fn format_date(
|
||||||
&self,
|
&self,
|
||||||
time: NaiveDate,
|
time: NaiveDate,
|
||||||
|
@ -83,6 +135,7 @@ impl L10N {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
struct DateTime(chrono::DateTime<Tz>);
|
struct DateTime(chrono::DateTime<Tz>);
|
||||||
|
|
||||||
impl Deref for DateTime {
|
impl Deref for DateTime {
|
||||||
|
@ -119,23 +172,59 @@ impl From<DateTime> for icu::calendar::DateTime<icu::calendar::Gregorian> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
fn reftime() -> DateTime {
|
||||||
fn it_formats_a_time_according_to_locale() {
|
NaiveDate::from_ymd_opt(2006, 1, 2)
|
||||||
let l10n = L10N::default();
|
|
||||||
|
|
||||||
let now = NaiveDate::from_ymd_opt(2006, 1, 2)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_hms_opt(3, 4, 5)
|
.and_hms_opt(3, 4, 5)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.and_local_timezone(Tz::UTC)
|
.and_local_timezone(Tz::US__Mountain)
|
||||||
.unwrap()
|
.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
|
// 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
|
// particular to ensure that the am/pm marker doesn't get split off from the time
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
l10n.format_date_time_tz(now, length::Date::Long, length::Time::Medium),
|
l10n.format_date_time_utc(now.clone(), length::Date::Long, length::Time::Medium),
|
||||||
"January 2, 2006, 3:04:05\u{202f}AM"
|
"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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue