Qrono: JavaScript Date Manipulation with DST Support

Category: Date & Time , Javascript | June 25, 2026
Authorurin
Last UpdateJune 25, 2026
LicenseMIT
Tags
Views0 views
Qrono: JavaScript Date Manipulation with DST Support

Qrono is a lightweight, dependency-free JavaScript date manipulation library that parses, compares, and adjusts dates with UTC as its default context.

It’s designed for single-timezone applications that need UTC-first logic, reliable date arithmetic, and explicit control over ambiguous local clock times.

You can use the library to build scheduling apps, event calendars, log processing tools, or any datetime manipulation workflow where bundle size matters.

Features:

  • Parses ISO-style strings, timestamps, arrays, objects, and native Date values.
  • Uses UTC as the default date and time context.
  • Returns a new instance from every setter and calculation.
  • Separates timestamp values from calendar-only dates.
  • Resolves daylight-saving gaps and overlaps through explicit rules.
  • Calculates ISO weeks, month boundaries, leap years, and days in a year.
  • Detects local daylight-saving transitions and shortened or extended days.

How To Use It

Installation

Install Qrono with the package manager you prefer.

npm install qrono
pnpm add qrono
yarn add qrono
deno add jsr:@urin/qrono
bunx jsr add @urin/qrono

Or load the ES module directly in your document.

<script type="module">
  import { qrono } from 'https://unpkg.com/qrono@1/dist/qrono.js';
  console.log(qrono().toString());
</script>

Basic Usage

Import qrono, create a datetime value, then use immutable methods to calculate a new value.

import { qrono } from 'qrono';
const publishedAt = qrono('2026-06-25T14:30:00.000Z');
const reviewDeadline = publishedAt.plus({
  day: 14
});
console.log(reviewDeadline.toString());
// 2026-07-09T14:30:00.000Z

Use qrono.date() for values that represent a calendar date instead of a specific timestamp.

import { qrono } from 'qrono';
const renewalDate = qrono.date('2026-06-30');
const nextRenewal = renewalDate.plus({
  month: 1
});
console.log(nextRenewal.toString());
// 2026-07-30

Advanced Usages

Calculate ISO Week Values

import { qrono } from 'qrono';
const completedAt = qrono('2026-12-31T18:20:00.000Z');
console.log(completedAt.weekOfYear());
console.log(completedAt.yearOfWeek());

Create a Half-Open Date Range

import { qrono } from 'qrono';
const month = qrono.date('2026-06-01');
const startsAt = month.toDatetime();
const endsBefore = month.plus({ month: 1 }).toDatetime();
const recordCreatedAt = qrono('2026-06-25T09:15:00.000Z');
const belongsToMonth =
  recordCreatedAt.isSameOrAfter(startsAt) &&
  recordCreatedAt.isBefore(endsBefore);
console.log(belongsToMonth);
// true

Resolve a Repeated Local Time During DST

import { qrono } from 'qrono';
const repeatedLocalTime = '2026-11-01T01:30:00';
const earlierTime = qrono(
  { localtime: true, disambiguation: 'earlier' },
  repeatedLocalTime
);
const laterTime = qrono(
  { localtime: true, disambiguation: 'later' },
  repeatedLocalTime
);
console.log(earlierTime.toString());
console.log(laterTime.toString());

Use reject when an ambiguous local timestamp should stop the workflow and require user correction.

import { qrono } from 'qrono';
const userInput = '2026-11-01T01:30:00';
const appointmentTime = qrono(
  { localtime: true, disambiguation: 'reject' },
  userInput
);

Work With Date-Only Deadlines

import { qrono } from 'qrono';
const deadline = qrono.date('2026-02-28');
console.log(deadline.dayOfYear());
console.log(deadline.endOfMonth().toString());
console.log(deadline.daysInMonth());

Configuration Options

  • localtime (boolean): Uses the runtime environment’s local time zone when set to true. The default value is false, which uses UTC.
  • disambiguation ('compatible' | 'earlier' | 'later' | 'reject'): Defines how Qrono handles ambiguous or invalid local times around daylight-saving transitions. The default value is 'compatible'.

Set the default context for new instances when the whole application follows the same runtime local-time rules.

import { qrono } from 'qrono';
qrono.context({
  localtime: true,
  disambiguation: 'later'
});

Pass a context object to one factory call when only a specific operation needs local-time behavior.

const localAppointment = qrono(
  { localtime: true },
  '2026-08-15T10:00:00'
);

API Methods

import { qrono } from 'qrono';
// Create a Qrono datetime from the current time.
qrono();
// Create a datetime from a native Date object.
qrono(new Date());
// Create a datetime from a Unix timestamp in milliseconds.
qrono(1782052200000);
// Create a datetime from an ISO-style string.
qrono('2026-06-25T14:30:00.000Z');
// Create a datetime from individual date and time values.
qrono(2026, 6, 25, 14, 30, 0, 0);
// Create a datetime from an array.
qrono([2026, 6, 25, 14, 30]);
// Create a datetime from an object.
qrono({
  year: 2026,
  month: 6,
  day: 25,
  hour: 14,
  minute: 30
});
// Create a date-only QronoDate value.
qrono.date('2026-06-25');
// Set the default context for future Qrono instances.
qrono.context({
  localtime: true,
  disambiguation: 'later'
});
// ISO day constants.
qrono.monday;
qrono.tuesday;
qrono.wednesday;
qrono.thursday;
qrono.friday;
qrono.saturday;
qrono.sunday;
const time = qrono('2026-06-25T14:30:45.250Z');
const date = qrono.date('2026-06-25');
// Convert a datetime or date-only value to a string.
time.toString();
date.toString();
// Return the numeric timestamp or day count.
time.numeric();
date.numeric();
// Support numeric coercion.
time.valueOf();
date.valueOf();
// Return date components as an array.
time.toArray();
date.toArray();
// Return date components as an object.
time.toObject();
date.toObject();
// Return a native JavaScript Date object.
time.nativeDate();
date.nativeDate();
// Extract the date portion from a datetime.
time.toDate();
// Convert a date-only value to a midnight datetime.
date.toDatetime();
// Get or replace year, month, and day values.
time.year();
time.year(2027);
time.month();
time.month(12);
time.day();
time.day(1);
date.year();
date.year(2027);
date.month();
date.month(12);
date.day();
date.day(1);
// Get or replace time components.
time.hour();
time.hour(9);
time.minute();
time.minute(45);
time.second();
time.second(0);
time.millisecond();
time.millisecond(500);
// Return the UTC offset in minutes.
time.offset();
// Get or replace instance context settings.
time.context();
time.context({ localtime: true });
// Add a duration to a datetime or date-only value.
time.plus({ month: 1, day: 5 });
time.plus(60 * 60 * 1000);
date.plus({ month: 1 });
date.plus(7);
// Subtract a duration from a datetime or date-only value.
time.minus({ day: 1, hour: 2 });
time.minus(15 * 60 * 1000);
date.minus({ month: 1 });
date.minus(14);
// Check whether a value represents a valid date.
time.valid();
date.valid();
// Compare date and datetime values.
time.isSame(qrono('2026-06-25T14:30:45.250Z'));
time.isBefore(qrono('2026-07-01T00:00:00.000Z'));
time.isAfter(qrono('2026-01-01T00:00:00.000Z'));
time.isSameOrBefore(qrono('2026-12-31T23:59:59.999Z'));
time.isSameOrAfter(qrono('2026-01-01T00:00:00.000Z'));
time.isBetween(
  qrono('2026-06-01T00:00:00.000Z'),
  qrono('2026-06-30T23:59:59.999Z')
);
date.isSame(qrono.date('2026-06-25'));
date.isBefore(qrono.date('2026-07-01'));
date.isAfter(qrono.date('2026-01-01'));
date.isSameOrBefore(qrono.date('2026-12-31'));
date.isSameOrAfter(qrono.date('2026-01-01'));
date.isBetween(
  qrono.date('2026-06-01'),
  qrono.date('2026-06-30')
);
// Return the start of a time unit.
time.startOfYear();
time.startOfMonth();
time.startOfDay();
time.startOfHour();
time.startOfMinute();
time.startOfSecond();
date.startOfYear();
date.startOfMonth();
// Return the final calendar date of a unit.
date.endOfYear();
date.endOfMonth();
// Read calendar information.
time.dayOfWeek();
time.dayOfYear();
time.weekOfYear();
time.yearOfWeek();
time.isLeapYear();
time.daysInMonth();
time.daysInYear();
time.weeksInYear();
date.dayOfWeek();
date.dayOfYear();
date.weekOfYear();
date.yearOfWeek();
date.isLeapYear();
date.daysInMonth();
date.daysInYear();
date.weeksInYear();
// Inspect daylight-saving behavior in local-time mode.
time.hasOffsetChangeInYear();
time.isInDst();
time.hasOffsetChangeInDay();
time.minutesInDay();
date.hasOffsetChangeInYear();
date.isInDst();
date.hasOffsetChangeInDay();
date.minutesInDay();

Alternatives:

FAQs:

Q: Does Qrono support time zones such as America/New_York or Europe/London?
A: Qrono supports UTC and the local time zone of the runtime environment. It does not provide arbitrary named IANA time-zone modeling.

Q: How does Qrono handle repeated times during daylight-saving changes?
A: Set localtime: true and choose a disambiguation value. Use earlier, later, compatible, or reject based on the business rule for your application.

Q: Does Qrono mutate existing values?
A: No. Setter methods, date calculations, and context changes return new Qrono or QronoDate instances. Store the returned value when you need the updated date.

Q: Why does a monthly range use isBefore() for the end value?
A: isBetween() includes both boundary values. A half-open range that starts at the first instant of a month and ends before the next month avoids edge cases around the final millisecond.

Q: What happens if I try to create a Qrono instance with an invalid date?
A: The library creates the instance normally. Call .valid() afterwards; it returns false for invalid dates, just like checking isNaN on a native Date.

Q: Can I use Qrono with React or Vue?
A: Absolutely. Qrono has no framework dependencies. Import it as a standard ES module and use its immutable instances in component state or computed properties without side effects.

Q: Does Qrono support time zones other than UTC and the local environment?
A: No. Qrono is built for single-timezone applications. It handles UTC and the system’s local time zone only. For multi‑time‑zone scenarios, keep everything in UTC or pair it with an IANA time zone library.

Q: How do I format dates with locale‑specific strings?
A: Qrono does not include formatting. Use .nativeDate() and pass it to Intl.DateTimeFormat or toLocaleString. This keeps the library small and delegates localization to the ECMAScript Internationalization API.

You Might Be Interested In:


Leave a Reply