Expand description
DateTime (DTT) is a comprehensive library for date and time manipulation.
§Overview
This crate provides robust tools for handling dates, times, and timezones in Rust, with a focus on correctness, ergonomics, and performance.
§Features
- Create and parse dates in multiple formats
- Timezone conversions and handling
- Date and time arithmetic
- Formatting and serialization
§Error Handling
This crate uses the thiserror crate for error handling. All errors are
properly typed and implement standard error traits. Operations that may fail
return Result<T, AppError>.
§Examples
use dtt::DateTime;
let now = DateTime::new();
println!("Current time: {}", now);
DateTime (DTT)
An ergonomic Rust library for parsing, validating, manipulating, and formatting dates, times, and timezones — with guaranteed round-trip safety and unambiguous timezone codes.
§Table of Contents
- Install
- Quick Start
- Why DTT?
- Features
- Supported Timezone Abbreviations
- API Highlights
- Development
- Troubleshooting
- Documentation
- Contributing
- License
§Install
cargo add dttOr add to Cargo.toml:
[dependencies]
dtt = "0.0.10"§Prerequisites
DTT requires Rust 1.88.0 or later (pinned by time = 0.3.47, which carries the upstream fix for RUSTSEC stack-exhaustion DoS in time < 0.3.47).
| Platform | Setup |
|---|---|
| macOS | brew install rustup-init && rustup-init -y |
| Linux | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y |
| WSL | Same as Linux, run inside your WSL distribution |
| Windows | Download rustup-init.exe from rustup.rs |
After install, verify with rustc --version (must be ≥ 1.88.0). Upgrade an existing toolchain with rustup update stable.
§Quick Start
use dtt::prelude::*;
fn main() -> Result<(), AppError> {
// Current UTC time
let now = DateTime::new();
println!("Current time: {}", now);
// Parse — strict, offset-required for time-bearing inputs
let parsed = DateTime::parse("2024-01-15T10:30:00Z")?;
println!("Parsed: {}", parsed);
// Round-trip is guaranteed: parse(format(x)) == x
let s = parsed.format_rfc3339()?;
assert_eq!(parsed, DateTime::parse(&s)?);
// Arithmetic
let next_week = parsed.add_days(7)?;
let next_year = parsed.add_years(1)?;
println!("Next week: {next_week}, next year: {next_year}");
// Timezone conversion (note the explicit USA suffix)
let est = parsed.convert_to_tz("EST_USA")?;
println!("In US Eastern: {est}");
// Validation
assert!(DateTime::is_valid_iso_8601("2024-01-15T10:30:00Z"));
assert!(!DateTime::is_valid_year("10000")); // outside time crate range
Ok(())
}Run the full demo:
cargo run --example dtt§Why DTT?
Most datetime libraries silently produce wrong answers in surprising places. DTT is designed to fail loudly rather than guess:
- Round-trip safety:
DateTime::parse(&dt.format_rfc3339()?)? == dtalways holds. No silent date-only truncation. - Unambiguous timezones:
ISTcould mean Indian (+05:30), Irish (+01:00), or Israel (+02:00). DTT requires explicit suffixes (IST_INDIA,IST_IRELAND,IST_ISRAEL) so you cannot accidentally use the wrong one. - Mixed-sign offsets rejected:
new_with_custom_offset(5, -30)returns an error instead of silently producing+05:30. - Deterministic
Default:DateTime::default()returns the Unix epoch, not wall-clock time, so tests are reproducible. - UTC-normalised equality: Two
DateTimevalues that represent the same instant compare equal regardless of which offset they were stored in. - Strict validation:
is_valid_yearis bounded to the actualtime::Daterange (-9999..=9999), so the validator and the builder always agree.
§Features
| Parsing | RFC 3339 with offset, ISO 8601 date-only, custom format strings |
| Formatting | RFC 3339, custom format descriptors |
| Validation | Components, ranges, leap years, ISO 8601, time strings |
| Arithmetic | add_days, add_months, add_years (overflow-checked) |
| Comparisons | Eq, Ord, Hash — all UTC-normalised |
| Calendar helpers | start_of_week, end_of_month, iso_week, iso_year |
| Timezone support | 22 disambiguated abbreviations + custom offsets |
| Serialization | serde round-trip via canonical RFC 3339 strings |
| Cross-platform | macOS, Linux, WSL, Windows |
§Supported Timezone Abbreviations
Common abbreviations are intentionally disambiguated. Bare codes like EST, CST, IST, and WADT are not accepted because they refer to multiple zones in the real world.
| Code | Offset | Region |
|---|---|---|
UTC, GMT | +00:00 | Coordinated Universal Time |
EST_USA | −05:00 | US Eastern Standard Time |
EDT | −04:00 | US Eastern Daylight Time |
CST_USA | −06:00 | US Central Standard Time |
CDT | −05:00 | US Central Daylight Time |
MST / MDT | −07/−06 | US Mountain |
PST / PDT | −08/−07 | US Pacific |
CET / CEST | +01/+02 | Central Europe |
EET / EEST | +02/+03 | Eastern Europe |
IST_IRELAND | +01:00 | Irish Standard Time |
IST_ISRAEL | +02:00 | Israel Standard Time |
IST_INDIA | +05:30 | Indian Standard Time |
JST | +09:00 | Japan |
HKT | +08:00 | Hong Kong |
CST_CHINA | +08:00 | China Standard Time |
EST_AUS / AEST | +10:00 | Australian Eastern |
AEDT | +11:00 | Australian Eastern Daylight |
ACWST | +08:45 | Australian Central Western |
For any other zone, use DateTime::new_with_custom_offset(hours, minutes).
Note: DST is not handled automatically. Pick the appropriate code (e.g.
EDTvsEST_USA) for the date range you care about.
§API Highlights
§Construction
use dtt::prelude::*;
use time::UtcOffset;
let now = DateTime::new(); // current UTC
let utc = DateTime::new_with_tz("UTC")?; // explicit
let mumbai = DateTime::new_with_tz("IST_INDIA")?; // disambiguated
let custom = DateTime::new_with_custom_offset(5, 30)?; // +05:30
let exact = DateTime::from_components(2024, 1, 15, 10, 30, 0, UtcOffset::UTC)?;
let epoch = DateTime::default(); // 1970-01-01T00:00:00Z
// Builder pattern
let dt = DateTimeBuilder::new()
.year(2024).month(1).day(15)
.hour(10).minute(30).second(0)
.offset(UtcOffset::UTC)
.build()?;§Parsing & Formatting
let dt1 = DateTime::parse("2024-01-15T10:30:00Z")?;
let dt2 = DateTime::parse("2024-01-15T10:30:00+05:30")?;
let dt3 = DateTime::parse("2024-01-15")?; // date-only OK
let custom = DateTime::parse_custom_format(
"15/01/2024 10:30",
"[day]/[month]/[year] [hour]:[minute]",
)?;
let s: String = dt1.format_rfc3339()?;
let pretty = dt1.format("[year]-[month]-[day]")?;§Arithmetic & Calendar Math
let dt = DateTime::parse("2024-01-31T00:00:00Z")?;
let next_day = dt.next_day()?;
let prev_day = dt.previous_day()?;
let next_week = dt.add_days(7)?;
let next_feb = dt.add_months(1)?; // → 2024-02-29 (leap year aware)
let next_year = dt.add_years(1)?;
let monday = dt.start_of_week()?;
let sunday = dt.end_of_week()?;
let last_day = dt.end_of_month()?;§Macros
use dtt::prelude::*;
use dtt::{dtt_now, dtt_parse, dtt_add_days, dtt_diff, dtt_diff_seconds};
let now = dtt_now!();
let dt = dtt_parse!("2024-01-15T10:30:00Z")?;
let later = dtt_add_days!(dt, 7)?;
let secs: Option<i64> = dtt_diff_seconds!("1609459200", "1609459230");
assert_eq!(secs, Some(30));§Development
Clone, build, and verify in under a minute on any platform:
git clone https://github.com/sebastienrousseau/dtt.git
cd dtt
make verify # fmt-check + lint + test in one command
make help # full task listThe Makefile is a thin wrapper around the underlying Cargo commands,
so the equivalent direct invocations also work:
cargo build # build the library and binary
cargo test # run all 240+ tests
cargo clippy --all-targets -- -D warnings # lint with strict warnings
cargo fmt --check # verify formatting
cargo doc --no-deps --open # open API docs in your browser
cargo run --example dtt # run the end-to-end demo
cargo bench # run criterion benchmarksAll commands work identically on macOS, Linux, and WSL. CI exercises
the same matrix on Linux, macOS, and Windows on every PR via
.github/workflows/cross-platform.yml.
§Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
feature 'edition2024' is required from time-core | Rust < 1.88.0 | rustup update stable |
Err(InvalidTimezone) for "EST", "CST", "IST" | Bare ambiguous codes are rejected by design | Use a suffixed form (e.g. EST_USA, IST_INDIA) |
Err(InvalidFormat) parsing "2024-01-01T12:00:00" | RFC 3339 requires an offset | Append Z or +HH:MM |
Err(InvalidTimezone) from new_with_custom_offset(5, -30) | Mixed-sign offsets are rejected | Pass same-sign components, e.g. (4, 30) |
Err(InvalidDate) from from_components(10000, ...) | time::Date only supports -9999..=9999 | Use a year inside that range |
| Tests fail with environment-variable race | cargo test runs tests in parallel | Already mitigated via serial_test; use cargo test -- --test-threads=1 if you have a custom env-var test |
§Documentation
- API reference: https://docs.rs/dtt
- End-to-end example:
examples/dtt.rs - Benchmarks:
benches/criterion.rs— run withcargo bench - Changelog:
CHANGELOG.md - Security policy:
.github/SECURITY.md - Code of conduct:
.github/CODE-OF-CONDUCT.md
§Contributing
Contributions are welcome. Please read CONTRIBUTING.md — in particular, all commits must be cryptographically signed (git commit -S).
Quick checklist before opening a PR:
cargo fmt
cargo clippy --all-targets -- -D warnings
cargo test
git commit -S -m "feat(dtt): your conventional commit message"THE ARCHITECT ᴬ Sebastien Rousseau THE ENGINE ᵞ EUXIS ᴬ Enterprise Unified Execution Intelligence System
§License
Dual-licensed under Apache 2.0 or MIT, at your option.
Modules§
- constants
- Library constants and configuration values
- datetime
- Core datetime functionality and operations.
- error
- Error handling types and implementations.
- macros
- Macro definitions for common operations.
- prelude
- Commonly used types and traits.
Macros§
- dtt_
add_ days - Adds the specified number of days to the given
DateTimeinstance. - dtt_
assert - Asserts that the given expression is true.
- dtt_
clone - Creates a copy of the provided
DateTimeobject. - dtt_
diff - A helper macro to calculate the difference between two
DateTimeinstances. - dtt_
diff_ days - Calculates the difference in days between two
DateTimeinstances. - dtt_
diff_ seconds - Calculates the difference in seconds between two
DateTimeinstances. - dtt_
format - Formats a
DateTimeobject using the provided format string. - dtt_
is_ valid_ function - Generates a function that validates a given input string based on a specified type.
- dtt_
join - Joins multiple strings into a single string.
- dtt_map
- Creates a new map of the given key-value pairs.
- dtt_max
- Returns the maximum of the given values.
- dtt_min
- Returns the minimum of the given values.
- dtt_
new_ with_ tz - Creates a new
DateTimeinstance with the specified timezone. - dtt_now
- Creates a new
DateTimeinstance with the current date and time in UTC. - dtt_
parse - Prints the arguments to the console.
- dtt_
print - Prints the arguments to the console.
- dtt_
print_ vec - Prints a vector of elements to the console.
- dtt_
sub_ days - Subtracts the specified number of days from the given
DateTimeinstance. - dtt_vec
- Creates a new vector of the given elements.
- is_
valid - Generates a function that validates a given input string based on a specified type.
Structs§
- Date
Time - Represents a date and time with timezone offset support.
Enums§
- AppError
- Custom error type for the application.
Functions§
- run
- Runs the main library functionality with proper error handling.