Skip to content

Commit

Permalink
[WIP] Add DateTimeFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
zbraniecki committed Aug 20, 2020
1 parent f2d1713 commit 027dd8f
Show file tree
Hide file tree
Showing 10 changed files with 619 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ members = [
"components/locale",
"components/num-util",
"components/pluralrules",
"components/datetime",
]
24 changes: 24 additions & 0 deletions components/datetime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[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]

[dev-dependencies]
criterion = "0.3"

[[bench]]
name = "datetime"
harness = false
125 changes: 125 additions & 0 deletions components/datetime/benches/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use criterion::{criterion_group, criterion_main, Criterion};
use std::fmt::Write;

use icu_datetime::date::DateTime;
use icu_datetime::options::{DateStyle, DateTimeFormatOptions, DateTimeFormatStyle, TimeStyle};
use icu_datetime::provider::DummyDataProvider;
use icu_datetime::DateTimeFormat;

fn datetime_benches(c: &mut Criterion) {
let datetimes = vec![
DateTime::new(2001, 9, 8, 18, 46, 40),
DateTime::new(2017, 7, 13, 19, 40, 0),
DateTime::new(2020, 9, 13, 5, 26, 40),
DateTime::new(2021, 1, 6, 22, 13, 20),
DateTime::new(2021, 5, 2, 17, 0, 0),
DateTime::new(2021, 8, 26, 10, 46, 40),
DateTime::new(2021, 12, 20, 3, 33, 20),
DateTime::new(2022, 4, 14, 22, 20, 0),
DateTime::new(2022, 8, 8, 16, 6, 40),
DateTime::new(2033, 5, 17, 20, 33, 20),
];
let values = &[
("pl", DateStyle::Full, TimeStyle::None),
("pl", DateStyle::Long, TimeStyle::None),
("pl", DateStyle::Medium, TimeStyle::None),
("pl", DateStyle::Short, TimeStyle::None),
("pl", DateStyle::None, TimeStyle::Full),
("pl", DateStyle::None, TimeStyle::Long),
("pl", DateStyle::None, TimeStyle::Medium),
("pl", DateStyle::None, TimeStyle::Short),
("pl", DateStyle::Full, TimeStyle::Full),
("pl", DateStyle::Long, TimeStyle::Long),
("pl", DateStyle::Medium, TimeStyle::Medium),
("pl", DateStyle::Short, TimeStyle::Short),
];

let mut results = vec![];

for _ in 0..datetimes.len() {
results.push(String::new());
}

let dp = DummyDataProvider::default();

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

group.bench_function("DateTimeFormat/format_to_write", |b| {
b.iter(|| {
for value in values {
let options = DateTimeFormatOptions::Style(DateTimeFormatStyle {
date_style: value.1,
time_style: value.2,
..Default::default()
});
let dtf = DateTimeFormat::try_new(&dp, &options);

for (dt, result) in datetimes.iter().zip(results.iter_mut()) {
result.clear();
let _ = dtf.format_to_write(&dt, result);
}
}
})
});

group.bench_function("DateTimeFormat/format_to_string", |b| {
b.iter(|| {
for value in values {
let options = DateTimeFormatOptions::Style(DateTimeFormatStyle {
date_style: value.1,
time_style: value.2,
..Default::default()
});
let dtf = DateTimeFormat::try_new(&dp, &options);

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

group.bench_function("FormattedDateTime/format", |b| {
b.iter(|| {
for value in values {
let options = DateTimeFormatOptions::Style(DateTimeFormatStyle {
date_style: value.1,
time_style: value.2,
..Default::default()
});
let dtf = DateTimeFormat::try_new(&dp, &options);

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

group.bench_function("FormattedDateTime/to_string", |b| {
b.iter(|| {
for value in values {
let options = DateTimeFormatOptions::Style(DateTimeFormatStyle {
date_style: value.1,
time_style: value.2,
..Default::default()
});
let dtf = DateTimeFormat::try_new(&dp, &options);

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

group.finish();
}
}

criterion_group!(benches, datetime_benches,);
criterion_main!(benches);
29 changes: 29 additions & 0 deletions components/datetime/src/date.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#[derive(Default)]
pub struct DateTime {
pub year: usize,
pub month: usize,
pub day: usize,
pub hour: usize,
pub minute: usize,
pub second: usize,
}

impl DateTime {
pub fn new(
year: usize,
month: usize,
day: usize,
hour: usize,
minute: usize,
second: usize,
) -> Self {
Self {
year,
month,
day,
hour,
minute,
second,
}
}
}
55 changes: 55 additions & 0 deletions components/datetime/src/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use super::date::DateTime;
use super::pattern::{parse_pattern, Field, FieldType};
use std::fmt;

pub struct FormattedDateTime<'s> {
pub(crate) pattern: &'s str,
// fields: Vec<Field>,
pub(crate) date_time: &'s DateTime,
}

impl<'s> fmt::Display for FormattedDateTime<'s> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let fields = parse_pattern(self.pattern.as_bytes());
write_pattern(self.pattern, fields, &self.date_time, f)
}
}

fn format_number(
result: &mut impl fmt::Write,
num: usize,
two_digit: bool,
) -> Result<(), std::fmt::Error> {
if two_digit {
write!(result, "{:0>2}", num)
} else {
write!(result, "{}", num)
}
}

pub fn write_pattern<F: std::borrow::Borrow<Field>>(
pattern: &str,
fields: impl Iterator<Item = F>,
date_time: &DateTime,
f: &mut impl fmt::Write,
) -> std::fmt::Result {
let mut ptr = 0;

for field in fields {
let field = field.borrow();
if field.idx.start > ptr {
f.write_str(&pattern[ptr..field.idx.start])?;
}
match field.field_type {
FieldType::Year => format_number(f, date_time.year, false)?,
FieldType::Month => format_number(f, date_time.month, true)?,
FieldType::Day => format_number(f, date_time.day, true)?,
}
ptr = field.idx.end + 1;
}

if ptr < pattern.len() {
f.write_str(&pattern[ptr..])?;
}
Ok(())
}
49 changes: 49 additions & 0 deletions components/datetime/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pub mod date;
mod format;
pub mod options;
pub mod pattern;
pub mod provider;

use date::DateTime;
pub use format::FormattedDateTime;
use options::DateTimeFormatOptions;
use pattern::parse_pattern;
use provider::DataProviderType;

pub struct DateTimeFormat {
pattern: String,
}

impl DateTimeFormat {
pub fn try_new<D: DataProviderType>(
data_provider: &D,
options: &DateTimeFormatOptions,
) -> Self {
Self {
pattern: data_provider.get_pattern(options),
}
}

pub fn format<'l>(&'l self, value: &'l DateTime) -> FormattedDateTime<'l> {
FormattedDateTime {
pattern: &self.pattern,
// fields: parse_pattern(self.pattern.as_bytes()).collect(),
date_time: value,
}
}

pub fn format_to_write(
&self,
value: &DateTime,
w: &mut impl std::fmt::Write,
) -> std::fmt::Result {
let fields = parse_pattern(self.pattern.as_bytes());
format::write_pattern(&self.pattern, fields, &value, w)
}

pub fn format_to_string(&self, value: &DateTime) -> String {
let mut s = String::new();
self.format_to_write(value, &mut s).unwrap();
s
}
}
Loading

0 comments on commit 027dd8f

Please sign in to comment.