From 82c63e5b40ffcfee58e3a1bc549c0a2e8fdac05e Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Thu, 5 Feb 2015 02:37:54 +0900 Subject: [PATCH] 0.2.0-dev: date/time parsing. Basically, this should close #12 when officially released. - Formatting syntax is now refactored out of the rendering logic. The main syntax is available in the `format::strftime` module, which also serves as a documentation for the syntax. - A parser (modelled after `strptime(3)`) has been implemented. See the individual commits for the detailed implementation. - There are two ways to get a timezone-aware value from a string: `Offset` or `DateTime`. The former should be used when the offset is known in advance (e.g. assume the local date) while the latter should be used when the offset is unknown. Naive types have a simple `from_str` method. - There are some known problems with the parser (even after tons of tests), which will be sorted out in 0.2. Known issues: - This does not exactly handle RFC 2822 and RFC 3339, which subtly differs from the current implementation in case-sensitivity, whitespace handling and legacy syntax. I'd like to integrate #24 for this cause. - Time zone names are not recognized at all. There is even no means to get a name itself, not sure about the resolution. - `Parsed` does *not* constrain `year` to be non-negative, so manually prepared `Parsed` may give a negative year. But the current verification pass may break such cases. - I absolutely don't know about the parser's performance! - `AUTHORS.txt` has been added, for what it's worth. --- AUTHORS.txt | 9 +++++++++ Cargo.toml | 2 +- Makefile | 11 +++++++++++ README.md | 36 +++++++++++++++++++++++++++++++++--- src/format/strftime.rs | 4 ++-- src/lib.rs | 34 ++++++++++++++++++++++++++++++++-- 6 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 AUTHORS.txt create mode 100644 Makefile diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 0000000..9cff58b --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,9 @@ +Chrono is mainly written by Kang Seonghoon , +and also the following people (in ascending order): + +Colin Ray +David Ross +Eunchong Yu +Ken Tossell +Steve Klabnik +klutzy diff --git a/Cargo.toml b/Cargo.toml index a471ec8..4401441 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chrono" -version = "0.1.17" +version = "0.2.0-dev" authors = ["Kang Seonghoon "] description = "Date and time library for Rust" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ea04ef4 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +.PHONY: all +all: + @echo 'Try `cargo build` instead.' + +.PHONY: authors +authors: + echo 'Chrono is mainly written by Kang Seonghoon ,' > AUTHORS.txt + echo 'and also the following people (in ascending order):' >> AUTHORS.txt + echo >> AUTHORS.txt + git log --format='%aN <%aE>' | grep -v 'Kang Seonghoon' | sort -u >> AUTHORS.txt + diff --git a/README.md b/README.md index b7b4b4d..c7fd450 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[Chrono][doc] 0.1.17 -==================== +[Chrono][doc] 0.2.0-dev +======================= [![Chrono on Travis CI][travis-image]][travis] @@ -115,6 +115,7 @@ assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_00 Formatting is done via the `format` method, which format is equivalent to the familiar `strftime` format. +(See the `format::strftime` module documentation for full syntax.) The default `to_string` method and `{:?}` specifier also give a reasonable representation. ~~~~ {.rust} @@ -129,6 +130,35 @@ assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); ~~~~ +Parsing can be done with two methods: + +- `DateTime::from_str` parses a date and time with offsets and returns `DateTime`. + This should be used when the offset is a part of input and the caller cannot guess that. + It *cannot* be used when the offset can be missing. + +- `Offset::datetime_from_str` is similar but returns `DateTime` of given offset. + When the explicit offset is missing from the input, it simply uses given offset. + It issues an error when the input contains an explicit offset different from the current offset. + +More detailed control over the parsing process is available via `format` module. + +~~~~ {.rust} +use chrono::{UTC, Offset, DateTime}; + +let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9); +assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone())); +assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone())); +assert_eq!(DateTime::from_str("2014-11-28 21:00:09 +09:00", + "%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_offset(UTC)), Ok(dt)); + +// oops, the year is missing! +assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err()); +// oops, the format string does not include the year at all! +assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err()); +// oops, the weekday is incorrect! +assert!(UTC.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err()); +~~~~ + ### Individual date and time Chrono also provides an individual date type (`Date`) and time type (`Time`). @@ -177,5 +207,5 @@ Any operation that can be ambiguous will return `None` in such cases. For example, "a month later" of 2014-01-30 is not well-defined and consequently `UTC.ymd(2014, 1, 30).with_month(2)` returns `None`. -Advanced offset handling and date/time parsing is not yet supported (but is planned). +Advanced offset handling is not yet supported (but is planned in 0.3). diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 0848949..797cedd 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -24,14 +24,14 @@ Spec. Example Description %m 07 Month number (01--12), zero-padded to 2 digits. %b Jul Abbreviated month name. Always 3 letters. -%B July Full month name. +%B July Full month name. Also accepts corresponding abbreviation in parsing. %h Jul Same to `%b`. %d 08 Day number (01--31), zero-padded to 2 digits. %e 8 Same to `%d` but space-padded. %a Sun Abbreviated weekday name. Always 3 letters. -%A Sunday Full weekday name. +%A Sunday Full weekday name. Also accepts corresponding abbreviation in parsing. %w 0 Sunday = 0, Monday = 1, ..., Saturday = 6. %u 7 Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601) diff --git a/src/lib.rs b/src/lib.rs index 1a0686c..cee1e14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ /*! -# Chrono 0.1.17 +# Chrono 0.2.0-dev Date and time handling for Rust. (also known as `rust-chrono`) It aims to be a feature-complete superset of the [time](https://github.com/rust-lang/time) library. @@ -116,6 +116,7 @@ assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_00 Formatting is done via the `format` method, which format is equivalent to the familiar `strftime` format. +(See the `format::strftime` module documentation for full syntax.) The default `to_string` method and `{:?}` specifier also give a reasonable representation. ~~~~ {.rust} @@ -130,6 +131,35 @@ assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); ~~~~ +Parsing can be done with two methods: + +- `DateTime::from_str` parses a date and time with offsets and returns `DateTime`. + This should be used when the offset is a part of input and the caller cannot guess that. + It *cannot* be used when the offset can be missing. + +- `Offset::datetime_from_str` is similar but returns `DateTime` of given offset. + When the explicit offset is missing from the input, it simply uses given offset. + It issues an error when the input contains an explicit offset different from the current offset. + +More detailed control over the parsing process is available via `format` module. + +~~~~ {.rust} +use chrono::{UTC, Offset, DateTime}; + +let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9); +assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone())); +assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone())); +assert_eq!(DateTime::from_str("2014-11-28 21:00:09 +09:00", + "%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_offset(UTC)), Ok(dt)); + +// oops, the year is missing! +assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err()); +// oops, the format string does not include the year at all! +assert!(UTC.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err()); +// oops, the weekday is incorrect! +assert!(UTC.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err()); +~~~~ + ### Individual date and time Chrono also provides an individual date type (`Date`) and time type (`Time`). @@ -179,7 +209,7 @@ Any operation that can be ambiguous will return `None` in such cases. For example, "a month later" of 2014-01-30 is not well-defined and consequently `UTC.ymd(2014, 1, 30).with_month(2)` returns `None`. -Advanced offset handling and date/time parsing is not yet supported (but is planned). +Advanced offset handling is not yet supported (but is planned in 0.3). */