Documents
Chrono Dependency And Timezone Safety
Chrono Dependency And Timezone Safety
Type
Topic
Status
Published
Created
Mar 7, 2026
Updated
Mar 8, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Chrono Dependency And Timezone Safety#

The chrono dependency represents an architectural decision in the libmagic-rs project for implementing date and timestamp type support in file format detection. The decision to use chrono 0.4 is driven by the project's strict workspace-level unsafe_code = "forbid" policy, which eliminates traditional approaches to timezone computation that rely on Foreign Function Interface (FFI) calls to libc or subprocess invocations. As a pure-Rust implementation of libmagic (the library behind the file command), libmagic-rs requires safe, zero-unsafe-code date handling for parsing Unix timestamps embedded in archive formats, filesystem images, and document metadata.

As of version 0.5.0, the date type implementation is included in the codebase. The feature was completed in PR #165, implementing GitHub issue #41. The architectural decision documented here reflects a durable commitment to memory safety through dependency vetting, enforced by comprehensive cargo-deny checks that mandate crates.io-only sources and ban C-based libraries in favor of pure-Rust alternatives.

The chrono selection exemplifies the project's broader dependency strategy: every dependency must enable core functionality while respecting the zero-unsafe-code constraint. Chrono provides safe timezone offset computation without requiring unsafe code in the libmagic-rs implementation, making it the only viable option for handling the 14 date and timestamp type specifiers required for comprehensive magic rule evaluation.

Unsafe Code Policy#

The libmagic-rs project enforces workspace-level unsafe_code = "forbid" in its Cargo.toml configuration with an explicit security rationale comment. The forbid lint level is the strictest possible setting in Rust—it prevents any module or crate from overriding the restriction with #[allow(unsafe_code)] annotations. This constraint applies throughout the libmagic-rs codebase and eliminates entire categories of implementation approaches.

The policy is reinforced by four hookify rules that enforce code safety, including a warn-unsafe-code check that flags any unsafe blocks, functions, or trait implementations during development. The project maintains 94%+ line coverage with over 1,000 tests across unit, integration, property (via proptest), and documentation tests to verify the safety guarantees.

For date and timezone handling, the unsafe code policy eliminates two traditional approaches: calling libc timezone functions via FFI (localtime_r, gmtime_r) and invoking subprocess commands (date). Both require unsafe code blocks for FFI or process handling. The policy applies only to libmagic-rs implementation code—dependencies like chrono may contain unsafe code internally, but the libmagic-rs interface to those dependencies remains safe.

Date Type Requirements#

The magic file format specification defines 14 date and timestamp type specifiers for interpreting byte sequences as Unix timestamps. These types are used extensively in archive formats (tar, cpio), filesystem images, and document metadata to detect creation and modification timestamps.

32-bit Date Types#

The specification includes eight 32-bit date type variants:

  • date - 32-bit Unix timestamp, native endianness, UTC
  • ldate - 32-bit Unix timestamp, native endianness, local time
  • bedate / beldate - big-endian variants (UTC / local)
  • ledate / leldate - little-endian variants (UTC / local)
  • medate / meldate - middle-endian (PDP-11) variants (UTC / local)

64-bit QDate Types#

Six 64-bit qdate (quad date) variants provide extended timestamp range:

  • qdate / qldate - native endianness (UTC / local)
  • beqdate / beqldate - big-endian (UTC / local)
  • leqdate / leqldate - little-endian (UTC / local)

The type names encode three orthogonal properties: timestamp width (32-bit vs 64-bit), endianness (native, little, big, middle), and timezone interpretation (UTC vs local time). The TypeKind enum uses two variants—Date and QDate—with endian: Endianness and utc: bool fields to represent all 14 type specifiers.

Chrono Integration Design#

The date type implementation uses chrono's safe timezone APIs to convert Unix timestamps to human-readable date strings. The implementation design distinguishes between UTC and local time at the type system level through the utc boolean field in TypeKind::Date and TypeKind::QDate variants.

Timezone Computation#

Chrono provides two separate timestamp conversion methods:

  • chrono::Utc::timestamp_opt - converts Unix timestamps to UTC DateTimes (for date, bedate, ledate, medate, qdate, beqdate, leqdate)
  • chrono::Local::timestamp_opt - converts Unix timestamps to local time DateTimes with system timezone offset (for ldate, beldate, leldate, meldate, qldate, beqldate, leqldate)

Both methods return Option<DateTime> to handle invalid timestamps safely. The evaluator converts failed conversions to evaluation errors without panicking.

Date Formatting#

All date values are formatted as "%a %b %e %H:%M:%S %Y" and stored in Value::String. Example output: "Wed Feb 14 12:34:56 2026". This format matches GNU file command output for compatibility with existing magic rule expectations.

Implementation Pipeline#

The date evaluation pipeline follows this sequence:

  1. Read raw bytes from buffer at specified offset
  2. Convert bytes to integer using specified endianness (native, little, big, or middle via read_middle_endian_u32)
  3. Cast integer to i64 for chrono compatibility
  4. Call Utc::timestamp_opt or Local::timestamp_opt based on utc field
  5. Format resulting DateTime as string
  6. Store formatted string in Value::String for comparison operations

The middle-endian helper function read_middle_endian_u32 handles PDP-11 byte order by swapping 16-bit words: bytes stored as [byte1, byte0, byte3, byte2] are rearranged to standard order.

Timezone Safety Architecture#

The chrono dependency provides safe timezone offset computation without requiring unsafe code in libmagic-rs. The entire date evaluation pipeline—from byte reading through endianness conversion to timestamp formatting—uses only safe Rust interfaces. Chrono handles the complex timezone logic internally, including daylight saving time transitions and locale-specific timezone rules.

The safety guarantees derive from three architectural choices:

  1. No FFI calls: Chrono's internal timezone implementation may use platform-specific FFI, but libmagic-rs never directly calls foreign functions. The chrono API boundary remains safe.

  2. Type-level timezone distinction: UTC vs local time is encoded in the TypeKind enum variants, preventing accidental misinterpretation of timestamps. The type system enforces correct usage of Utc::timestamp_opt vs Local::timestamp_opt.

  3. Error propagation: Invalid timestamps return None from timestamp_opt methods. The evaluator converts these to EvaluationError results rather than panicking or producing undefined behavior.

This architecture enables libmagic-rs to handle timezone-aware date detection while maintaining its zero-unsafe-code guarantee.

Dependency Vetting and Enforcement#

The libmagic-rs project uses cargo-deny to enforce strict dependency policies. The deny.toml configuration mandates crates.io-only dependency sources—unknown registries are denied and git sources from GitHub, GitLab, and Bitbucket are blocked through empty allow-lists. This prevents supply chain attacks via unvetted git dependencies.

Banned Dependencies#

The configuration explicitly bans C-based libraries in favor of pure-Rust alternatives:

  • git2gix
  • openssl / openssl-sysrustls
  • libssh2-sys (banned)
  • cmakecc

This policy aligns with the unsafe code prohibition by preferring dependencies written entirely in Rust. Multiple versions of the same crate are denied to prevent version confusion vulnerabilities.

Security Policies#

The advisories section denies yanked crates and tracks unmaintained dependencies:

Chrono has joined the vetted dependency list alongside memmap2, byteorder, nom, serde, and thiserror. The current dependency set includes chrono 0.4.41 with features ["std", "clock"].

Implementation Status#

As of version 0.5.0, the date type implementation is included in the codebase. Chrono 0.4.41 appears in the Cargo.toml dependencies with features ["std", "clock"], and date.rs exists in the src/evaluator/types/ directory implementing the read_date and read_qdate functions. The TypeKind enum in src/parser/ast.rs includes Date and QDate variants with endian and utc fields.

The feature completes GitHub issue #41, as marked in ROADMAP.md. The implementation was merged via PR #165.

The type system in src/evaluator/types/ includes numeric.rs, float.rs, string.rs, date.rs, and tests.rs, following the modular refactoring effort.

Alternative Approaches#

The chrono selection reflects careful evaluation of alternatives for timezone-aware date handling:

libc FFI#

Direct calls to system timezone functions (localtime_r, gmtime_r, tzset) via FFI would require unsafe code blocks for foreign function calls. This violates the workspace-level unsafe_code = "forbid" policy and introduces platform-specific implementation complexity.

Subprocess Calls#

Invoking the date command or similar system utilities requires process spawning via std::process::Command. While the API is safe, it introduces performance overhead, error handling complexity, and platform portability issues. The approach also creates security concerns when parsing untrusted input for command arguments.

Custom Implementation#

Implementing timezone conversion from scratch would require parsing timezone databases (tzdata/zoneinfo), handling daylight saving time transitions, and maintaining platform-specific timezone rules. This represents significant complexity and ongoing maintenance burden for functionality already provided by mature libraries.

std::time Alone#

The standard library's std::time::SystemTime provides basic Unix timestamp handling but lacks timezone conversion capabilities. It cannot distinguish UTC from local time or format timestamps with timezone-aware offsets, making it insufficient for the magic file format's local time variants (ldate, qldate, etc.).

Other Time Crates#

While alternatives like time exist, chrono 0.4 is the established choice in the Rust ecosystem for timezone-aware date handling. Its widespread adoption provides better documentation, community support, and integration patterns. The chrono API design aligns well with libmagic-rs's error handling through Option<DateTime> return types.

Usage Example#

Magic rules detect file timestamps using the date type specifiers. Example magic rule for detecting tar archives by their modification timestamp:

# Detect tar archive with recent timestamp
0 string ustar\x00 tar archive
>148 ldate >0 \b, modified %s

The evaluator processes this rule:

  1. Reads bytes 148-151 from the file (4 bytes at offset 148)
  2. Interprets bytes as a 32-bit Unix timestamp in native endianness
  3. Calls chrono::Local::timestamp_opt(timestamp, 0) (because ldate specifies local time)
  4. Formats the resulting DateTime<Local> as "%a %b %e %H:%M:%S %Y"
  5. Stores formatted string in Value::String
  6. Compares against the rule's test value (here, >0 matches any valid timestamp)

For a tar archive created on February 14, 2026 at 12:34:56 local time, the output would be:

tar archive, modified Wed Feb 14 12:34:56 2026

The API for library users follows the existing pattern:

use libmagic_rs::{MagicDatabase, EvaluationConfig};

let db = MagicDatabase::load_default()?;
let config = EvaluationConfig::performance();
let buffer = std::fs::read("archive.tar")?;

match db.evaluate(&buffer, &config)? {
    Some(result) => println!("{}", result.description),
    None => println!("Unknown file type"),
}

The rmagic CLI binary evaluates date types transparently:

$ rmagic archive.tar
archive.tar: tar archive, modified Wed Feb 14 12:34:56 2026

Architectural Context#

The date type implementation is part of a broader type system modular refactoring effort tracked in issue #63. The evaluator's type handling is split into separate files in the src/evaluator/types/ directory, with each type category (numeric, float, string, date) receiving its own module.

The date type design follows the established pattern used for numeric and string types:

  1. TypeKind enum extension - Add Date and QDate variants to src/parser/ast.rs with fields for endianness and UTC vs local time
  2. Parser grammar updates - Recognize all 14 date type keywords in magic rule parsing
  3. Type-specific module - Implement date.rs with read_date() and read_qdate() functions
  4. Value representation - Store formatted date strings in existing Value::String variant
  5. Comparison operations - Reuse string comparison logic for date value tests

The architecture maintains compatibility with GNU file command output, ensuring that magic rules written for the original libmagic work correctly with libmagic-rs. This compatibility requirement drives the date format specification ("%a %b %e %H:%M:%S %Y") and the distinction between UTC and local time variants.

Relevant Code Files#

FilePurposeStatus
Cargo.tomlWorkspace lints enforcing unsafe_code = "forbid", chrono 0.4.41 dependencyCurrent (v0.5.0)
deny.tomlcargo-deny configuration for dependency vetting and supply chain securityCurrent (v0.5.0)
src/parser/ast.rsTypeKind enum definition with Date and QDate variantsCurrent (v0.5.0)
src/evaluator/types/Type evaluation modules including date.rsCurrent (v0.5.0)
src/evaluator/types/date.rsDate and timestamp type evaluation implementation with chrono integrationCurrent (v0.5.0)
ROADMAP.mdProject roadmap marking date type feature as completedCurrent (v0.5.0)
AGENTS.mdAgent documentation listing supported date typesCurrent (v0.5.0)
  • Memory Safety And Unsafe Code Policy - The workspace-level unsafe_code = "forbid" enforcement that drives the chrono dependency decision
  • Type System Architecture - The modular evaluator type system that date types extend
  • Dependency Vetting Strategy - The cargo-deny enforcement and crates.io-only policy that governs dependency selection
  • Supply Chain Security - The ban on C-based dependencies and git sources in favor of audited pure-Rust crates from crates.io