Use the time crate for modern, type-safe timestamp handling by leveraging its OffsetDateTime type for local time and PrimitiveDateTime for UTC, then format or parse strings using the format_description module. Unlike the older chrono crate, time avoids many common pitfalls like ambiguous timezone conversions and provides compile-time format validation.
Add the dependency to your Cargo.toml:
[dependencies]
time = { version = "0.3", features = ["formatting", "parsing", "macros"] }
Here is a practical example showing how to get the current time, format it, and parse a string back into a timestamp:
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
fn main() {
// Get current time in the system's local timezone
let now = OffsetDateTime::now_local().unwrap();
// Format to a human-readable string using a format description
let formatted = now.format(&time::macros::format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour]:[offset_minute]"
)).unwrap();
println!("Current time: {}", formatted);
// Parse a string back into an OffsetDateTime
let input = "2023-10-27T10:00:00+00:00";
let parsed: OffsetDateTime = input.parse().unwrap(); // Uses Rfc3339 by default for &str
// Convert to UTC explicitly if needed
let utc = parsed.to_offset(time::UtcOffset::UTC);
println!("Parsed UTC: {}", utc);
}
For more complex formatting or parsing where you need specific patterns, define a FormatDescription once and reuse it. The macros feature is highly recommended as it allows you to write format strings that are checked at compile time, preventing runtime errors from typos in your format specifiers. If you need to work with Unix timestamps, use OffsetDateTime::from_unix_timestamp(seconds) or to_unix_timestamp() methods, which return a Result to handle overflow cases safely.
Remember that OffsetDateTime includes the timezone offset, making it the safest choice for most application logic. If you strictly need UTC without offset data, use PrimitiveDateTime combined with UtcOffset::UTC. Avoid mixing time with chrono in the same project unless absolutely necessary, as their types are not interoperable and conversion requires manual implementation.