cdate - a compact calendar date
- Fast: the benchmark result shows that cdate is 37% faster than Moment.js, Day.js and Luxon
- Display: Moment.js-style
.format("YYYY-MM-DD HH:mm:ss")
- Developer friendly display: strftime-style
.text("%Y-%m-%d %H:%M:%S")
- Manipulation:
.add(1, "month").startOf("week").endOf("day")
like Moment.js does but immutable - Time zones: names like
America/New_York
supported by Intl.DateTimeFormat API as well as UTC offset likeGMT-05:00
- I18N:
.locale("fr").text("%c")
resultsdim. 2 janv. 2022, 03:04:05
also managed by Intl API - Small: 9KB minified and less than 4KB gzip including time zones supported per default
- Fully immutable: even plugins never effect the cdate's core. None of "dual package hazard"
- Pure ESM, CommonJS - Node.js, Browsers, TypeScript
SYNOPSIS
// ESM
import {cdate} from "cdate";
// CommonJS
const {cdate} = require("cdate");
Display:
const now = cdate();
console.log(now.format("YYYY-MM-DD HH:mm:ss.SSSZ"));
console.log(now.text("%Y-%m-%d %H:%M:%S.%L%:z"));
Get + Set:
const isLeapYear = (year) => {
return cdate().set("year", year).set("month", 1).endOf("month").get("date") === 29;
}
isLeapYear(2020); // => true
isLeapYear(2021); // => false
isLeapYear(2022); // => false
isLeapYear(2023); // => false
isLeapYear(2024); // => true
Manipulation:
const today = cdate("2023-01-01");
console.log(today.format(" MMMM YYYY"));
const start = today.startOf("month").startOf("week");
const end = today.endOf("month").endOf("week");
for (let day = start; +day < +end;) {
const week = [];
for (let i = 0; i < 7; i++) {
week.push(day.format("DD"))
day = day.next("day");
}
console.log(week.join(" "));
}
Result:
January 2023
01 02 03 04 05 06 07
08 09 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 01 02 03 04
TYPESCRIPT
See TypeScript declaration index.d.ts for detail. API may change.
BENCHMARK
The result shows that cdate is 37% faster than moment!
Library | Version | Minified Size | Local Time Bench | Time Zone Bench | Note |
---|---|---|---|---|---|
cdate | 0.0.5 | 9 KB | 7,868 ops/sec | 6,471 ops/sec | fastest! |
moment | 2.29.4 | 100 KB+ | 5,744 ops/sec | 3,622 ops/sec | big tz database |
dayjs | 1.11.7 | 13 KB | 3,875 ops/sec | 89 ops/sec | DST related bugs |
luxon | 3.3.0 | 74 KB | 930 ops/sec | 158 ops/sec | different API |
Tested on node v18.14.2, Apple Silicon M1, MacBook Pro.
"Minified Size" for dayjs includes its utc and time zone plugins.
Each 1 op
above includes:
- 192 ops of
.add()
manipulations - 60 ops of
.startOf()
and.endOf()
- 30 ops of
.format()
displaying
Try the benchmark on your environment:
git clone --depth=1 https://github.com/kawanet/cdate.git
cd cdate
npm install
npm run build
node cli/benchmark.js
PLUGIN SYSTEM
To be minimal, the cdate itself has many missing features compared to Moment.js's gorgeous APIs.
If you need subtract()
method, for example, you can add it with your own plugin:
const cdateS = cdate().plugin(P => class extends P {
subtract(diff, unit) {
return this.add(-diff, unit);
}
}).cdateFn();
cdateS("2023-01-01").subtract(1, "day").format("YYYY-MM-DD");
// => '2022-12-31'
Or just call add()
method simply with a negative value:
cdate("2023-01-01").add(-1, "day").format("YYYY-MM-DD");
// => '2022-12-31'
Note that the subtract()
method implemented above is available only for instances created by cdateS()
function,
as the cdate's plugin system is immutable as well.
LOCALES
It supports English names: December, Sunday, etc., per default.
There are ways to change it.
The most simple way is to call .locale()
method which enables I18N via
Intl
API on demand:
// English per default
cdate().format("ddd D MMM");
// => 'Sun 18 Dec'
cdate().locale("de").format("ddd D MMM");
// => 'So 18 Dez'
If you still need to support old environments which does not have Intl API, try cdate-locale which has a series of locale settings prebuilt via Intl API.
const {locale_de} = require("cdate-locale/locale/de.js");
cdate().handler(locale_de).format("ddd D MMM");
// => 'So 18 Dez'
The last way is for you to code it.
Call .handler()
method to customize handlers for .format()
specifiers:
const weekday = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
const month = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];
const cdateDE = cdate().handler({
ddd: (dt) => weekday[dt.getDay()],
MMM: (dt) => month[dt.getMonth()],
}).cdateFn();
cdateDE().format("ddd D MMM");
// => 'So 18 Dez'
If you prefer strftime
-style, the same .handler()
method also works for .text()
specifiers:
const cdateDE = cdate().handler({
"%a": (dt) => weekday[dt.getDay()],
"%b": (dt) => month[dt.getMonth()],
}).cdateFn();
cdateDE().text("%a %-d %b");
// => 'So 18 Dez'
TIMEZONES
It supports both UTC offset and timezone names
without any external modules and plugins.
If you use Japan Standard Time (JST) GMT+09:00
for instance:
const dt = new Date("2023-01-01T00:00:00+09:00");
cdate(dt).utcOffset(+9).text(); // +9 hours
cdate(dt).utcOffset(+540).text(); // +540 minutes
cdate(dt).utcOffset("+09:00").text();
cdate(dt).utcOffset("GMT+09:00").text();
cdate(dt).tz("Asia/Tokyo").text();
// => '2023-01-01T00:00:00.000+09:00'
If your app is designed to use a constant UTC offset value, call like .utcOffset(+9).cdateFn()
to preset the offset. It runs faster.
const cdateJST = cdate().utcOffset(+9).cdateFn();
cdateJST(dt).text(); // fast