Rust stdt now with Date & Time management
April 18, 2026•564 words
I am pleased to announce the release of stdt version 0.0.6. In the Rust ecosystem, date and time handling is often delegated to heavyweight crates like chrono or time. While these are excellent for comprehensive production needs, there is a distinct need for lightweight, zero-dependency implementations for standard formats. Version 0.0.6 introduces stdt::date, a domain-specific module focusing on strict RFC 3339 and ISO 8601 parsing, validation, and formatting.
The Architecture
The main idea of this implementation is the separation of pure data from format context. So we have a minimal Date primitive:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Date {
pub year: i32,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
}
This struct is Copy and purely holds the temporal components. Validation and parsing logic are pushed into wrapper structs—Rfc3339 and Iso8601—which act as context providers.
RFC 3339
The Rfc3339 implementation provides a manual parser (no RegEx) for explicit string slicing. This approach reduces the footprint. It includes a semantic validator that respects calendar logic (e.g., checking for February 29th only on leap years).
Usage Example:
use stdt::date::rcf3339::Rfc3339;
let raw = "2023-11-23T14:30:05Z";
let rfc = Rfc3339::parse(raw).expect("Invalid Date");
// Custom pattern formatting without external crates
println!("{}", rfc.format("Date: dd/mm/yy Time: HH:MM"));
// Output: Date: 23/11/23 Time: 14:30
ISO 8601
The Iso8601 module steps up the complexity by handling the duality of the standard. We have
- Extended Format: 2023-11-23T14:30:00
- Basic Format: 20231123T143000 (Compact)
- Duration
The parser auto-detects the format based on the presence of separators. Parsing ISO durations (e.g., P3Y6M4DT12H) can be tricky because the character M is ambiguous—it can mean Months or Minutes depending on whether it appears before or after the time separator T. I implemented a state-machine parser that tracks the T token to resolve this ambiguity. This allows seamless parsing of complex durations like P1Y2DT3H or P1MT1M (1 month, 1 minute).
// stdt/date/iso8601.rs
// Simplified logic snippet
match c {
'T' => is_time_part = true,
'M' => {
let val = num_buf.parse()?;
if is_time_part { dur.minutes = val; } else { dur.months = val; }
},
// ...
}
Pros and Cons
The Pros:
- Zero External Dependencies: This module adds no bloat to your Cargo.lock. It relies solely on std.
- Predictable Memory Layout: The structures are simple aggregates of integers, making them cache-friendly and easy to pass around.
- Strict Validation: The parser doesn't just check syntax; it enforces days-in-month rules and leap years explicitly.
- Flexibility: The ISO implementation handles both compact and extended formats, which is a common pain point when dealing with legacy banking or XML APIs.
The Cons & Future Work:
- Allocation in Formatting: The format() method in Rfc3339 uses chained .replace() calls. While simple to read, this creates temporary string allocations. A future update should move to a single-pass fmt writer.
- Offset Handling: Currently, the structs parse the existence of offsets (like Z), but the offset_str is stored as an Option<&'static str> and logic is largely omitted for simplicity. Timezone arithmetic is not yet supported.
- Error Types: The current implementation returns String for errors. In a future major version, we should introduce a dedicated DateError enum for better error handling control.
You can find the crate on crates.io the documentation on docs.rs and the code on a GitHub repository.
:#/ :)