An open API service indexing awesome lists of open source software.

https://github.com/porsager/datie

Small template string based date formatter for the browser and Node.js.
https://github.com/porsager/datie

date formatter

Last synced: 11 days ago
JSON representation

Small template string based date formatter for the browser and Node.js.

Awesome Lists containing this project

README

          

# πŸ—“ Datie

Small template string based date formatter for the browser and Node.js. It supports custom specifiers and relative time calculations without external libraries. Datie is lightweight (~1KB minified) and caches formatters for performance.

### LDML Compliance

Follows Unicode LDML date patterns (https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table) with additions:
- `o`: Ordinal suffix (e.g., `1st`, `2nd`) for numbers like day or month.
- `R`: Relative time (e.g., `1 minute ago`, `in 2 days`).

# Usage

Datie uses tagged template literals to define formats, returning a reusable function that accepts a Date object or compatible string. Formatters are cached by string.

```js
import d from 'datie'

const string = '2020-05-13T08:34:30.911Z'
const date = new Date(string)

d`d/M-y hh:mm`(string) // '13/5-2020 08:34'
d`d/M-y hh:mm`(date) // '13/5-2020 08:34'
```

## Supported Specifiers

Comprehensive list of format specifiers, with descriptions and examples (using July 19, 2025, Saturday, 12:34:56):

- **Year**:
- `y` / `yyyy`: Full year β†’ '2025'
- `yy`: Two-digit year β†’ '25'

- **Month**:
- `M`: Month number (1-12) β†’ '7'
- `MM`: Padded month (01-12) β†’ '07'
- `MMM`: Abbreviated month β†’ 'Jul'
- `MMMM`: Full month β†’ 'July'
- `MMMMM`: Narrow month (first letter) β†’ 'J'

- **Day**:
- `d`: Day of month (1-31) β†’ '19'
- `dd`: Padded day (01-31) β†’ '19'

- **Weekday**:
- `e`: Weekday number (0=Sun-6=Sat) β†’ '6'
- `ee`: Padded weekday number β†’ '06'
- `E` / `EE` / `EEE`: Abbreviated weekday β†’ 'Sat'
- `EEEE`: Full weekday β†’ 'Saturday'
- `EEEEE`: Narrow weekday β†’ 'Sa'
- `EEEEEE`: Shortest weekday β†’ 'S'

- **Hour** (24-hour; `h`/`hh` aliases `H`/`HH`; no AM/PM):
- `H` / `h`: Hour (0-23) β†’ '12'
- `HH` / `hh`: Padded hour β†’ '12'

- **Minute**:
- `m`: Minute (0-59) β†’ '34'
- `mm`: Padded minute β†’ '34'

- **Second**:
- `s`: Second (0-59) β†’ '56'
- `ss`: Padded second β†’ '56'

- **Week** (ISO week, Thursday-based):
- `w`: Week of year (1-53) β†’ '29'
- `ww`: Padded week β†’ '29'

- **Quarter**:
- `Q`: Quarter (1-4) β†’ '3'
- `QQ`: Padded quarter β†’ '03'
- `QQQ`: Prefixed quarter β†’ 'Q3'
- `QQQQ`: Full with ordinal β†’ '3rd quarter'

- **Ordinal Suffix**:
- `o`: Suffix for prior number (e.g., `do` β†’ '19th', `Qo` β†’ '3rd')

## Relative Time Formatting

Use `R` for relative time vs. current time (`new Date()`). Handles past (`ago`) and future (`in`), with pluralization and `<5s` as `a few seconds ago`/`in a few seconds`. Threshold for `now` is under 5 seconds.

There is an optional 2nd parameter accepted if you want to provide a different reference point instead of Date.now().

Examples (assuming current time is July 22, 2025, 12:00:00):

```js
const reference = new Date('2025-07-22T11:55:00')
const pastDate = reference.getTime() - 1000 * 60 * 5 // 5 minutes ago
const futureDate = reference.getTime() + 1000 * 60 * 10 // 10 minutes future

d`R`(pastDate, reference) // '5 minutes ago'
d`R`(futureDate, reference) // 'in 10 minutes'
d`R`(new Date()) // 'now' (or 'a few seconds ago' if slight offset)
```

## Relative Fallbacks

Combine relative time with a fallback format using thresholds. If the date is within the spec (past or future), show relative; else, use fallback.

- **Syntax**:
- Past: `R ` (e.g., `R1D yyyy-MM-dd`) – Relative if past and within spec.
- Future: ` R` (e.g., `yyyy-MM-dd R1Y`) – Relative if future and within spec.
- **Spec**: `[unit]`; units: `m` (minutes, default), `H` (hours), `D` (days), `M` (months), `Y` (years). No spec = always relative (threshold Infinity).

Examples (current: July 22, 2025, 12:00:00):

```js
// Past fallback
const recentPast = new Date('2025-07-22T11:00:00') // 1 hour ago
const oldPast = new Date('2025-07-20T12:00:00') // >1 day ago

d`R1D yyyy-MM-dd HH:mm`(recentPast) // '1 hour ago'
d`R1D yyyy-MM-dd HH:mm`(oldPast) // '2025-07-20 12:00'

// Future fallback
const nearFuture = new Date('2025-07-22T15:00:00') // 3 hours future
const farFuture = new Date('2025-08-22T12:00:00') // >15 days future

d`yyyy-MM-dd HH:mm R3H`(nearFuture) // 'in 3 hours'
d`yyyy-MM-dd HH:mm R3H`(farFuture) // '2025-08-22 12:00'

// Other specs
d`yyyy-MM-dd R15D`(farFuture) // '2025-08-22' (31 days >15D)
d`yyyy-MM-dd R6M`(new Date('2025-12-22')) // 'in 5 months'
d`yyyy-MM-dd R1Y`(new Date('2026-07-22')) // 'in 1 year'
d`yyyy-MM-dd R1Y`(new Date('2027-01-01')) // '2027-01-01' (>1Y)
```

## Localization

Override names for days, months, seasons (relative time fixed in English):

```js
d.names = {
days: ['Domingo', 'Lunes', /* Spanish days */],
months: ['Enero', 'Febrero', /* Spanish months */],
seasons: ['Primavera', 'Verano', 'OtoΓ±o', 'Invierno'],
ordinals: ['o', 'o', 'o', 'o'] // Custom ordinals (e.g., Spanish)
}
```

> [!NOTE]
> Localization doesn't alter LTR output or handle all global formats. Relative strings remain English.