@kikuchan/calendar
v0.0.1-alpha.2
Published
Arbitrary precision date and time library built on top of @kikuchan/decimal
Downloads
131
Maintainers
Readme
@kikuchan/calendar
Arbitrary precision date and time library built on top of @kikuchan/decimal. Handles fractional seconds, time zones, and calendar alignment operations.
Installation
npm install @kikuchan/calendar @kikuchan/decimalQuick Start
import { Calendar } from '@kikuchan/calendar';
// Current time in UTC
const now = new Calendar();
// From calendar components
const date = new Calendar(2024, 6, 15, 12, 30, '45.123', 'utc');
console.log(date.format('YYYY-MM-DD hh:mm:ss.SSS')); // "2024-06-15 12:30:45.123"
// From epoch seconds (with arbitrary precision)
const epoch = Calendar.fromEpoch('1718451045.123456789', 'utc');
console.log(epoch.seconds().toString()); // "45.123456789"Creating Calendar Instances
Constructors
// Current time in UTC
new Calendar();
// From epoch seconds with optional time zone
new Calendar(epochSeconds);
new Calendar(epochSeconds, 'America/New_York');
// From calendar components (year, month, day, hour?, minutes?, seconds?, zone?)
new Calendar(2024, 6, 15);
new Calendar(2024, 6, 15, 12, 30, '45.5', 'utc');
// From native Date
new Calendar(new Date(), 'local');Static Methods
Calendar.fromEpoch(epochSeconds, zone?) // from Unix epoch seconds
Calendar.fromDate(date, zone?) // from native Date
Calendar.fromComponents(components, zone?) // from object { year, month, day, ... }
Calendar.parse(value, format, zone?) // from formatted stringTime Zones
Supports UTC, local system time, and IANA time zone names:
const date = Calendar.fromEpoch(0, 'utc');
date.zone(); // 'utc'
date.zone('America/New_York'); // new instance with different zone
date.utc(); // shorthand for zone('utc')
date.local(); // shorthand for zone('local')
// In-place mutation with $ suffix
date.zone$('Asia/Tokyo');
date.utc$();
date.local$();API Overview
Component Accessors
All getters return the value; setters return a new instance (immutable):
const date = Calendar.fromComponents({ year: 2024n, month: 6n, day: 15n }, 'utc');
date.year(); // 2024n (bigint)
date.month(); // 6n
date.day(); // 15n
date.hour(); // 0n
date.minutes(); // 0n
date.seconds(); // Decimal(0)
date.weekday(); // 6 (Saturday, 0=Sunday)
// Setters return new instances
date.year(2025); // new Calendar with year 2025
date.month(12).day(31); // chaining worksMutable Operations
Methods ending with $ modify the instance in place:
const date = Calendar.fromEpoch(0, 'utc');
date.year$(2000).month$(6).day$(15);
date.hour$(12).minutes$(30).seconds$('45.5');Epoch Access
const date = Calendar.fromEpoch('1718451045.123', 'utc');
date.epoch(); // Decimal('1718451045.123')
date.epoch('0'); // new instance at epoch 0
date.epoch$('123.456'); // mutate in placeComponents
const date = new Calendar(2024, 6, 15, 12, 30, '45.5', 'utc');
date.components();
// {
// year: 2024n,
// month: 6n,
// day: 15n,
// hour: 12n,
// minutes: 30n,
// seconds: Decimal('45.5'),
// weekday: 6
// }Cloning
const copy = date.clone();Alignment & Stepping
Align dates to boundaries or step to the next boundary. Time components are reset to midnight for day/month/year alignment.
Day Alignment
const date = Calendar.fromComponents(
{ year: 2024n, month: 6n, day: 17n, hour: 10n, minutes: 30n, seconds: 0 },
'utc'
);
date.alignToDay(); // same day at 00:00:00
date.alignToDay(5); // align to nearest 5th (day 15)
date.alignToDay([1, 15]); // align to nearest from list (day 15)
date.nextDay(5); // next 5-day boundary (day 20)
date.nextDay([1, 15]); // next from list (July 1 if past 15th)Month Alignment
date.alignToMonth(); // first day of current month
date.alignToMonth(3); // align to nearest quarter (month 4, 7, 10, or 1)
date.nextMonth(3); // next quarter boundaryYear Alignment
date.alignToYear(); // January 1 of current year
date.alignToYear(10); // align to nearest decade
date.nextYear(10); // next decade boundary
// Era-aware alignment (handles BC/AD transition)
date.alignToYear(100, { era: true });
date.nextYear(100, { era: true });Second Alignment
// Align to 15-second intervals within the day
date.alignToSecond(15);
// Align to 5-minute intervals
date.alignToSecond(300);Formatting
const date = Calendar.fromEpoch('12.3456', 'utc');
date.format('YYYY-MM-DD'); // "1970-01-01"
date.format('YYYY-MM-DD hh:mm:ss'); // "1970-01-01 00:00:12"
date.format('YYYY-MM-DD hh:mm:ss.SSS'); // "1970-01-01 00:00:12.345"
date.format('YYYY-MM-DD hh:mm:ss.SSSSSS'); // "1970-01-01 00:00:12.345600"Parsing
const date = Calendar.parse('2024-06-15 12:30:45.123', 'YYYY-MM-DD hh:mm:ss.SSS', 'utc');
date.year(); // 2024nParsing defaults missing lower-order components to the start of the period (day = 1, time = 00:00:00), requires year and month tokens, and validates calendar ranges (e.g. invalid dates throw). Duplicate tokens must resolve to the same value.
Format Tokens
| Token | Description | Example |
|----------|------------------------------------|-----------------------|
| YYYY | 4+ digit year | 0123 |
| yyyy | 4+ digit year (alias) | 0123 |
| y | Year without padding | 123 |
| MM | 2-digit month (1-2 digits parsed) | 06 |
| M | Month without padding | 6 |
| DD | 2-digit day (1-2 digits parsed) | 15 |
| hh | 2-digit hour (1-2 digits parsed) | 14 |
| h | Hour without padding | 4 |
| mm | 2-digit minutes (1-2 digits parsed)| 30 |
| ss | 2-digit seconds (1-2 digits parsed)| 45 |
| S | Fractional seconds (1 digit) | 1 |
| SS | Fractional seconds (2 digits) | 12 |
| SSS | Fractional seconds (3 digits) | 123 |
| SSSSSS | Fractional seconds (6 digits) | 123456 |
| G | Era year with AD/BC | BC 1 / 123 AD |
| GGGG | Era year padded with AD/BC | BC 0001 / 0123 AD |
| g | Era year with BC prefix | BC 1 / 123 |
| gggg | Era year padded with BC prefix | BC 0001 / 0123 |
Era tokens map to proleptic years where year 1 BC is 0, 2 BC is -1, and so on.
Important Notes
- Immutability: Operations return new instances unless using
$methods - Precision: Seconds support arbitrary precision via
@kikuchan/decimal - Bigint: Year, month, day, hour, and minutes are returned as
bigint - Weekday: Sunday = 0, Monday = 1, ..., Saturday = 6
- Time Zones: Uses
Intl.DateTimeFormatfor IANA zone support
License
See LICENSE file for details.
