Trying to understand how date works in Rust. Specifically how to get the current local date, and how to manually display a date in a particular format. In the process, we'll touch on two different external date, time crates: time
and chrono
. We'll also look at how to enable crates' features which are disabled by default.
As of the time of writing this post, the 2nd of September, 2023, my Rust “experience” is about 40 (forty) days, and less than 8 (eight) hours a day 😂. This post is intended as a recording of problems which I've come across rather than anything else.
“The book” does not discuss date, time. However, after finishing it, I was under the impression that date, time in Rust is fully the responsibilities of the standard library. Date, time are a complicated business. Coming to any new language, I'm sure we all set aside sometimes to study how date, time work. My first attempt is to get the current local date, and display it in the Australian format, i.e.: dd/mm/yyyy
. E.g.: 02/09/2023
.
I expected it to be straight forward like other languages which I'm used to. But it is not... After some searching, it seems that there're at least one (1) module and two (2) different crates which deal with date, time:
- Module std::time -- it's part of the standard library. It seems that this module provides system time functionalities, which we can use for tasks such as measuring performance and etc.
-
Crate time -- appears to be an external crate, to use it we need to add it to the
[dependencies]
section of theCargo.toml
file. - Crate chrono -- is also an external crate.
The above two (2) crates come up as the first results in the searches that I did. It would seem that chrono
is also one of the popular, most used one. Presently, I don't know which one is the one to use -- it does not make sense to use both in a single application?
Please note, example codes in this post have been tested on both Windows 10 and Ubuntu 22.10. For simplicity, I do not do proper error handling, the codes are simple, they should always run successfully anyway.
First, I started looking at date formatting, eventually, I was pointed to crate time's parse(...) method -- note the line:
Available on crate feature
parsing
only.
And the example given:
let format = format_description!("[year]-[month]-[day]");
assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020 - 01 - 02));
This example uses two (2) macros: time::macros::format_description and time::macros::date. On macro time::macros::format_description's documentation, I find the following statement a bit confusing:
Available on crate feature
macros
and (crate featuresformatting
orparsing
) only.
This statement seems to suggest that if we only want to use the parse(...) method and time::macros::format_description, the crate feature parsing
alone would suffice? But that is not the case, the crate feature macros
is also required.
And in the Feature flags section of crate time:
This crate exposes a number of features. These can be enabled or disabled as shown in Cargo’s documentation. Features are disabled by default unless otherwise noted.
What that means is, to use this time crate's above functionalities, we need to include it in the Cargo.toml
file as follows:
...
[dependencies]
time = { version = "0.3.22", default-features = false, features = ["parsing", "macros"] }
And below is the complete working version of the above example.
Content of src/main.rs:
use time::error::Parse;
use time::Date;
use time::macros::{date, format_description};
fn main() -> Result<(), Parse> {
let format = format_description!("[year]-[month]-[day]");
assert_eq!(Date::parse("2020-01-02", &format)?, date!(2020 - 01 - 02));
Ok(())
}
To format dates, we can use the format(...) method, which in turn requires the formatting
crate feature. The Cargo.toml
file gets updated as follows:
...
[dependencies]
time = { version = "0.3.22", default-features = false, features = ["formatting", "macros", "parsing"] }
And following is the format example I've come up with:
use time::macros::{date, format_description};
fn main() {
let format = format_description!("[day]/[month]/[year]");
let str = date!(2020 - 01 - 02).format(&format).unwrap();
println!("[day]/[month]/[year] 2020 - 01 - 02: {}", str);
}
Next, to get the current local date. We need struct time::OffsetDateTime's now_local() method, and this requires crate feature local-offset
enabled:
...
[dependencies]
time = { version = "0.3.22", default-features = false, features = ["formatting", "macros", "parsing", "local-offset"] }
And below is my learning example:
use time::OffsetDateTime;
use time::macros::format_description;
fn main() {
assert!(OffsetDateTime::now_local().is_ok());
println!("{:#?}", OffsetDateTime::now_local());
let format = format_description!("[day]/[month]/[year]");
let str = OffsetDateTime::now_local().unwrap().date().format(&format).unwrap();
println!("[day]/[month]/[year]: {}", str);
}
Crate chrono seems to be a bit simpler, to get the current local date and display it in the Australian format, we don't have to enable any crate features. Just include the crate:
...
[dependencies]
chrono = "0.4.27"
And below is my learning example code:
use chrono::offset::Local;
fn main() {
let date_time = Local::now();
let str = format!("{}", date_time.format("%d/%m/%Y"));
println!("%d/%m/%Y: {}", str);
}
This is my first step looking at date in Rust. I've run a lot of the example code from the two crates' documentations, too. Presently, I still don't have a clear understanding of the relationship between crate time and crate chrono -- or even if there's a relationship at all? Both seem to be comprehensive. I don't know when to use which, or just one is enough... I'm guessing, these questions will have their own answers as we go along the Rust journey.
I'm happy with what I've learned in the process of writing this post. Thank you for reading... I do hope this post would help people who're new to Rust like myself. Stay safe as always.
✿✿✿
Feature image source:
Top comments (0)