Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DateTimeFormat #202

Merged
merged 15 commits into from
Oct 2, 2020
Merged
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ members = [
"components/locale",
"components/num-util",
"components/pluralrules",
"components/datetime",
]
34 changes: 34 additions & 0 deletions components/datetime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "icu-datetime"
description = "API for managing Unicode Language and Locale Identifiers"
version = "0.0.1"
authors = ["The ICU4X Project Developers"]
edition = "2018"
readme = "README.md"
repository = "https://github.com/unicode-org/icu4x"
license-file = "../../LICENSE"
categories = ["internationalization"]
include = [
"src/**/*",
"Cargo.toml",
"README.md"
]

[dependencies]
icu-locale = { path = "../locale" }
icu-data-provider = { path = "../data-provider" }

[dev-dependencies]
criterion = "0.3"
icu-data-provider = { path = "../data-provider", features = ["invariant"] }
icu-fs-data-provider = { path = "../fs-data-provider" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[[bench]]
name = "datetime"
harness = false

[[bench]]
name = "pattern"
harness = false
119 changes: 119 additions & 0 deletions components/datetime/benches/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
mod fixtures;

use criterion::{criterion_group, criterion_main, Criterion};
use std::fmt::Write;

use icu_datetime::DateTimeFormat;
use icu_fs_data_provider::FsDataProvider;

fn datetime_benches(c: &mut Criterion) {
let fxs = fixtures::get_fixture("styles").unwrap();

let provider = FsDataProvider::try_new("./tests/fixtures/data/icu4x")
.expect("Loading file from testdata directory");

{
let mut group = c.benchmark_group("datetime");

group.bench_function("DateTimeFormat/format_to_write", |b| {
b.iter(|| {
for fx in &fxs.0 {
let datetimes: Vec<_> = fx
.values
.iter()
.map(|value| fixtures::parse_date(value).unwrap())
.collect();

for setup in &fx.setups {
let langid = setup.locale.parse().unwrap();
let options = fixtures::get_options(&setup.options);
let dtf = DateTimeFormat::try_new(langid, &provider, &options).unwrap();

let mut result = String::new();

for dt in &datetimes {
let _ = dtf.format_to_write(&mut result, dt);
result.clear();
}
}
}
})
});

group.bench_function("DateTimeFormat/format_to_string", |b| {
b.iter(|| {
for fx in &fxs.0 {
let datetimes: Vec<_> = fx
.values
.iter()
.map(|value| fixtures::parse_date(value).unwrap())
.collect();

for setup in &fx.setups {
let langid = setup.locale.parse().unwrap();
let options = fixtures::get_options(&setup.options);
let dtf = DateTimeFormat::try_new(langid, &provider, &options).unwrap();

for dt in &datetimes {
let _ = dtf.format_to_string(dt);
}
}
}
})
});

group.bench_function("FormattedDateTime/format", |b| {
b.iter(|| {
for fx in &fxs.0 {
let datetimes: Vec<_> = fx
.values
.iter()
.map(|value| fixtures::parse_date(value).unwrap())
.collect();

for setup in &fx.setups {
let langid = setup.locale.parse().unwrap();
let options = fixtures::get_options(&setup.options);
let dtf = DateTimeFormat::try_new(langid, &provider, &options).unwrap();

let mut result = String::new();

for dt in &datetimes {
let fdt = dtf.format(dt);
write!(result, "{}", fdt).unwrap();
result.clear();
}
}
}
})
});

group.bench_function("FormattedDateTime/to_string", |b| {
b.iter(|| {
for fx in &fxs.0 {
let datetimes: Vec<_> = fx
.values
.iter()
.map(|value| fixtures::parse_date(value).unwrap())
.collect();

for setup in &fx.setups {
let langid = setup.locale.parse().unwrap();
let options = fixtures::get_options(&setup.options);
let dtf = DateTimeFormat::try_new(langid, &provider, &options).unwrap();

for dt in &datetimes {
let fdt = dtf.format(dt);
let _ = fdt.to_string();
}
}
}
})
});

group.finish();
}
}

criterion_group!(benches, datetime_benches,);
criterion_main!(benches);
62 changes: 62 additions & 0 deletions components/datetime/benches/fixtures/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
pub mod structs;

use icu_datetime::options::{style, DateTimeFormatOptions};
use icu_datetime::DummyDateTime;
use std::fs::File;
use std::io::BufReader;

#[allow(dead_code)]
pub fn get_fixture(name: &str) -> std::io::Result<structs::Fixture> {
let file = File::open(format!("./benches/fixtures/tests/{}.json", name))?;
let reader = BufReader::new(file);

Ok(serde_json::from_reader(reader)?)
}

#[allow(dead_code)]
pub fn get_patterns_fixture() -> std::io::Result<structs::PatternsFixture> {
let file = File::open("./benches/fixtures/tests/patterns.json")?;
let reader = BufReader::new(file);

Ok(serde_json::from_reader(reader)?)
}

#[allow(dead_code)]
pub fn get_options(input: &structs::TestOptions) -> DateTimeFormatOptions {
let style = style::Bag {
date: input.style.date.as_ref().map(|date| match date {
structs::TestStyleWidth::Full => style::Date::Full,
structs::TestStyleWidth::Long => style::Date::Long,
structs::TestStyleWidth::Medium => style::Date::Medium,
structs::TestStyleWidth::Short => style::Date::Short,
}),
time: input.style.time.as_ref().map(|time| match time {
structs::TestStyleWidth::Full => style::Time::Full,
structs::TestStyleWidth::Long => style::Time::Long,
structs::TestStyleWidth::Medium => style::Time::Medium,
structs::TestStyleWidth::Short => style::Time::Short,
}),
..Default::default()
};
style.into()
}

#[allow(dead_code)]
pub fn parse_date(input: &str) -> Result<DummyDateTime, std::num::ParseIntError> {
let year: usize = input[0..4].parse()?;
let month: usize = input[5..7].parse()?;
let day: usize = input[8..10].parse()?;
let hour: usize = input[11..13].parse()?;
let minute: usize = input[14..16].parse()?;
let second: usize = input[17..19].parse()?;
let millisecond: usize = input[20..23].parse()?;
Ok(DummyDateTime {
year,
month: month - 1,
day: day - 1,
hour,
minute,
second,
millisecond,
})
}
42 changes: 42 additions & 0 deletions components/datetime/benches/fixtures/structs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Fixture(pub Vec<Test>);

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Test {
pub setups: Vec<TestInput>,
pub values: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TestInput {
pub locale: String,
pub options: TestOptions,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TestOptions {
pub style: TestOptionsStyle,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TestOptionsStyle {
pub date: Option<TestStyleWidth>,
pub time: Option<TestStyleWidth>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TestStyleWidth {
#[serde(rename = "short")]
Short,
#[serde(rename = "medium")]
Medium,
#[serde(rename = "long")]
Long,
#[serde(rename = "full")]
Full,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PatternsFixture(pub Vec<String>);
24 changes: 24 additions & 0 deletions components/datetime/benches/fixtures/tests/patterns.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
"dd/MM/y",
"dd/MM",
"d MMM",
"d MMM y",
"MMMM y",
"d MMMM",
"HH:mm:ss",
"HH:mm",
"y",
"mm:ss",
"h:mm:ss B",
"E, h:mm B",
"E, h:mm:ss B",
"E d",
"E h:mm a",
"y G",
"MMM y G",
"dd/MM",
"E, dd/MM",
"LLL",
"E, d MMM y",
"E, dd/MM/y"
sffc marked this conversation as resolved.
Show resolved Hide resolved
]
Loading