English dates
Dates typed in English read as times, in the user's time zone and US or UK style: next friday at 3pm, tomorrow 9am, in 2 weeks, 3 days ago.
Version 1.0.0 · 3 functions · 2 crates
Functions
What use dates_english.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use dates_parse, dates_parse_iso from dates_english (Quillo 0.6).
dates_parse(text: str, now_ms: int, utc_offset_minutes: int, dialect: str) → intor an errorThe time text means, in milliseconds since 1970, counted from now_ms (now()) in the user's time zone, utc_offset_minutes from UTC (-300 for New York in winter, 60 for Paris). dialect is "us" or "uk": "04/01/27" is April 1 in the US and 4 January in the UK, and "next friday" is this coming Friday in the US and the one after in the UK. A time with no hour is midnight.
dates_parse_iso(text: str, now_ms: int, utc_offset_minutes: int, dialect: str) → stror an errorAs dates_parse, the time as ISO 8601 text with the user's offset: "2026-11-06T15:00:00+01:00".
dates_duration(text: str) → anyor an errorA length of time typed in English: "2 weeks", "15m ago", "3 months", as { seconds, days, months }, one of them set and the others 0 (months and days are not a fixed number of seconds). "ago" makes it negative.
Get it
$ quillo install dates_english # dates_english.qwer into this folder$ quillo install dates_english --example # and its example, dates_english.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/dates_english.qwer$ curl -O https://quillolang.org/plugins/files/dates_english.qweThen, in your program, all of it or only what you call:
use dates_english.qweruse dates_parse, dates_parse_iso from dates_english // Quillo 0.6: only theseIt uses these crates, which cargo fetches the first time the plugin is built:
interim = { version = "0.1", features = ["chrono"] }chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }Example
// Reminders typed as people say them: "next friday at 3pm", "tomorrow 9am", "in 2 weeks".//// quillo run dates_english.qwe then open http://localhost:8080/remind?when=tomorrow%209amuse "dates_english.qwer"// Wednesday 28 October 2026, 10:00 in Paris (UTC+1): fixed, so the answers below do not move.let NOW = 1793178000000let PARIS = 60route GET /remind ? { when: str } = { when, at: dates_parse_iso(when, NOW, PARIS, "uk")? }route GET /examples = ["next friday at 3pm", "friday 3pm", "in 2 weeks", "3 days ago", "1 April 2027", "04/01/27"] | map((w) => { text: w, uk: dates_parse_iso(w, NOW, PARIS, "uk") ?? "?", us: dates_parse_iso(w, NOW, PARIS, "us") ?? "?" })route GET /due ? { length: str = "2 weeks" } = dates_duration(length)?$ quillo run dates_english.qwe$ curl 'localhost:8080/remind?when=tomorrow%209am'$ curl 'localhost:8080/examples'Source
//! Dates and times typed in English read as times: "next friday at 3pm", "tomorrow 9am", "in 2 weeks", "3 days ago", "April 1 2027", for reminders and due dates.//! version: 1.0.0//!//! [dependencies]//! interim = { version = "0.1", features = ["chrono"] }//! chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }use chrono::{DateTime, FixedOffset, TimeZone, Utc};use interim::{parse_date_string, Dialect, Interval};use serde_json::{json, Value};fn base(now_ms: i64, utc_offset_minutes: i64) -> Result<DateTime<FixedOffset>, String> { let tz = FixedOffset::east_opt((utc_offset_minutes.clamp(-1080, 1080) * 60) as i32).ok_or("bad offset")?; let t = Utc.timestamp_millis_opt(now_ms).single().ok_or("now_ms is out of range")?; Ok(t.with_timezone(&tz))}fn dialect(d: &str) -> Dialect { if d.eq_ignore_ascii_case("us") { Dialect::Us } else { Dialect::Uk }}fn parse(text: &str, now_ms: i64, utc_offset_minutes: i64, d: &str) -> Result<DateTime<FixedOffset>, String> { if text.len() > 200 { return Err("up to 200 characters".into()); } let mut t = text.trim().to_lowercase(); // "at 3pm" and "in 2 weeks" are how people write them; the parser wants "3pm" and "2 weeks". t = t.replace(" at ", " "); if let Some(rest) = t.strip_prefix("in ") { t = rest.to_string(); } parse_date_string(&t, base(now_ms, utc_offset_minutes)?, dialect(d)).map_err(|e| format!("{:?}: {}", text, e))}/// The time `text` means, in milliseconds since 1970, counted from `now_ms` (`now()`) in the user's time zone, `utc_offset_minutes` from UTC (-300 for New York in winter, 60 for Paris). `dialect` is "us" or "uk": "04/01/27" is April 1 in the US and 4 January in the UK, and "next friday" is this coming Friday in the US and the one after in the UK. A time with no hour is midnight.pub fn dates_parse(text: &str, now_ms: i64, utc_offset_minutes: i64, dialect: &str) -> Result<i64, String> { Ok(parse(text, now_ms, utc_offset_minutes, dialect)?.timestamp_millis())}/// As `dates_parse`, the time as ISO 8601 text with the user's offset: "2026-11-06T15:00:00+01:00".pub fn dates_parse_iso(text: &str, now_ms: i64, utc_offset_minutes: i64, dialect: &str) -> Result<String, String> { Ok(parse(text, now_ms, utc_offset_minutes, dialect)?.to_rfc3339())}/// A length of time typed in English: "2 weeks", "15m ago", "3 months", as `{ seconds, days, months }`, one of them set and the others 0 (months and days are not a fixed number of seconds). "ago" makes it negative.pub fn dates_duration(text: &str) -> Result<Value, String> { let i = interim::parse_duration(&text.trim().to_lowercase()).map_err(|e| format!("{:?}: {}", text, e))?; Ok(match i { Interval::Seconds(s) => json!({ "seconds": s, "days": 0, "months": 0 }), Interval::Days(d) => json!({ "seconds": 0, "days": d, "months": 0 }), Interval::Months(m) => json!({ "seconds": 0, "days": 0, "months": m }), })}Related
humanize.qwer · 1.0.0Durations, file sizes and relative times as people write them and back: 2h 30m, 1.5 GB, 2 GiB, 3 days ago, in 2 hours.7 views · 11 downloadsBusiness days business_days.qwer · 1.0.0Working days for due dates, delivery estimates and SLAs: add them, count them between dates, skip weekends and holidays, with US, UK, French and German public holidays built in.6 views · 5 downloadsISO durations iso_durations.qwer · 1.0.0ISO 8601 durations such as P1DT2H and PT30M read, written, turned into seconds and added to dates and times, months moving the calendar.7 views · 9 downloadsSubtitles subtitles.qwer · 1.0.0SRT and WebVTT subtitles: cues read, shifted or stretched back in sync, converted either way, the cue at a moment, and the words as a transcript.7 views · 5 downloadsCase case.qwer · 1.0.0Text in snake_case, camelCase, PascalCase, kebab-case, CONSTANT_CASE, Title Case and Sentence case: column names as API keys and labels.7 views · 8 downloadsInflection inflect.qwer · 1.0.0English words in the right form for counts and labels: plurals and singulars, 3 items, ordinals such as 1st and 22nd, and a or an by how a word sounds.6 views · 7 downloadsThread 0 posts
On English dates: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.