Skip to content

Commit

Permalink
Locales and format_localized (chronotope#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
cecton authored and pickfire committed Jan 22, 2022
1 parent 302be8c commit 0551dbb
Show file tree
Hide file tree
Showing 11 changed files with 448 additions and 53 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Ben Boeckel <[email protected]>
Ben Eills <[email protected]>
Brandon W Maister <[email protected]>
Brandon W Maister <[email protected]>
Cecile Tonglet <[email protected]>
Colin Ray <[email protected]>
Corey Farwell <[email protected]>
Dan <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Versions with only mechanical changes will be omitted from the following list.

* Add day and week iterators for `NaiveDate` (@gnzlbg & @robyoung)
* Add a `Month` enum (@hhamana)
* Add `locales`. All format functions can now use locales.

### Improvements

Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ alloc = []
std = []
clock = ["time", "std"]
wasmbind = ["wasm-bindgen", "js-sys"]
unstable-locales = ["pure-rust-locales", "alloc"]
__internal_bench = []
__doctest = []

Expand All @@ -38,6 +39,7 @@ num-integer = { version = "0.1.36", default-features = false }
num-traits = { version = "0.2", default-features = false }
rustc-serialize = { version = "0.3.20", optional = true }
serde = { version = "1.0.99", default-features = false, optional = true }
pure-rust-locales = { version = "0.5.2", optional = true }

[target.'cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))'.dependencies]
wasm-bindgen = { version = "0.2", optional = true }
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ Default features:
Optional features:

- `wasmbind`: Enable integration with [wasm-bindgen][] and its `js-sys` project
- [`serde`][]: Enable
- [`serde`][]: Enable serialization/deserialization via serde.
- `unstable-locales`: Enable localization. This adds various methods with a
`_localized` suffix. The implementation and API may change or even be
removed in a patch release. Feedback welcome.

[`serde`]: https://github.com/serde-rs/serde
[wasm-bindgen]: https://github.com/rustwasm/wasm-bindgen
Expand Down Expand Up @@ -225,12 +228,23 @@ Chrono also provides [`to_rfc2822`](https://docs.rs/chrono/0.4/chrono/struct.Dat
[`to_rfc3339`](https://docs.rs/chrono/0.4/chrono/struct.DateTime.html#method.to_rfc3339) methods
for well-known formats.

Chrono now also provides date formatting in almost any language without the
help of an additional C library. This functionality is under the feature
`unstable-locales`:

```text
chrono { version = "0.4", features = ["unstable-locales"]
```

The `unstable-locales` feature requires and implies at least the `alloc` feature.

```rust
use chrono::prelude::*;

let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9);
assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09");
assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014");
assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09");
assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string());

assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
Expand Down
4 changes: 2 additions & 2 deletions ci/github.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -euo pipefail
source "${BASH_SOURCE[0]%/*}/_shlib.sh"

TEST_TZS=(ACST-9:30 EST4 UTC0 Asia/Katmandu)
FEATURES=(std serde clock "alloc serde")
FEATURES=(std serde clock "alloc serde" unstable-locales)
RUST_113_FEATURES=(rustc-serialize serde)

main() {
Expand Down Expand Up @@ -56,7 +56,7 @@ test_all_tzs() {
test_regular() {
tz="$1" && shift

runt env TZ="$tz" cargo test --features __doctest --color=always -- --color=always
runt env TZ="$tz" cargo test --features __doctest,unstable-locales --color=always -- --color=always
for feature in "${FEATURES[@]}"; do
runt env TZ="$tz" cargo test --no-default-features --features "$feature" --lib --color=always -- --color=always
done
Expand Down
36 changes: 36 additions & 0 deletions src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use core::ops::{Add, Sub};
use core::{fmt, hash};
use oldtime::Duration as OldDuration;

#[cfg(feature = "unstable-locales")]
use format::Locale;
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::{DelayedFormat, Item, StrftimeItems};
use naive::{self, IsoWeek, NaiveDate, NaiveTime};
Expand Down Expand Up @@ -295,6 +297,40 @@ where
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
}

/// Formats the date with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
#[inline]
pub fn format_localized_with_items<'a, I, B>(
&self,
items: I,
locale: Locale,
) -> DelayedFormat<I>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
DelayedFormat::new_with_offset_and_locale(
Some(self.naive_local()),
None,
&self.offset,
items,
locale,
)
}

/// Formats the date with the specified format string and locale.
/// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences.
#[cfg(feature = "unstable-locales")]
#[inline]
pub fn format_localized<'a>(
&self,
fmt: &'a str,
locale: Locale,
) -> DelayedFormat<StrftimeItems<'a>> {
self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
}
}

impl<Tz: TimeZone> Datelike for Date<Tz> {
Expand Down
37 changes: 37 additions & 0 deletions src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use std::string::ToString;
use core::borrow::Borrow;
#[cfg(any(feature = "alloc", feature = "std", test))]
use format::DelayedFormat;
#[cfg(feature = "unstable-locales")]
use format::Locale;
use format::{parse, ParseError, ParseResult, Parsed, StrftimeItems};
use format::{Fixed, Item};
use naive::{self, IsoWeek, NaiveDateTime, NaiveTime};
Expand Down Expand Up @@ -493,6 +495,41 @@ where
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
}

/// Formats the combined date and time with the specified formatting items and locale.
#[cfg(feature = "unstable-locales")]
#[inline]
pub fn format_localized_with_items<'a, I, B>(
&self,
items: I,
locale: Locale,
) -> DelayedFormat<I>
where
I: Iterator<Item = B> + Clone,
B: Borrow<Item<'a>>,
{
let local = self.naive_local();
DelayedFormat::new_with_offset_and_locale(
Some(local.date()),
Some(local.time()),
&self.offset,
items,
locale,
)
}

/// Formats the combined date and time with the specified format string and locale.
/// See the [`format::strftime` module](./format/strftime/index.html)
/// on the supported escape sequences.
#[cfg(feature = "unstable-locales")]
#[inline]
pub fn format_localized<'a>(
&self,
fmt: &'a str,
locale: Locale,
) -> DelayedFormat<StrftimeItems<'a>> {
self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
}
}

impl<Tz: TimeZone> Datelike for DateTime<Tz> {
Expand Down
33 changes: 33 additions & 0 deletions src/format/locales.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use pure_rust_locales::{locale_match, Locale};

pub(crate) fn short_months(locale: Locale) -> &'static [&'static str] {
locale_match!(locale => LC_TIME::ABMON)
}

pub(crate) fn long_months(locale: Locale) -> &'static [&'static str] {
locale_match!(locale => LC_TIME::MON)
}

pub(crate) fn short_weekdays(locale: Locale) -> &'static [&'static str] {
locale_match!(locale => LC_TIME::ABDAY)
}

pub(crate) fn long_weekdays(locale: Locale) -> &'static [&'static str] {
locale_match!(locale => LC_TIME::DAY)
}

pub(crate) fn am_pm(locale: Locale) -> &'static [&'static str] {
locale_match!(locale => LC_TIME::AM_PM)
}

pub(crate) fn d_fmt(locale: Locale) -> &'static str {
locale_match!(locale => LC_TIME::D_FMT)
}

pub(crate) fn d_t_fmt(locale: Locale) -> &'static str {
locale_match!(locale => LC_TIME::D_T_FMT)
}

pub(crate) fn t_fmt(locale: Locale) -> &'static str {
locale_match!(locale => LC_TIME::T_FMT)
}
Loading

0 comments on commit 0551dbb

Please sign in to comment.