period 0.3.0

A human-friendly date and time library for Rust
Documentation

Period

A human-friendly date and time library for Rust.

Rust License: MIT CI crates.io


Overview

Period provides an expressive, readable API for common date and time operations. Instead of wrestling with offsets and arithmetic, you write code that reads like English.

use period::{today, yesterday, days_ago, weeks_from_now, months_ago, humanize};
use period::now;

let today     = today();
let yesterday = yesterday();
let past      = days_ago(3)?;
let future    = weeks_from_now(2)?;
let earlier   = months_ago(6)?;
let label     = humanize(now()); // "just now"

Installation

Add Period to your Cargo.toml:

[dependencies]
period = "0.1"

API Reference

Current time

use period::{now, today};

let datetime = now();    // DateTime<Local>
let date     = today();  // NaiveDate

Named days

use period::{yesterday, tomorrow};

let yesterday = yesterday(); // NaiveDate
let tomorrow  = tomorrow();  // NaiveDate

Relative dates

All relative functions return Result<NaiveDate, PeriodError> and reject negative values with a helpful error message.

use period::{days_ago, days_from_now, weeks_ago, weeks_from_now,
             months_ago, months_from_now, years_ago, years_from_now};

let d = days_ago(7)?;          // 7 days in the past
let d = days_from_now(30)?;    // 30 days in the future
let d = weeks_ago(2)?;         // 2 weeks in the past
let d = weeks_from_now(4)?;    // 4 weeks in the future
let d = months_ago(3)?;        // 3 calendar months in the past
let d = months_from_now(6)?;   // 6 calendar months in the future
let d = years_ago(1)?;         // 1 year in the past
let d = years_from_now(5)?;    // 5 years in the future

Relative times

These return Result<DateTime<Local>, PeriodError>.

use period::{seconds_ago, seconds_from_now, minutes_ago, minutes_from_now,
             hours_ago, hours_from_now};

let t = seconds_ago(30)?;        // 30 seconds in the past
let t = seconds_from_now(10)?;   // 10 seconds in the future
let t = minutes_ago(15)?;        // 15 minutes in the past
let t = minutes_from_now(45)?;   // 45 minutes in the future
let t = hours_ago(2)?;           // 2 hours in the past
let t = hours_from_now(8)?;      // 8 hours in the future

Humanize

Convert any DateTime<Local> into a human-readable relative string.

use period::humanize;
use chrono::Local;

let dt = Local::now() - chrono::Duration::minutes(35);
println!("{}", humanize(dt)); // "35 minutes ago"

let dt = Local::now() + chrono::Duration::hours(2);
println!("{}", humanize(dt)); // "in 2 hours"
Absolute delta Past Future
< 30 s "just now" "just now"
< 90 s "a minute ago" "in a minute"
< 45 min "N minutes ago" "in N minutes"
< 90 min "an hour ago" "in an hour"
< 22 h "N hours ago" "in N hours"
< 36 h "yesterday" "tomorrow"
< 25 days "N days ago" "in N days"
< 45 days "a month ago" "in a month"
< 10 months "N months ago" "in N months"
< 18 months "a year ago" "in a year"
≥ 18 months "N years ago" "in N years"

Error handling

All fallible functions return Result<T, PeriodError>. The error type is inspectable — you can match on specific variants:

use period::{days_ago, PeriodError};

match days_ago(-5) {
    Err(PeriodError::NegativeValue { suggestion, value, .. }) => {
        println!("Did you mean {}({})?", suggestion, value);
    }
    Err(PeriodError::Overflow { unit, value }) => {
        println!("{} value {} is too large", unit, value);
    }
    Ok(date) => println!("{}", date),
}

Passing a negative value produces a descriptive error with a suggestion:

days must be positive. Did you mean days_from_now(5)?

PeriodError implements both std::fmt::Display and std::error::Error, making it compatible with ? in functions returning Box<dyn Error> or anyhow::Error.


Design principles

  • Human-readable — function names read like natural language
  • Explicit over implicit — negative values are rejected with actionable error messages rather than silently producing unexpected results
  • Zero heap allocation on the error path — error variants use &'static str fields
  • ComposablePeriodError implements std::error::Error for easy integration with the broader Rust ecosystem

License

MIT