waktoo
v1.1.0
Published
A lightweight, modern, Moment-style date-time library with timezone, locale, arithmetic, durations, and relative time. Zero dependencies. Fast. Chainable. Universal.
Downloads
305
Maintainers
Readme
WaktooJS
UTC-First • Lightweight • Chainable Date-Time Library
A fast, modern, dependency-free datetime engine for JavaScript —
with strict UTC parsing, timezone support, locale formatting, durations,
relative time, calendar outputs, and flexible tokens, date range, and age calculation.
“Time made simple. Lightweight. Predictable. Powerful.”
See Release notes
Why WaktooJS?
Ideal for applications needing reliable, predictable, and readable date manipulation without heavy dependencies.
Modern JavaScript apps need predictable and readable date operations — not massive libraries. Waktoo focuses on the essentials:
Fast, Lightweight, Zero Dependencies
No overhead. No polyfills. No bloated parsing engine.
UTC-First (Predictable Everywhere)
Your code runs the same on every machine — CI, server, client, container.
No surprise timezone shifts.
Timezone support
Full timezone formatting + abbreviations & offsets.
Modern, Clean, Chainable API
waktoo().tz("Asia/Tokyo").add(1, "day").format("DD MMM YYYY");Table of Contents
- Introduction
- Why Waktoo
- Installation
- Importing
- Quick Usage
- UTC Default Behavior
- Timezone-Aware Getters
- Date Arithmetic
- Diff
- Range
- Age
- Duration
- Duration.format()
- Relative Time
- Calendar Output
- Token-Based Date Parsing
- Timezone Formatting
- Supported Format Tokens
- Supported Timezone Abbreviations
- API Reference Index
- License
Installation
npm install waktooImporting
CommonJS
const waktoo = require("waktoo");ESM
import waktoo from "waktoo";Quick Usage
waktoo().format();
// → "2025-12-01T00:00:00.000Z"
waktoo().format("DD MMM YYYY");
// → "16 Nov 2025"
waktoo("2025-12-01").tz("Asia/Jakarta").format("DD MMM YYYY HH:mm Z");
// → "02 Des 2025 07:00 +07:00"
waktoo().locale("id-ID").format("DD MMMM YYYY");
// → "16 November 2025"
waktoo("2025-12-31").fromNow();
// → "in 1 month"UTC Default Behavior
Waktoo stores everything in strict UTC.
This means:
waktoo().hour()→ UTC hourwaktoo().date()→ UTC datewaktoo().day()→ UTC weekday
This guarantees reproducibility across all machines.
Timezone-Aware Getters
waktoo("2025-12-01T00:00:00Z").tz("Asia/Jakarta").hour();
// → 7
waktoo("2025-12-01T00:00:00Z").tz("America/New_York").date();
// → 30 (previous day)Any of these reflect the chosen timezone:
year()month()date()day()hour()minute()second()
Date Arithmetic
waktoo("2025-01-01").add(3, "days");
waktoo("2025-01-01").add({ months: 2, hours: 5 });
waktoo("2025-01-10").subtract(1, "month");Diff
const a = waktoo("2025-12-25");
const b = waktoo("2025-12-10");
a.diff(b, "days"); // 15
a.diff(b, "days", true); // 15.0 (float)Range
Human-readable, localized difference between two dates.
Detailed breakdown
waktoo("2023-01-01").range("2025-03-05");
// → "2 years 2 months 4 days"Single-unit output
waktoo("2023-01-01").range("2025-01-01", "day");
// → "731 days"
waktoo("2023-01-01").range("2023-01-03", "minute");
// → "2880 minutes"Localized
waktoo("2023-01-01").locale("id-ID").range("2025-01-01");
// → "2 tahun"Age
Age is always:
- absolute
- localized
- humanized by default
- still convertible numerically with
.asDays()etc
Basic age
waktoo("2023-01-01").age();
// → "2 years"Month-based
waktoo("2024-12-01").age();
// → "1 month"Localized
waktoo("2023-01-01").locale("id-ID").age();
// → "2 tahun"Conversions
waktoo("2023-01-01").age().asDays();
// → 731
waktoo("2023-01-01").age().asMonths();
// → 24Duration
waktoo.duration(3, "hours").asMinutes();
// → 180
waktoo.duration({ hours: 2, minutes: 30 }).humanize();
// → "in 2 hours"Durations support:
- numeric conversions (
.asDays(),.asHours(), etc.) - human-readable output (
.humanize()) - suffixless output (
.humanize(false)) - localization (
.locale("id-ID")) - deterministic normalized formatting (
.format())
Duration.format()
.format() always returns a fully normalized breakdown, using localized unit names.
Object-based durations:
waktoo
.duration({
years: 2,
months: 3,
days: 5,
hours: 4,
minutes: 30,
seconds: 10,
})
.format();
// → "2 years 3 months 5 days 4 hours 30 minutes 10 seconds"Numeric or mixed durations normalize automatically:
waktoo.duration({ minutes: 90 }).format();
// → "1 hour 30 minutes"Localized:
waktoo.duration({ minutes: 90 }).locale("id-ID").format();
// → "1 jam 30 menit"Relative Time
waktoo("2025-12-31").fromNow();
// → "in 1 month"
waktoo("2025-12-01").from("2025-11-25");
// → "in 6 days"Localized:
waktoo().add(1, "hour").locale("id-ID").fromNow();
// → "dalam 1 jam"
waktoo().subtract(2, "hours").locale("id-ID").fromNow();
// → "2 jam yang lalu"Calendar Output
waktoo("2025-12-31").calendar();
// → "Today at 15:00"
// → "Tomorrow at 11:00"
// → "Yesterday at 22:00"
// → "Sunday at 09:00"
// → "31/12/2025"Localized:
waktoo("2025-12-31").locale("id-ID").calendar();
// → "Hari ini pukul 15:00"Token-Based Date Parsing
Supports patterns similar to Moment:
Example:
waktoo("25/12/2025", "DD/MM/YYYY").format("YYYY-MM-DD");
// → "2025-12-25"
waktoo().format("D MMM YYYY HH:mm");
// → "1 January 2025 12:30"Localized:
waktoo().locale("id-ID").format("D MMM YYYY HH:mm");
// → "1 Januari 2025 12:30"Strict mode rejects wrong formats:
waktoo("999/99/9999", "DD/MM/YYYY");
// Throws invalid date errorTimezone Formatting
Waktoo supports:
Z→ "+07:00"ZZ→ "+0700"z→ "WIB"zzz→ "WIB" (long/variant)
waktoo().tz("Asia/Jakarta").format("DD MMM YYYY HH:mm:ss Z z");
// → "16 Nov 2025 23:00:00 +07:00 WIB"Supported Format Tokens
| Token | Description | | ----- | -------------------- | | YYYY | 4-digit year | | YY | 2-digit year | | MMMM | Month long | | MMM | Month short | | MM | 01–12 | | M | 1–12 | | DD | 01–31 | | D | 1–31 | | dddd | Weekday long | | ddd | Weekday short | | HH | 00–23 | | H | 0–23 | | hh | 01–12 | | h | 1–12 | | mm | 00–59 | | m | 0–59 | | ss | 00–59 | | s | 0–59 | | A | AM/PM | | a | am/pm | | Z | +07:00 | | ZZ | +0700 | | z | timezone abbr | | zzz | long/display TZ abbr |
Supported Timezone Abbreviations
Waktoo includes an expanded global TZ abbreviation map:
| Timezone | Abbrev | | ------------------- | --------- | | Asia/Jakarta | WIB | | Asia/Makassar | WITA | | Asia/Jayapura | WIT | | America/New_York | EST/EDT | | America/Chicago | CST/CDT | | America/Denver | MST/MDT | | America/Los_Angeles | PST/PDT | | America/Phoenix | MST | | America/Toronto | EST | | America/Vancouver | PST | | America/Sao_Paulo | BRT | | Europe/London | GMT/BST | | Europe/Dublin | GMT/IST | | Europe/Paris | CET/CEST | | Europe/Berlin | CET/CEST | | Europe/Madrid | CET/CEST | | Europe/Rome | CET/CEST | | Europe/Moscow | MSK | | Africa/Johannesburg | SAST | | Africa/Cairo | EET | | Africa/Nairobi | EAT | | Asia/Tokyo | JST | | Asia/Seoul | KST | | Asia/Shanghai | CST | | Asia/Hong_Kong | HKT | | Asia/Singapore | SGT | | Asia/Kuala_Lumpur | MYT | | Asia/Bangkok | ICT | | Australia/Sydney | AEST/AEDT | | Australia/Perth | AWST | | Pacific/Auckland | NZST/NZDT |
Fallback behavior:
If a timezone is missing an abbreviation, waktoo uses the last segment of the TZ name (e.g., "Asia/Colombo" → "Colombo").
API Reference Index
Core
waktoo(input?)waktoo().format(pattern)waktoo().locale(localeCode)waktoo().tz(timezone)
Getters
year()month()date()day()hour()minute()second()
Math
add(value, unit)add({ parts })subtract(value, unit)subtract({ parts })diff(otherDate, unit?, float?)
Range
range(date2)range(date2, unit)
Age
age().asSeconds().asMinutes().asHours().asDays().asWeeks().asMonths().asYears()
Relative
fromNow()from(otherWaktooInstance)
Calendar
calendar()
Duration API
waktoo.duration(number, unit)waktoo.duration({ parts }).locale(localeCode).asMilliseconds().asSeconds().asMinutes().asHours().asDays().asWeeks().asMonths().asYears().humanize(withSuffix = true).format()
