--- url: 'https://qronojs.dev/index.md' description: A tiny JavaScript date library with 100+ APIs and strict DST guarantees. --- ## Quick Start ::: code-group ```sh [npm] npm install qrono ``` ```sh [bun] bunx jsr add @urin/qrono ``` ```sh [deno] deno add jsr:@urin/qrono ``` ```html [browser] ``` ::: ```javascript import { qrono } from 'qrono' // UTC-first const now = qrono().toString() // '2027-01-23T12:34:56:789Z' // DST overlap (occurs twice) of Europe/London qrono.context({ localtime: true }) const t = '2019-10-27T01:30:00' qrono(t) // 01:30 +00:00 Same as JavaScript's `Date` qrono({ disambiguation: 'earlier' }, t) // 01:30 +00:00 qrono({ disambiguation: 'later' }, t) // 01:30 +01:00 qrono({ disambiguation: 'reject' }, t) // throws RangeError now.plus(0, 1, 10) // +1 month, +10 days now.startOfMonth() now.isBetween(qrono('2024-01-01'), qrono('2024-12-31')) const date = qrono.date('2024-06-15') date.dayOfYear() // 167 date.weekOfYear() // 24 date.endOfMonth() // 2024-06-30 ``` ## Learn More * [Introduction](/introduction) - Design philosophy and getting started * [Concepts](/introduction#design-philosophy) - The principles behind the API * [DST Handling](/introduction#handling-daylight-saving-time) - Why ambiguous times are explicit * [Comparison](/comparison) - How Qrono differs from other libraries * [API Reference](/api/) - Complete API documentation --- --- url: 'https://qronojs.dev/introduction.md' description: >- Qrono design philosophy, installation, usage, UTC/local-time model, DST handling, and quick tour. --- # Introduction Qrono is a **tiny** JavaScript date library with **100+ APIs** and **strict DST guarantees**.\ Designed for *single-timezone* applications. ```javascript import { qrono } from 'qrono' // UTC-first const now = qrono().toString() // '2027-01-23T12:34:56:789Z' // DST overlap (occurs twice) of Europe/London qrono.context({ localtime: true }) const t = '2019-10-27T01:30:00' qrono(t) // 01:30 +00:00 Same as JavaScript's `Date` qrono({ disambiguation: 'earlier' }, t) // 01:30 +00:00 qrono({ disambiguation: 'later' }, t) // 01:30 +01:00 qrono({ disambiguation: 'reject' }, t) // throws RangeError now.plus(0, 1, 10) // +1 month, +10 days now.startOfMonth() now.isBetween(qrono('2024-01-01'), qrono('2024-12-31')) const date = qrono.date('2024-06-15') date.dayOfYear() // 167 date.weekOfYear() // 24 date.endOfMonth() // 2024-06-30 ``` ## Getting Started ::: code-group ```sh [npm] npm install qrono ``` ```sh [bun] bunx jsr add @urin/qrono ``` ```sh [deno] deno add jsr:@urin/qrono ``` ```html [browser] ``` ::: ### Usage ::: code-group ```javascript [npm] // ES modules import { qrono } from 'qrono' // CommonJS const { qrono } = require('qrono') ``` ```typescript [bun / deno] import { qrono } from '@urin/qrono' ``` ```html [browser] ``` ::: ## Design Philosophy #### 🌍 **UTC-first by Default, Local by Choice** * Keep storage and logic in UTC, and opt into local time only when needed. * Locale formatting is delegated to the [ECMAScript Internationalization API](https://402.ecma-international.org/#overview). #### 🕐 **DST is a First-Class Concept** * Ambiguous times are not hidden; they are modeled explicitly. * Dedicated APIs make overlap and gap behavior predictable. #### 🔐 **Immutable by Construction** * Every operation returns a new value, so chains are safe and reasoning stays simple. * The API is shaped for common workflows instead of edge-case completeness. #### ⚡ **Small Surface, Focused Power** * Pure JavaScript with zero dependencies. * A compact core with **100+** APIs through a tight, coherent design and a small compressed footprint. #### ✅ **Standards-Aligned** * Fully compliant with [ISO 8601](https://www.iso.org/obp/ui/#iso:std:iso:8601:-1:ed-1:v1:en) for interoperable date-time exchange. #### 🔷 **TypeScript Included** * First-class type definitions are part of the package. * Works consistently across server-side and browser-side JavaScript. ### Why Qrono? Other date-time libraries have larger codebases and more complicated usage to support multiple time zones and locales. Qrono takes a different approach: * **[Moment.js](https://momentjs.com/)**\ Strength: very familiar in legacy codebases. Tradeoff: mutable objects and maintenance-mode status. * **[Luxon](https://moment.github.io/luxon/)**\ Strength: rich feature set and timezone support. Tradeoff: ambiguous DST handling is not strict by default. * **[Day.js](https://day.js.org/)**\ Strength: tiny core and Moment-like API. Tradeoff: key features depend on plugins. * **[date-fns](https://date-fns.org/)**\ Strength: tree-shakable functional style. Tradeoff: inherits JavaScript `Date` quirks (mutability, 0-indexed months). None of these libraries provide APIs to detect or handle DST transitions properly. Qrono fills this gap with a balanced approach - not too simple, not too complex, just right. #### `Temporal` and `Intl`: Complementary, Not Competing JavaScript already provides **`Intl`** for locale-aware formatting, and **`Temporal`** covers broader multi-timezone workflows. Qrono is deliberately narrower: it stays small by delegating localization to `Intl` and by focusing on applications that only need UTC plus the runtime's local time zone. That makes the relationship complementary: use `Intl` for presentation, use `Temporal` when you need full time-zone modeling, and use Qrono when you want a lighter API for the common single-timezone case. ### Package Size Comparison The table below compares browser-ready distribution files from npm as of April 4, 2026.\ Versions are pinned explicitly, and the compressed sizes are measured from each published minified browser build. | Library | Version | Minified | gzip | brotli | | --------- | :-----: | -------: | ------: | ---------: | | *Qrono* | 1.5.0 | 11.6 kB | 3.7 kB | **3.3 kB** | | Day.js | 1.11.19 | 7.0 kB | 3.0 kB | 2.7 kB | | Luxon | 3.7.2 | 79.8 kB | 23.9 kB | 20.9 kB | | Moment.js | 2.30.1 | 57.5 kB | 18.4 kB | 16.6 kB | `date-fns` is intentionally excluded from this package-size table because it is designed for tree-shaking and is not meant to be evaluated as a single browser bundle. ### Repository Size Comparison [![Comparison of repository size](/comparison-repo-size.svg)](/comparison-repo-size.svg) This comparison shows that **Qrono stands out for its small codebase** among other libraries. Its compact size reflects a strong focus on minimalism and efficiency, making it well suited for situations where bundle size and simplicity are important. For many of the other libraries, their larger size is due to the fact that a significant portion of the codebase is dedicated to supporting a wide range of locales and time zones. Meanwhile, the larger size of `date-fns` is intentional and not a drawback. It is designed with tree-shaking in mind, so unused functions are removed at build time, and its API is intentionally fine-grained and verbose to provide clarity and flexibility. The size difference therefore represents a difference in design philosophy, not a measure of overall quality. ### Supporting Only the Local Time of the Execution Environment When handling time in a globally accessible web application, careful consideration is required for local time. #### Why Store in UTC In general, the server does not know the user’s actual time zone or the time zone of the client environment (OS). If the system needs to be aware of the user’s time zone, an application-level mechanism to manage time zones becomes necessary. For this reason, to keep the system design simple, the server should avoid managing user-specific time zones. Instead, the server should store and handle time exclusively in UTC. All time values should be transmitted to clients in UTC (typically as ISO 8601–formatted strings), and converting them into local time should be the responsibility of the client. Qrono is designed precisely for this model. Because it is UTC-first while also supporting the local time zone of the runtime environment, it works naturally on both sides of this architecture: servers can stay simple with UTC-based logic, and clients can reliably handle local-time behavior. Even when support for multiple locales is required, storing time data in UTC is usually sufficient. In most cases, locale-specific formatting can be handled entirely on the client side by using the [ECMAScript Internationalization API](https://402.ecma-international.org/#overview). #### Why Use the OS Time Zone In practice, the user’s time zone is usually assumed to be the same as the client environment’s (OS) time zone. For example, a user who resides in Japan may start using the application in the United States. If the user changes the OS time zone to match the local time in the United States, this will be done automatically in most cases, such as when the environment is a smart device; the client environment's time zone will differ from the one that is managed in the server. Considering the large number of such edge cases, it is impractical for a server-side application to manage each user's intended time zone in a database-like manner. #### Constraints and Exceptions One important caveat of this design is that the time zone database of the client environment (OS) must be properly maintained. Daylight saving time rules — for example, in Brazil — may change from year to year, and time zone definitions themselves are determined by laws that are frequently revised. This means that the underlying time zone database must be kept up to date. If the application is used in a closed or unmanaged environment where such updates cannot be applied due to special constraints, the approach described above may be insufficient. In most typical environments, this requirement is satisfied automatically through the operating system’s regular update mechanisms, so it does not pose a practical issue for the majority of applications. Considering these factors, **Qrono** is deliberately designed to forgo support for multiple time zones in order to achieve greater overall benefits, such as a **small code base and easy handling of daylight saving time transitions**. ### Handling Daylight Saving Time Qrono is the only JavaScript date-time library with dedicated APIs for DST handling ([`hasOffsetChangeInYear()`](./api/#hasOffsetChangeInYear), [`isInDst()`](./api/#isindst), [`hasOffsetChangeInDay()`](./api/#hasOffsetChangeInDay), [`minutesInDay()`](./api/#minutesinday)). JavaScript's `Date` object can behave in non-intuitive ways when handling daylight saving time transitions. For example, see the following scenario in the Central Standard Time (CST) zone of the USA: ```javascript const date = new Date('2021-03-14T03:00:00.000') date.setMilliseconds(-1) // results 2021-03-14 03:59:59.999 CST ``` On March 14, 2021, daylight saving time begins. The time jumps directly from `2021-03-14 01:59:59 CST` to `2021-03-14 03:00:00 CST`. In this example, subtracting 1 millisecond from `2021-03-14 03:00:00.000 CST` results in `2021-03-14 03:59:59.999 CST`. This appears to be a simple subtraction of 1 millisecond, but it actually advances the time by 1 hour. This behavior is not a bug but a result of strictly following the [ECMAScript specification](https://262.ecma-international.org/11.0/#sec-local-time-zone-adjustment). Additionally, a `Date` object created from a duplicated time during daylight saving time (DST) transition always refers to the time before DST ends. In other words, there is no simple way to obtain a `Date` object that refers to the UTC time **after** the end of DST from a duplicated time. **Qrono** addresses these issues by providing a more principled approach to handling such transitions. Ambiguous local times — those that fall in a DST gap (spring-forward) or overlap (fall-back) — are resolved through the `disambiguation` option, which mirrors the [`Temporal` API](https://tc39.es/proposal-temporal/docs/): ```javascript qrono.context({ localtime: true }) // Gap: 2019-03-31T01:30 does not exist in Europe/London qrono('2019-03-31T01:30') // → 02:30+01:00 (compatible, DST side) qrono({ disambiguation: 'earlier' }, '2019-03-31T01:30') // → 00:30+00:00 (standard side) qrono({ disambiguation: 'reject' }, '2019-03-31T01:30') // throws RangeError // Overlap: 2019-10-27T01:30 occurs twice in Europe/London qrono('2019-10-27T01:30') // → 01:30+00:00 (compatible, standard side) qrono({ disambiguation: 'later' }, '2019-10-27T01:30') // → 01:30+01:00 (standard side) ``` ## Quick Tour ### Construction ```javascript // now qrono() // from various types of arguments qrono('2022-12-31') // => 2022-12-31T00:00:00.000Z qrono(new Date()) // the following are the same 2022-12-31T15:23:11.321Z qrono('2022-12-31 15:23:11.321') qrono(1672500191321) qrono(2022, 12, 31, 15, 23, 11, 321) qrono([2022, 12, 31, 15, 23, 11, 321]) qrono({ year: 2022, month: 12, day: 31, hour: 15, minute: 23, second: 11, millisecond: 321 }) ``` ### Accessor ```javascript const time = qrono(2022, 12, 31, 15, 23, 11, 321) time.year() // => 2022 time.month() // => 12 time.day() // => 31 time.hour() // => 15 time.minute() // => 23 time.second() // => 11 time.millisecond() // => 321 time.second(0) // => returns new Qrono instance (immutable) ``` ### Time Zone ```javascript // UTC as default qrono('2022-12-31 15:23:11.321').toString() // => "2022-12-31T15:23:11.321Z" // set default to local time qrono.context({ localtime: true }) qrono('2022-12-31 15:23:11.321').toString() // => "2022-12-31T15:23:11.321-04:00" qrono('2022-12-31 15:23:11.321').context({ localtime: false }).hour() // => 11 as UTC qrono('2022-12-31 15:23:11.321').hour() // => 15 as local time ``` ### Conversion ```javascript +qrono('2000-01-01') // => 946,684,800,000 milliseconds from UNIX epoch const time = qrono('2000-01-02 03:04:05.006') time.toObject() // => { year: 2000, month: 1, day: 2, hour: 3, minute: 4, second: 5, millisecond: 6 } time.toArray() // => [2000, 1, 2, 3, 4, 5, 6] time.nativeDate() // => JavaScript native Date instance ``` ### Calculation and Comparison ```javascript qrono('2000-01-01 01:00:00.000') - qrono('2000-01-01') // => 3,600,000 milliseconds = 1 hour qrono('2000-01-01 01:00:00.000') < qrono('2000-01-01') // => false qrono('2000-01-01').plus(7200000).minus(3600000) // => 2000-01-01T01:00:00.000Z // In operations using Object, `year`, `month`, and `day` are calculated literally. // For example, adding one month at the end of a month results in the end of the following month. // `hour`, `minute`, `second`, and `millisecond` are treated as a duration in calculations. qrono('2000-01-01').minus({ hour: 1, minute: 30 }) // => 1999-12-31T22:30:00.000Z qrono('2020-02-29').plus({ year: 1 }) // => 2021-02-28T00:00:00.000Z qrono('2021-12-31').minus({ month: 1 }) // => 2021-11-30T00:00:00.000Z const today = qrono() const yesterday = today.minus({ day: 1 }) const tomorrow = today.plus({ day: 1 }) today.isBetween(yesterday, tomorrow) // => true ``` ### Short-hands ```javascript const time = qrono('2000-01-02 03:04:05.006') time.startOfYear() // => 2000-01-01T00:00:00.000Z time.startOfMonth() // => 2000-01-01T00:00:00.000Z time.startOfDay() // => 2000-01-02T00:00:00.000Z time.startOfHour() // => 2000-01-02T03:00:00.000Z time.startOfMinute() // => 2000-01-02T03:04:00.000Z time.startOfSecond() // => 2000-01-02T03:04:05.000Z time.dayOfWeek() // => 7 === qrono.sunday time.dayOfYear() // => 2 time.isLeapYear() // => true time.daysInMonth() // => 31 time.daysInYear() // => 366 // ISO week number. See https://en.wikipedia.org/wiki/ISO_week_date time.weeksInYear() // => 52 time.weekOfYear() // => 52 time.yearOfWeek() // => 1999 // Daylight saving time stuff that is meaningful in case of local time const localtime = time.context({ localtime: true }) localtime.hasOffsetChangeInYear() localtime.isInDst() localtime.hasOffsetChangeInDay() localtime.minutesInDay() ``` ### QronoDate `qrono.date(...)` returns a `QronoDate` instance with only date information. Methods of `QronoDate` are almost compatible with those of `Qrono`. ```javascript qrono.date('2000-01-02').toString() // => "2000-01-02" qrono('2000-01-02 23:04:05.006').toDate() // => QronoDate instance 2000-01-02 +qrono.date('2000-01-02') // => 10958 days from UNIX epoch ``` --- --- url: 'https://qronojs.dev/comparison.md' description: >- Side-by-side API comparison of Qrono, Temporal, Day.js, Moment.js, Luxon, and date-fns. --- # API Comparison This section compares Qrono's API against six popular date/time APIs and libraries — [TC39 `Temporal`](https://tc39.es/proposal-temporal/docs/), [Day.js](https://day.js.org/), [Moment.js](https://momentjs.com/), [Luxon](https://moment.github.io/luxon/), and [date-fns](https://date-fns.org/) — across common use cases. Use it as a quick reference to understand how each library approaches the same task and to evaluate which best fits your needs. ## Instance creation Qrono and Day.js use a single overloaded function. Luxon uses dedicated static factory methods per input type (`fromISO`, `fromJSDate`, `fromFormat`, …). ```ts // Current time qrono() // String // Almost compliant with ISO 8601 // String parsing format (i.e. dd/mm/yyyy) is NOT supported. qrono('2024-01-15 12:34:56') // Date object qrono(new Date()) // Millisecond timestamp qrono(1705286096000) // Spread arguments qrono(2024, 1, 15, 12, 34, 56, 0) // Array qrono([2024, 1, 15, 12, 34, 56, 0]) // Object qrono({ year: 2024, month: 1, day: 15 }) // Clone another instance qrono(another) ``` ```ts // Temporal has multiple strongly-typed entry points. // Current time (zoned datetime) Temporal.Now.zonedDateTimeISO('UTC') // ISO string with timezone/offset Temporal.ZonedDateTime.from('2024-01-15T12:34:56+00:00[UTC]') // Date object Temporal.Instant.fromEpochMilliseconds(new Date().getTime()) // Millisecond timestamp Temporal.Instant.fromEpochMilliseconds(1705286096000) // Date-only Temporal.PlainDate.from('2024-01-15') // Object Temporal.PlainDateTime.from({ year: 2024, month: 1, day: 15, hour: 12, minute: 34, second: 56, }) // Clone another instance Temporal.ZonedDateTime.from(another.toString()) ``` ```ts // Current time dayjs() // String dayjs('2024-01-15 12:34:56') // Date object dayjs(new Date()) // Millisecond timestamp dayjs(1705286096000) // Array dayjs([2024, 0, 15, 12, 34, 56, 0]) // Object dayjs({ year: 2024, month: 0, day: 15 }) // Clone another instance dayjs(another) ``` ```ts // Current time moment() // String moment('2024-01-15 12:34:56') // Date object moment(new Date()) // Millisecond timestamp moment(1705286096000) // Array moment([2024, 0, 15, 12, 34, 56, 0]) // Object moment({ year: 2024, month: 0, day: 15 }) // Clone another instance moment(another) ``` ```ts // Current time DateTime.now() // ISO string DateTime.fromISO('2024-01-15T12:34:56') // Date object DateTime.fromJSDate(new Date()) // Millisecond timestamp DateTime.fromMillis(1705286096000) // Object DateTime.fromObject({ year: 2024, month: 1, day: 15, }) // Format string DateTime.fromFormat('2024-01-15', 'yyyy-MM-dd') ``` ```ts import { parseISO, parse } from 'date-fns' // ISO string parseISO('2024-01-15T12:34:56') // Format string parse('2024-01-15', 'yyyy-MM-dd', new Date()) ``` ## DST gap/overlap handling When a local time string falls in a DST gap or overlap, each library must resolve the ambiguity differently. `Temporal` and Day.js default to the DST-active (later) offset in overlap cases, like JavaScript's `Date`. Luxon defaults to the standard (earlier) offset in overlap cases. Qrono defaults to `'compatible'` — gap times are forwarded to the later (DST) side, overlap times use the earlier (standard-time) side — and uniquely exposes all four resolution strategies via its `disambiguation` option, mirroring the [`Temporal` API](https://tc39.es/proposal-temporal/docs/). Europe/London DST is used here as an example. For `Temporal`, `timeZone` must be explicit in this example so `disambiguation` is resolved deterministically for Europe/London. * Spring forward (Gap)\ 2019-03-31 01:00 → 2019-03-31 02:00 (+00:00 → +01:00) * Fall back (Overlap)\ 2019-10-27 02:00 → 2019-10-27 01:00 (+01:00 → +00:00) ### Gap (non-existent local time) ```ts const input = '2019-03-31T01:30:00' qrono.context({ localtime: true }) // defaults localtime qrono(input) // Qrono 2019-03-31T02:30+01:00 qrono({ disambiguation: 'earlier' }, input) // Qrono 2019-03-31T00:30+00:00 qrono({ disambiguation: 'later' }, input) // Qrono 2019-03-31T02:30+01:00 qrono({ disambiguation: 'reject' }, input) // Qrono throws RangeError dayjs(input) // Day.js 2019-03-31T02:30+01:00 moment.tz(input, 'Europe/London') // Moment 2019-03-31T02:30+01:00 DateTime.fromISO(input) // Luxon 2019-03-31T02:30+01:00 parseISO(input) // date-fns 2019-03-31T02:30+01:00 Temporal.ZonedDateTime.from({ // Temporal (compatible) 2019-03-31T02:30+01:00 year: 2019, month: 3, day: 31, hour: 1, minute: 30, timeZone: 'Europe/London', }) Temporal.ZonedDateTime.from( // Temporal (earlier) 2019-03-31T00:30+00:00 { year: 2019, month: 3, day: 31, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'earlier' }, ) Temporal.ZonedDateTime.from( // Temporal (later) 2019-03-31T02:30+01:00 { year: 2019, month: 3, day: 31, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'later' }, ) Temporal.ZonedDateTime.from( // Temporal (reject) throws RangeError { year: 2019, month: 3, day: 31, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'reject' }, ) ``` ### Overlap (duplicated local time) ```ts const input = '2019-10-27T01:30:00' qrono.context({ localtime: true }) // defaults localtime qrono(input) // Qrono 2019-10-27T01:30+00:00 qrono({ disambiguation: 'earlier' }, input) // Qrono 2019-10-27T01:30+00:00 qrono({ disambiguation: 'later' }, input) // Qrono 2019-10-27T01:30+01:00 qrono({ disambiguation: 'reject' }, input) // Qrono throws RangeError dayjs(input) // Day.js 2019-10-27T01:30+01:00 moment.tz(input, 'Europe/London') // Moment 2019-10-27T01:30+01:00 DateTime.fromISO(input) // Luxon 2019-10-27T01:30+00:00 parseISO(input) // date-fns 2019-10-27T01:30+01:00 Temporal.ZonedDateTime.from({ // Temporal (compatible) 2019-10-27T01:30+01:00 year: 2019, month: 10, day: 27, hour: 1, minute: 30, timeZone: 'Europe/London', }) Temporal.ZonedDateTime.from( // Temporal (earlier) 2019-10-27T01:30+00:00 { year: 2019, month: 10, day: 27, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'earlier' }, ) Temporal.ZonedDateTime.from( // Temporal (later) 2019-10-27T01:30+01:00 { year: 2019, month: 10, day: 27, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'later' }, ) Temporal.ZonedDateTime.from( // Temporal (reject) throws RangeError { year: 2019, month: 10, day: 27, hour: 1, minute: 30, timeZone: 'Europe/London' }, { disambiguation: 'reject' }, ) ``` ## Date-only instance Qrono provides a dedicated `QronoDate` type for calendar dates with no time component. `Temporal` also has a dedicated `PlainDate` type. Other libraries represent date-only values as a datetime at midnight, which can be affected by timezone handling. ```ts // Current date qrono.date() // String qrono.date('2024-01-15') // Date object qrono.date(new Date()) // Object qrono.date({ year: 2024, month: 1, day: 15 }) ``` ```ts // Current date Temporal.Now.plainDateISO() // String Temporal.PlainDate.from('2024-01-15') // Date object Temporal.PlainDate.from( new Date().toISOString().slice(0, 10), ) // Object Temporal.PlainDate.from({ year: 2024, month: 1, day: 15 }) ``` ```ts // Not available ``` ```ts // Not available ``` ```ts // Not available ``` ```ts // Not available ``` ## DST information Only Qrono and Luxon provide dedicated DST methods (`isInDst` / `isInDST`) directly. ```ts qrono.context({ localtime: true }) // Whether DST is currently active qrono('2024-07-15').isInDst() // Whether the year has DST at all qrono('2024-07-15').hasOffsetChangeInYear() // Whether the day is a DST transition day qrono('2024-03-10').hasOffsetChangeInDay() // Minutes in the day considering DST qrono('2024-03-10').minutesInDay() ``` ```ts // Not available ``` ```ts // Not available ``` ```ts // Not available ``` ```ts // Whether DST is currently active DateTime.local().isInDST ``` ```ts // Not available ``` ## Timezone Qrono supports UTC and the runtime's local timezone only; arbitrary IANA timezone IDs are **NOT** supported. `Temporal` and Luxon support named timezones natively; Day.js and Moment.js support them via plugins; date-fns handles timezone conversion through the companion `date-fns-tz` package. ```ts // Local time (runtime environment TZ) qrono({ localtime: true }, '2024-01-15 12:00') // UTC (default) qrono('2024-01-15 12:00') // Switch an instance to local time qrono('2024-01-15 12:00').context({ localtime: true }) // Switch an instance to UTC qrono({ localtime: true }, '2024-01-15 12:00').context({ localtime: false }) // Note: arbitrary TZID is NOT supported ``` ```ts // UTC Temporal.ZonedDateTime.from('2024-01-15T12:00:00+00:00[UTC]') // Arbitrary timezone Temporal.ZonedDateTime.from({ year: 2024, month: 1, day: 15, hour: 12, minute: 0, timeZone: 'America/New_York', }) // Convert timezone (same instant) Temporal.ZonedDateTime .from('2024-01-15T12:00:00+00:00[UTC]') .withTimeZone('America/New_York') ``` ```ts import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import timezone from 'dayjs/plugin/timezone' dayjs.extend(utc) dayjs.extend(timezone) // UTC dayjs.utc('2024-01-15 12:00') // Arbitrary timezone dayjs.tz('2024-01-15 12:00', 'America/New_York') // Convert timezone dayjs('2024-01-15 12:00').tz('America/New_York') ``` ```ts import moment from 'moment-timezone' // UTC moment.utc('2024-01-15 12:00') // Arbitrary timezone moment.tz('2024-01-15 12:00', 'America/New_York') // Convert timezone moment('2024-01-15 12:00').tz('America/New_York') ``` ```ts // UTC DateTime.fromISO('2024-01-15T12:00:00', { zone: 'utc', }) // Arbitrary timezone DateTime.fromISO('2024-01-15T12:00:00', { zone: 'America/New_York', }) // Convert timezone DateTime.now().setZone('America/New_York') ``` ```ts import { fromZonedTime, toZonedTime } from 'date-fns-tz' // Convert local time to UTC fromZonedTime('2024-01-15 12:00', 'America/New_York') // Convert UTC to a specific timezone toZonedTime(new Date(), 'America/New_York') ``` ## Timezone offset All libraries can expose UTC offset information, but units and APIs differ. Qrono/Day.js/Moment.js/Luxon use minutes; `Temporal` uses nanoseconds and offset strings; date-fns-tz returns milliseconds and requires an explicit IANA timezone ID. Note that the native `Date.prototype.getTimezoneOffset()` uses the opposite sign convention (positive = west of UTC). ```ts // Offset in minutes, positive = east of UTC qrono({ localtime: true }).offset() // e.g. JST => 540 ``` ```ts const zdt = Temporal.Now.zonedDateTimeISO('Asia/Tokyo') // Offset in nanoseconds zdt.offsetNanoseconds // e.g. JST => 32400000000000 // Offset as string zdt.offset // e.g. '+09:00' // Offset in minutes, positive = east of UTC zdt.offsetNanoseconds / (60 * 1_000_000_000) // e.g. JST => 540 ``` ```ts import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' dayjs.extend(utc) // Offset in minutes, positive = east of UTC dayjs().utcOffset() // e.g. JST => 540 ``` ```ts // Offset in minutes, positive = east of UTC moment().utcOffset() // e.g. JST => 540 // Offset as string moment().format('Z') // e.g. '+09:00' ``` ```ts // Offset in minutes DateTime.local().offset // e.g. JST => 540 // Offset as string DateTime.local().offsetNameShort // e.g. 'JST' ``` ```ts import { getTimezoneOffset } from 'date-fns-tz' // Offset in milliseconds getTimezoneOffset('America/New_York', new Date()) // e.g. -18000000 ``` ## Converting All libraries convert to a native `Date`, millisecond timestamp, ISO 8601 string, and plain object. Day.js and Luxon include a built-in format method for custom strings; Qrono delegates that to `Intl.DateTimeFormat` (see [Formatting](#formatting)). ```ts const dt = qrono('2024-01-15 12:34:56.789') // Native Date dt.nativeDate() // Millisecond timestamp dt.valueOf() // Object dt.toObject() // { year, month, day, hour, minute, second, millisecond } // Array dt.toArray() // [2024, 1, 15, 12, 34, 56, 789] // QronoDate (date only) dt.toDate() // ISO 8601 string dt.toString() ``` ```ts const zdt = Temporal.ZonedDateTime.from( '2024-01-15T12:34:56.789+00:00[UTC]', ) // Native Date new Date(zdt.epochMilliseconds) // Millisecond timestamp zdt.epochMilliseconds // Object zdt.getISOFields() // ISO 8601 string zdt.toString() // Date-only zdt.toPlainDate() ``` ```ts const dt = dayjs('2024-01-15T12:34:56.789') // Native Date dt.toDate() // Millisecond timestamp dt.valueOf() // Object dt.toObject() // { years, months, date, hours, minutes, seconds, milliseconds } // Array dt.toArray() // [2024, 0, 15, 12, 34, 56, 789] // ISO 8601 string dt.toISOString() // Custom format string dt.format('YYYY-MM-DD HH:mm:ss') ``` ```ts const dt = moment('2024-01-15T12:34:56.789') // Native Date dt.toDate() // Millisecond timestamp dt.valueOf() // Object dt.toObject() // Array dt.toArray() // ISO 8601 string dt.toISOString() // Custom format string dt.format('YYYY-MM-DD HH:mm:ss') ``` ```ts const dt = DateTime.fromISO('2024-01-15T12:34:56.789') // Native Date dt.toJSDate() // Millisecond timestamp dt.toMillis() // or dt.valueOf() // Object dt.toObject() // { year, month, day, hour, minute, second, millisecond } // ISO 8601 string dt.toISO() // Custom format string dt.toFormat('yyyy-MM-dd HH:mm:ss') ``` ```ts import { format } from 'date-fns' // ISO 8601 string const d = new Date('2024-01-15T12:34:56.789').toISOString() // Custom format string format(d, 'yyyy-MM-dd HH:mm:ss') ``` ## Arithmetic Qrono's `plus`/`minus` accept spread arguments, object, array, or a raw millisecond number. `Temporal` and Luxon use object-based duration units; Day.js and Moment.js use `(value, unit)`; date-fns provides individual functions per unit (`addMonths`, `addDays`, …). For differences, Qrono and date-fns typically return plain numbers; `Temporal`/Luxon/Moment.js can produce Duration-like objects (see [Duration](#duration)). ```ts const dt = qrono('2024-01-15 12:00:00') // Addition (spread: year, month, day, h, m, s, ms) dt.plus(0, 1, 10) // +1 month, +10 days dt.plus({ month: 1, day: 10 }) dt.plus([0, 1, 10]) dt.plus(3600 * 1000) // +1 hour (ms) // Subtraction dt.minus(0, 0, 7) // -7 days dt.minus({ day: 7 }) dt.minus(3600 * 1000) // Difference (ms) dt.valueOf() - qrono('2024-01-01').valueOf() ``` ```ts const dt = Temporal.ZonedDateTime.from( '2024-01-15T12:00:00+00:00[UTC]', ) // Addition dt.add({ months: 1, days: 10 }) dt.add({ hours: 1 }) // Subtraction dt.subtract({ days: 7 }) dt.subtract({ hours: 1 }) // Difference Temporal.ZonedDateTime .from('2024-01-01T00:00:00+00:00[UTC]') .until(dt, { largestUnit: 'day' }) .days ``` ```ts const dt = dayjs('2024-01-15 12:00:00') // Addition dt.add(1, 'month').add(10, 'day') dt.add(1, 'hour') // Subtraction dt.subtract(7, 'day') dt.subtract(1, 'hour') // Difference dt.diff(dayjs('2024-01-01'), 'day') ``` ```ts const dt = moment('2024-01-15 12:00:00') // Addition dt.add(1, 'month').add(10, 'day') dt.add(1, 'hour') // Subtraction dt.subtract(7, 'day') dt.subtract(1, 'hour') // Difference dt.diff(moment('2024-01-01'), 'day') ``` ```ts const dt = DateTime.fromISO('2024-01-15T12:00:00') // Addition dt.plus({ months: 1, days: 10 }) dt.plus({ hours: 1 }) // Subtraction dt.minus({ days: 7 }) dt.minus({ hours: 1 }) // Difference dt.diff(DateTime.fromISO('2024-01-01'), 'days').days ``` ```ts import { addMonths, addDays, addHours, subDays, subHours, differenceInDays, } from 'date-fns' const d = new Date('2024-01-15T12:00:00') // Addition addMonths(addDays(d, 10), 1) addHours(d, 1) // Subtraction subDays(d, 7) subHours(d, 1) // Difference differenceInDays(d, new Date('2024-01-01')) ``` ## Comparing Qrono, Day.js (with plugins), and Moment.js provide all six comparison methods as named methods. `Temporal` uses `compare()`/`equals()` static and instance APIs. Luxon relies on native comparison operators (`<`, `>`, `<=`, `>=`) for ordering and `Interval.contains()` for range checks. date-fns provides `isBefore`, `isAfter`, and `isEqual` as functions, and falls back to native operators for the rest. ```ts const a = qrono('2024-01-15') const b = qrono('2024-06-01') a.isBefore(b) // true a.isAfter(b) // false a.isSame(b) // false a.isSameOrBefore(b) // true a.isSameOrAfter(b) // false a.isBetween(qrono('2024-01-01'), qrono('2024-12-31')) // true ``` ```ts const a = Temporal.Instant.from('2024-01-15T00:00:00Z') const b = Temporal.Instant.from('2024-06-01T00:00:00Z') Temporal.Instant.compare(a, b) < 0 // true (isBefore) Temporal.Instant.compare(a, b) > 0 // false (isAfter) a.equals(b) // false Temporal.Instant.compare(a, b) <= 0 // true (isSameOrBefore) Temporal.Instant.compare(a, b) >= 0 // false (isSameOrAfter) const start = Temporal.Instant.from('2024-01-01T00:00:00Z') const end = Temporal.Instant.from('2024-12-31T23:59:59Z') Temporal.Instant.compare(a, start) >= 0 && Temporal.Instant.compare(a, end) <= 0 // true (isBetween) ``` ```ts import dayjs from 'dayjs' import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' import isSameOrAfter from 'dayjs/plugin/isSameOrAfter' import isBetween from 'dayjs/plugin/isBetween' dayjs.extend(isSameOrBefore) dayjs.extend(isSameOrAfter) dayjs.extend(isBetween) const a = dayjs('2024-01-15') const b = dayjs('2024-06-01') a.isBefore(b) // true a.isAfter(b) // false a.isSame(b) // false a.isSameOrBefore(b) // true (plugin) a.isSameOrAfter(b) // false (plugin) a.isBetween(dayjs('2024-01-01'), dayjs('2024-12-31')) // true (plugin) ``` ```ts const a = moment('2024-01-15') const b = moment('2024-06-01') a.isBefore(b) // true a.isAfter(b) // false a.isSame(b) // false a.isSameOrBefore(b) // true a.isSameOrAfter(b) // false a.isBetween(moment('2024-01-01'), moment('2024-12-31')) // true ``` ```ts import { DateTime, Interval } from 'luxon' const a = DateTime.fromISO('2024-01-15') const b = DateTime.fromISO('2024-06-01') a < b // true (isBefore) a > b // false (isAfter) a.equals(b) // false a <= b // true (isSameOrBefore) a >= b // false (isSameOrAfter) Interval.fromDateTimes( DateTime.fromISO('2024-01-01'), DateTime.fromISO('2024-12-31'), ).contains(a) // true (isBetween) ``` ```ts import { isBefore, isAfter, isEqual, isWithinInterval } from 'date-fns' const a = new Date('2024-01-15') const b = new Date('2024-06-01') isBefore(a, b) // true isAfter(a, b) // false isEqual(a, b) // false a <= b // true (isSameOrBefore) a >= b // false (isSameOrAfter) isWithinInterval(a, { start: new Date('2024-01-01'), end: new Date('2024-12-31'), }) // true ``` ## Start/End boundaries Day.js, Moment.js, Luxon, and date-fns use a generic `startOf(unit)` / `endOf(unit)` style down to the hour level. Qrono uses dedicated methods per granularity (`startOfYear()`, `startOfMonth()`, …) but does not provide `endOf` on `Qrono` instances; `endOfYear()` and `endOfMonth()` are available on `QronoDate` only. `Temporal` composes equivalent behavior via immutable field updates. ```ts const dt = qrono('2024-06-15 12:34:56') dt.startOfYear() // 2024-01-01 00:00:00 dt.startOfMonth() // 2024-06-01 00:00:00 dt.startOfDay() // 2024-06-15 00:00:00 dt.startOfHour() // 2024-06-15 12:00:00 dt.startOfMinute() // 2024-06-15 12:34:00 dt.startOfSecond() // 2024-06-15 12:34:56 qrono.date('2024-06-15').endOfYear() // => QronoDate: 2024-12-31 qrono.date('2024-06-15').endOfMonth() // => QronoDate: 2024-06-30 ``` ```ts const zdt = Temporal.ZonedDateTime.from( '2024-06-15T12:34:56+00:00[UTC]', ) zdt.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }) zdt.with({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }) zdt.startOfDay() zdt.with({ minute: 0, second: 0, millisecond: 0 }) zdt.with({ second: 0, millisecond: 0 }) zdt.with({ millisecond: 0 }) // Generic endOf is not available as a built-in ``` ```ts const dt = dayjs('2024-06-15 12:34:56') dt.startOf('year') // 2024-01-01 00:00:00 dt.startOf('month') // 2024-06-01 00:00:00 dt.startOf('day') // 2024-06-15 00:00:00 dt.startOf('hour') // 2024-06-15 12:00:00 dt.startOf('minute') // 2024-06-15 12:34:00 dt.startOf('second') // 2024-06-15 12:34:56 dt.endOf('year') // 2024-12-31 23:59:59 dt.endOf('month') // 2024-06-30 23:59:59 dt.endOf('day') // 2024-06-15 23:59:59 dt.endOf('hour') // 2024-06-15 12:59:59 ``` ```ts const dt = moment('2024-06-15 12:34:56') dt.startOf('year') // 2024-01-01 00:00:00 dt.startOf('month') // 2024-06-01 00:00:00 dt.startOf('day') // 2024-06-15 00:00:00 dt.startOf('hour') // 2024-06-15 12:00:00 dt.startOf('minute') // 2024-06-15 12:34:00 dt.startOf('second') // 2024-06-15 12:34:56 dt.endOf('year') // 2024-12-31 23:59:59 dt.endOf('month') // 2024-06-30 23:59:59 dt.endOf('day') // 2024-06-15 23:59:59 dt.endOf('hour') // 2024-06-15 12:59:59 ``` ```ts const dt = DateTime.fromISO('2024-06-15T12:34:56') dt.startOf('year') // 2024-01-01 00:00:00 dt.startOf('month') // 2024-06-01 00:00:00 dt.startOf('day') // 2024-06-15 00:00:00 dt.startOf('hour') // 2024-06-15 12:00:00 dt.startOf('minute') // 2024-06-15 12:34:00 dt.startOf('second') // 2024-06-15 12:34:56 dt.endOf('year') // 2024-12-31 23:59:59 dt.endOf('month') // 2024-06-30 23:59:59 dt.endOf('day') // 2024-06-15 23:59:59 dt.endOf('hour') // 2024-06-15 12:59:59 ``` ```ts import { startOfYear, startOfMonth, startOfDay, startOfHour, startOfMinute, startOfSecond, endOfYear, endOfMonth, endOfDay, endOfHour, } from 'date-fns' const d = new Date('2024-06-15T12:34:56') startOfYear(d) // 2024-01-01 00:00:00 startOfMonth(d) // 2024-06-01 00:00:00 startOfDay(d) // 2024-06-15 00:00:00 startOfHour(d) // 2024-06-15 12:00:00 startOfMinute(d) // 2024-06-15 12:34:00 startOfSecond(d) // 2024-06-15 12:34:56 endOfYear(d) // 2024-12-31 23:59:59 endOfMonth(d) // 2024-06-30 23:59:59 endOfDay(d) // 2024-06-15 23:59:59 endOfHour(d) // 2024-06-15 12:59:59 ``` ## Day and Week All compared APIs can retrieve day-of-year and ISO week/year with different method/property names. Day.js may require plugins. `daysInYear` and `weeksInYear` availability differs by library (`Temporal` and Qrono expose both directly). ```ts const dt = qrono('2024-06-15 12:00:00') // Day of year dt.dayOfYear() // e.g. 167 // ISO week of year dt.weekOfYear() // e.g. 24 dt.yearOfWeek() // ISO week year, e.g. 2024 // Total days in the year dt.daysInYear() // 366 (leap year) // Total ISO weeks in the year dt.weeksInYear() // e.g. 52 // Also available on QronoDate qrono.date('2024-06-15').dayOfYear() qrono.date('2024-06-15').weekOfYear() qrono.date('2024-06-15').daysInYear() qrono.date('2024-06-15').weeksInYear() ``` ```ts const dt = Temporal.PlainDate.from('2024-06-15') // Day of year dt.dayOfYear // e.g. 167 // ISO week of year dt.weekOfYear // e.g. 24 dt.yearOfWeek // e.g. 2024 // Total days in the year dt.daysInYear // 366 // Total ISO weeks in the year dt.weeksInYear // e.g. 52 ``` ```ts import dayjs from 'dayjs' import dayOfYear from 'dayjs/plugin/dayOfYear' import weekOfYear from 'dayjs/plugin/weekOfYear' import weekYear from 'dayjs/plugin/weekYear' import isLeapYear from 'dayjs/plugin/isLeapYear' dayjs.extend(dayOfYear) dayjs.extend(weekOfYear) dayjs.extend(weekYear) dayjs.extend(isLeapYear) const dt = dayjs('2024-06-15 12:00:00') // Day of year dt.dayOfYear() // e.g. 167 // ISO week of year dt.week() // e.g. 24 dt.weekYear() // e.g. 2024 // Total days in the year // Not available dt.isLeapYear() ? 366 : 365 // Total ISO weeks in the year // Not available ``` ```ts const dt = moment('2024-06-15 12:00:00') // Day of year dt.dayOfYear() // e.g. 167 // ISO week of year dt.isoWeek() // e.g. 24 dt.isoWeekYear() // e.g. 2024 // Total days in the year dt.isLeapYear() ? 366 : 365 // Total ISO weeks in the year dt.isoWeeksInYear() // e.g. 52 ``` ```ts const dt = DateTime.fromISO('2024-06-15T12:00:00') // Day of year dt.ordinal // e.g. 167 // ISO week of year dt.weekNumber // e.g. 24 dt.weekYear // e.g. 2024 // Total days in the year dt.daysInYear // 366 // Total ISO weeks in the year // Not available ``` ```ts import { getDayOfYear, getISOWeek, getISOWeekYear, getISOWeeksInYear, isLeapYear, } from 'date-fns' const d = new Date('2024-06-15T12:00:00') // Day of year getDayOfYear(d) // e.g. 167 // ISO week of year getISOWeek(d) // e.g. 24 getISOWeekYear(d) // e.g. 2024 // Total days in the year // Not available isLeapYear(d) ? 366 : 365 // Total ISO weeks in the year getISOWeeksInYear(d) // e.g. 52 ``` ## Get / Set Qrono and Day.js use the same method name for both get (no argument) and set (with argument). Moment.js is similar and mutable. `Temporal` and Luxon use read-only property accessors for get and object-based immutable updates (`with` / `set`). date-fns provides individual `getX` / `setX` functions. Note that Day.js/Moment.js/date-fns months are **0-indexed** while Qrono/`Temporal`/Luxon use **1-indexed** months. ```ts const dt = qrono('2024-06-15 12:34:56.789') // Get dt.year() // 2024 dt.month() // 6 (1-indexed) dt.day() // 15 dt.hour() // 12 dt.minute() // 34 dt.second() // 56 dt.millisecond() // 789 dt.dayOfWeek() // 6 (1=Mon ... 7=Sun, ISO 8601) // Set (returns new instance) dt.year(2025) dt.month(1) dt.day(1) dt.hour(0) dt.minute(0) dt.second(0) dt.millisecond(0) ``` ```ts const dt = Temporal.PlainDateTime.from('2024-06-15T12:34:56.789') // Get (property accessors) dt.year // 2024 dt.month // 6 dt.day // 15 dt.hour // 12 dt.minute // 34 dt.second // 56 dt.millisecond // 789 dt.dayOfWeek // 6 (1=Mon ... 7=Sun) // Set (returns new instance) dt.with({ year: 2025 }) dt.with({ month: 1, day: 1 }) dt.with({ hour: 0, minute: 0, second: 0, millisecond: 0 }) ``` ```ts const dt = dayjs('2024-06-15 12:34:56.789') // Get dt.year() // 2024 dt.month() // 5 (0-indexed!) dt.date() // 15 dt.hour() // 12 dt.minute() // 34 dt.second() // 56 dt.millisecond() // 789 dt.day() // 6 (0=Sun ... 6=Sat) // Generic getter/setter dt.get('year') dt.set('year', 2025) dt.set('month', 0) // 0-indexed dt.set('date', 1) ``` ```ts const dt = moment('2024-06-15 12:34:56.789') // Get dt.year() // 2024 dt.month() // 5 (0-indexed) dt.date() // 15 dt.hour() // 12 dt.minute() // 34 dt.second() // 56 dt.millisecond() // 789 dt.day() // 6 (0=Sun ... 6=Sat) // Set (mutable) dt.year(2025) dt.month(0) dt.date(1) dt.hour(0) dt.minute(0) dt.second(0) dt.millisecond(0) ``` ```ts const dt = DateTime.fromISO('2024-06-15T12:34:56.789') // Get (property accessors) dt.year // 2024 dt.month // 6 (1-indexed) dt.day // 15 dt.hour // 12 dt.minute // 34 dt.second // 56 dt.millisecond // 789 dt.weekday // 6 (1=Mon ... 7=Sun, ISO 8601) // Set (returns new instance) dt.set({ year: 2025 }) dt.set({ month: 1, day: 1 }) ``` ```ts import { getYear, getMonth, getDate, getHours, getMinutes, getSeconds, getMilliseconds, getDay, setYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, } from 'date-fns' const d = new Date('2024-06-15T12:34:56.789') // Get getYear(d) // 2024 getMonth(d) // 5 (0-indexed!) getDate(d) // 15 getHours(d) // 12 getMinutes(d) // 34 getSeconds(d) // 56 getMilliseconds(d) // 789 getDay(d) // 6 (0=Sun ... 6=Sat) // Set (returns new Date) setYear(d, 2025) setMonth(d, 0) // 0-indexed setDate(d, 1) setHours(d, 0) ``` ## Validation Validity handling differs by API. Qrono/Day.js/Moment.js expose `valid()` / `isValid()` methods, Luxon uses `isValid` properties with reasons, date-fns has standalone `isValid()`, and `Temporal` throws `RangeError` for invalid values. ```ts qrono('2024-01-15').valid() // true qrono('invalid').valid() // false qrono(NaN).valid() // false // QronoDate qrono.date('2024-01-15').valid() // true qrono.date('invalid').valid() // false ``` ```ts // Temporal throws on invalid input. Temporal.PlainDate.from('2024-01-15') // valid try { Temporal.PlainDate.from('invalid') } catch (e) { e instanceof RangeError // true } ``` ```ts dayjs('2024-01-15').isValid() // true dayjs('invalid').isValid() // false dayjs(NaN).isValid() // false ``` ```ts moment('2024-01-15').isValid() // true moment('invalid').isValid() // false moment(NaN).isValid() // false ``` ```ts DateTime.fromISO('2024-01-15').isValid // true DateTime.fromISO('invalid').isValid // false // Detailed reason for invalidity DateTime.fromISO('invalid').invalidReason // e.g. 'unparsable' DateTime.fromISO('invalid').invalidExplanation ``` ```ts import { isValid, parseISO } from 'date-fns' isValid(parseISO('2024-01-15')) // true isValid(parseISO('invalid')) // false isValid(new Date('invalid')) // false isValid(NaN) // false ``` ## Formatting Day.js and Moment.js use `YYYY`-style tokens; Luxon and date-fns use `yyyy`-style tokens (Unicode CLDR). Qrono and `Temporal` have **NO** built-in custom token formatter and delegate to [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). ```ts const dt = qrono('2024-06-15 12:34:56') // ISO 8601 (built-in) dt.toString() // '2024-06-15T12:34:56.000Z' // Custom format via Intl.DateTimeFormat new Intl.DateTimeFormat('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false, }).format(dt.nativeDate()) // e.g. '06/15/2024, 12:34:56' ``` ```ts const zdt = Temporal.ZonedDateTime.from( '2024-06-15T12:34:56+00:00[UTC]', ) // ISO 8601 (built-in) zdt.toString() // '2024-06-15T12:34:56+00:00[UTC]' // Custom format via Intl.DateTimeFormat new Intl.DateTimeFormat('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false, timeZone: 'UTC', }).format(new Date(zdt.epochMilliseconds)) ``` ```ts const dt = dayjs('2024-06-15 12:34:56') // ISO 8601 dt.toISOString() // '2024-06-15T12:34:56.000Z' // Custom format (Moment.js-compatible tokens) dt.format('YYYY-MM-DD HH:mm:ss') // '2024-06-15 12:34:56' dt.format('ddd, MMM D YYYY') // 'Sat, Jun 15 2024' ``` ```ts const dt = moment('2024-06-15 12:34:56') // ISO 8601 dt.toISOString() // '2024-06-15T12:34:56.000Z' // Custom format (Moment.js tokens) dt.format('YYYY-MM-DD HH:mm:ss') // '2024-06-15 12:34:56' dt.format('ddd, MMM D YYYY') // 'Sat, Jun 15 2024' ``` ```ts const dt = DateTime.fromISO('2024-06-15T12:34:56') // ISO 8601 dt.toISO() // '2024-06-15T12:34:56.000Z' // Custom format (CLDR tokens) dt.toFormat('yyyy-MM-dd HH:mm:ss') // '2024-06-15 12:34:56' dt.toFormat('EEE, MMM d yyyy') // 'Sat, Jun 15 2024' ``` ```ts import { format } from 'date-fns' import { ja } from 'date-fns/locale' const d = new Date('2024-06-15T12:34:56') // Custom format (CLDR tokens) format(d, 'yyyy-MM-dd HH:mm:ss') // '2024-06-15 12:34:56' format(d, 'EEE, MMM d yyyy') // 'Sat, Jun 15 2024' ``` ## Locale / i18n Qrono, `Temporal`, and Luxon rely on the runtime's `Intl` API with no locale files to import. Day.js and Moment.js use locale packs. date-fns requires importing locale objects per call site, which allows fine-grained tree-shaking. ```ts // Qrono delegates locale handling to Intl APIs. // No built-in locale configuration is needed. const dt = qrono('2024-06-15 12:34:56') const d = dt.nativeDate() // Localized month name new Intl.DateTimeFormat('fr-FR', { month: 'long' }).format(d) // 'juin' // Localized weekday new Intl.DateTimeFormat('de-DE', { weekday: 'long' }).format(d) // 'Samstag' // Localized full date new Intl.DateTimeFormat('ja-JP', { dateStyle: 'full' }).format(d) // '2024年6月15日土曜日' ``` ```ts // Temporal delegates locale handling to Intl APIs. const zdt = Temporal.ZonedDateTime.from( '2024-06-15T12:34:56+00:00[UTC]', ) const d = new Date(zdt.epochMilliseconds) new Intl.DateTimeFormat('fr-FR', { month: 'long', timeZone: 'UTC' }).format(d) new Intl.DateTimeFormat('de-DE', { weekday: 'long', timeZone: 'UTC' }).format(d) new Intl.DateTimeFormat('ja-JP', { dateStyle: 'full', timeZone: 'UTC' }).format(d) ``` ```ts import dayjs from 'dayjs' import 'dayjs/locale/fr' import 'dayjs/locale/de' import 'dayjs/locale/ja' import localizedFormat from 'dayjs/plugin/localizedFormat' dayjs.extend(localizedFormat) // Set global locale dayjs.locale('ja') // Or per-instance locale const dt = dayjs('2024-06-15').locale('fr') // Localized month name dt.locale('fr').format('MMMM') // 'juin' // Localized weekday dt.locale('de').format('dddd') // 'Samstag' // Localized date format dt.locale('ja').format('LL') // '2024年6月15日' ``` ```ts import 'moment/locale/fr' import 'moment/locale/de' import 'moment/locale/ja' const dt = moment('2024-06-15 12:34:56') // Localized month name dt.clone().locale('fr').format('MMMM') // 'juin' // Localized weekday dt.clone().locale('de').format('dddd') // 'Samstag' // Localized date format dt.clone().locale('ja').format('LL') // '2024年6月15日' ``` ```ts // Luxon uses the runtime's Intl API natively. // No locale files to import. // Per-instance locale const dt = DateTime.fromISO('2024-06-15T12:34:56') .setLocale('fr') // Localized month name dt.setLocale('fr').toFormat('MMMM') // 'juin' // Localized weekday dt.setLocale('de').toFormat('EEEE') // 'Samstag' // Localized date format dt.setLocale('ja').toLocaleString(DateTime.DATE_FULL) // '2024年6月15日' ``` ```ts import { format } from 'date-fns' import { fr, de, ja } from 'date-fns/locale' const d = new Date('2024-06-15T12:34:56') // Localized month name format(d, 'MMMM', { locale: fr }) // 'juin' // Localized weekday format(d, 'EEEE', { locale: de }) // 'Samstag' // Localized date format format(d, 'PPP', { locale: ja }) // '2024年6月15日' // Note: locale objects must be explicitly imported, // which enables effective tree-shaking. ``` ## Relative time Luxon supports relative time natively via `toRelative()` / `toRelativeCalendar()`. Moment.js supports it natively (`fromNow`/`from`/`to`). Day.js supports it via the `relativeTime` plugin. date-fns provides `formatDistanceToNow` and `formatDistance` as standalone functions. Qrono and `Temporal` have no built-in; `Intl.RelativeTimeFormat` can be used directly. ```ts // Not available as a built-in. // Use Intl.RelativeTimeFormat with valueOf() difference. const days = qrono.date('2024-01-10').valueOf() - qrono.date('2024-01-15').valueOf() const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }) rtf.format(days, 'day') // '5 days ago' // With locale const rtfJa = new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }) rtfJa.format(days, 'day') // '5日前' ``` ```ts // Not available as a built-in. // Use Intl.RelativeTimeFormat with Temporal differences. const base = Temporal.PlainDate.from('2024-01-15') const target = Temporal.PlainDate.from('2024-01-10') const days = target.until(base, { largestUnit: 'day' }).days const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }) rtf.format(-days, 'day') // '5 days ago' ``` ```ts import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import 'dayjs/locale/ja' dayjs.extend(relativeTime) const dt = dayjs('2024-01-10') // Relative to now dt.fromNow() // 'a year ago' dt.toNow() // 'in a year' // Relative to another date dt.from(dayjs('2024-01-15')) // '5 days ago' dt.to(dayjs('2024-01-15')) // 'in 5 days' // With locale dayjs.locale('ja') dt.fromNow() // '1年前' ``` ```ts const dt = moment('2024-01-10') // Relative to now dt.fromNow() // 'a year ago' dt.toNow() // 'in a year' // Relative to another date dt.from(moment('2024-01-15')) // '5 days ago' dt.to(moment('2024-01-15')) // 'in 5 days' // With locale dt.locale('ja').fromNow() // '1年前' ``` ```ts // Luxon uses Intl.RelativeTimeFormat natively. const dt = DateTime.fromISO('2024-01-10') // Relative to now dt.toRelative() // 'a year ago' dt.toRelativeCalendar() // 'last year' // Relative to another date dt.toRelative({ base: DateTime.fromISO('2024-01-15') }) // '5 days ago' // With locale dt.setLocale('ja').toRelative() // '1年前' ``` ```ts import { formatDistance, formatRelative, formatDistanceToNow, } from 'date-fns' import { ja } from 'date-fns/locale' const d = new Date('2024-01-10') // Relative to now formatDistanceToNow(d, { addSuffix: true }) // 'about 1 year ago' // Relative to another date formatDistance(d, new Date('2024-01-15'), { addSuffix: true }) // '5 days ago' // Calendar-style relative formatRelative(d, new Date('2024-01-15')) // e.g. 'last Monday at 12:00 AM' // With locale formatDistanceToNow(d, { addSuffix: true, locale: ja }) // '約1年前' ``` ## Duration Qrono intentionally has no Duration type. Differences between `Qrono` instances are plain milliseconds; differences between `QronoDate` instances are plain integers (days). `Temporal`, Moment.js, Day.js, and Luxon provide Duration types/APIs. ```ts const a = qrono('2024-01-15 12:00:00') const b = qrono('2024-03-20 18:30:00') // Difference as milliseconds const ms = b.valueOf() - a.valueOf() // 5_734_200_000 // Decompose manually if needed const totalMinutes = Math.floor(ms / 60000) const hours = Math.floor(totalMinutes / 60) const minutes = totalMinutes % 60 // QronoDate difference as integer days const da = qrono.date('2024-01-15') const db = qrono.date('2024-03-20') const days = db.valueOf() - da.valueOf() // 65 ``` ```ts const a = Temporal.ZonedDateTime.from('2024-01-15T12:00:00+00:00[UTC]') const b = Temporal.ZonedDateTime.from('2024-03-20T18:30:00+00:00[UTC]') // Difference as Temporal.Duration const dur = a.until(b, { largestUnit: 'month', smallestUnit: 'minute', }) // Duration fields dur.months dur.days dur.hours dur.minutes // ISO 8601 duration string dur.toString() // e.g. 'P2M5DT6H30M' ``` ```ts import dayjs from 'dayjs' import duration from 'dayjs/plugin/duration' dayjs.extend(duration) // Create a duration const dur = dayjs.duration({ months: 2, days: 5 }) dur.months() // 2 dur.days() // 5 dur.asMilliseconds() // total ms // Difference as duration const a = dayjs('2024-01-15') const b = dayjs('2024-03-20') const diff = dayjs.duration(b.diff(a)) diff.months() // 2 diff.days() // 5 diff.humanize() // 'in 2 months' ``` ```ts const a = moment('2024-01-15 12:00:00') const b = moment('2024-03-20 18:30:00') // Create a duration const dur = moment.duration({ months: 2, days: 5 }) dur.months() dur.days() dur.asMilliseconds() // Difference as duration const diff = moment.duration(b.diff(a)) diff.months() diff.days() diff.humanize() ``` ```ts import { Duration, DateTime } from 'luxon' // Create a duration const dur = Duration.fromObject({ months: 2, days: 5 }) dur.months // 2 dur.days // 5 dur.toMillis() // total ms dur.toISO() // 'P2M5D' // Difference as duration const a = DateTime.fromISO('2024-01-15') const b = DateTime.fromISO('2024-03-20') const diff = b.diff(a, ['months', 'days']) diff.months // 2 diff.days // 5 diff.toHuman() // '2 months, 5 days' ``` ```ts import { intervalToDuration, formatDuration, differenceInDays, differenceInHours, } from 'date-fns' const a = new Date('2024-01-15') const b = new Date('2024-03-20') // Structured duration object const dur = intervalToDuration({ start: a, end: b }) // { months: 2, days: 5 } dur.months // 2 dur.days // 5 // Human-readable formatDuration(dur) // '2 months 5 days' // Single-unit differences differenceInDays(b, a) // 65 differenceInHours(b, a) // 1566 ``` --- --- url: 'https://qronojs.dev/api.md' description: >- Complete Qrono API reference for factories, conversion, accessors, context, calculation, comparison, boundaries, date information, and DST APIs. --- # API Reference Complete API reference for Qrono. The library provides two classes: `Qrono`, which represents a point in time, and `QronoDate`, which represents a calendar date. * [Factory](#factory) * [qrono(...args)](#qrono) 14 overloads * [qrono.date(...args)](#qrono-date) 7 overloads * [Conversion](#conversion) * [.toString()](#tostring) * [.valueOf()](#valueof) * [.toArray()](#toarray) * [.toObject()](#toobject) * [.nativeDate()](#nativedate) * [.toDate()](#todate) * [.toDatetime()](#todatetime) * [Constants](#constants) * [qrono.monday](#day-constants) * [qrono.tuesday](#day-constants) * [qrono.wednesday](#day-constants) * [qrono.thursday](#day-constants) * [qrono.friday](#day-constants) * [qrono.saturday](#day-constants) * [qrono.sunday](#day-constants) * [Accessors](#accessors) * [.year()](#year) 2 overloads 2 overloads * [.month()](#month) 2 overloads 2 overloads * [.day()](#day) 2 overloads 2 overloads * [.hour()](#hour) 2 overloads * [.minute()](#minute) 2 overloads * [.second()](#second) 2 overloads * [.millisecond()](#millisecond) 2 overloads * [.offset()](#offset) * [Context](#context-methods) * [qrono.context()](#default-context) 2 overloads * [.context()](#context) 2 overloads * [Calculation](#calculation) * [.plus(duration)](#plus) 4 overloads 4 overloads * [.minus(duration)](#minus) 4 overloads 4 overloads * [.valid()](#valid) * [Comparison](#comparison) * [.isSame(other)](#issame) 3 overloads 3 overloads * [.isBefore(other)](#isbefore) 3 overloads 3 overloads * [.isAfter(other)](#isafter) 3 overloads 3 overloads * [.isSameOrBefore(other)](#issameorbefore) 3 overloads 3 overloads * [.isSameOrAfter(other)](#issameorafter) 3 overloads 3 overloads * [.isBetween(start, end)](#isbetween) 3 overloads 3 overloads * [Time Unit Boundary](#boundary) * [.startOfYear()](#startofyear) * [.startOfMonth()](#startofmonth) * [.startOfDay()](#startofday) * [.startOfHour()](#startofhour) * [.startOfMinute()](#startofminute) * [.startOfSecond()](#startofsecond) * [.endOfYear()](#endofyear) * [.endOfMonth()](#endofmonth) * [Date Information](#date-info) * [.dayOfWeek()](#dayofweek) * [.dayOfYear()](#dayofyear) * [.weekOfYear()](#weekofyear) * [.yearOfWeek()](#yearofweek) * [.isLeapYear()](#isleapyear) * [.daysInMonth()](#daysinmonth) * [.daysInYear()](#daysinyear) * [.weeksInYear()](#weeksinyear) * [Daylight Saving Time](#dst) * [.hasOffsetChangeInYear()](#hasOffsetChangeInYear) * [.isInDst()](#isindst) * [.hasOffsetChangeInDay()](#hasOffsetChangeInDay) * [.minutesInDay()](#minutesinday) ## Factory {#factory} All Factory methods accept an optional `context` object as the first argument to configure how the instance handles timezone and DST settings. ### qrono(...args) {#qrono} Creates a new `Qrono` datetime instance. ```javascript import { qrono } from 'qrono' // Current time qrono() // From Date object qrono(new Date()) // From timestamp (milliseconds) qrono(1704067200000) // From string // // Conforms to ISO 8601 format except for a few exceptions. // If no time zone is specified, parsing is performed // according to the current context (`localtime`). // // Format: // yyyy[[-|/]MM[[-|/]DD]][(T| )HH[:]mm[[:]ss[(.|:)SSS]]][Z|(+|-)hh:mm] // qrono('2024-01-15T10:30:00.000Z') // From components (year, month, day, hour, minute, second, millisecond) qrono(2024, 1, 15, 10, 30, 0, 0) // From array qrono([2024, 1, 15, 10, 30]) // From object qrono({ year: 2024, month: 1, day: 15 }) // With context options (context as first argument) qrono({ localtime: true }, '2024-01-15') ``` ### qrono.date(...args) {#qrono-date} Creates a new `QronoDate` instance (date only, no time component). ```javascript // Today qrono.date() // From string qrono.date('2024-01-15') // From components qrono.date(2024, 1, 15) // From array qrono.date([2024, 1, 15]) // From object qrono.date({ year: 2024, month: 1, day: 15 }) ``` ## Conversion {#conversion} ### toString() {#tostring} Get the ISO 8601 string representation. ```javascript time.toString() // "2024-06-15T14:30:00.000Z" qrono.date('2024-06-15').toString() // "2024-06-15" ``` ### valueOf() {#valueof} Get the numeric value of the instance.\ For `Qrono`, the unit is milliseconds since UNIX epoch.\ For `QronoDate`, the unit is days since UNIX epoch. ```javascript +time // 1718458200000 +qrono.date('1970-01-02') // 1 ``` ### toArray() {#toarray} Get an array of components. ```javascript time.toArray() // [2024, 6, 15, 14, 30, 0, 0] qrono.date('2024-06-15').toArray() // [2024, 6, 15] ``` ### toObject() {#toobject} Get an object with named properties. ```javascript time.toObject() // { year: 2024, month: 6, day: 15, hour: 14, minute: 30, second: 0, millisecond: 0 } qrono.date('2024-06-15').toObject() // { year: 2024, month: 6, day: 15 } ``` ### nativeDate() {#nativedate} Get a native JavaScript Date object. ```javascript time.nativeDate() // Date instance ``` ### toDate() {#todate} Get a `QronoDate` instance (date portion only). ```javascript time.toDate() // QronoDate instance ``` ### toDatetime() {#todatetime} Converts a `QronoDate` to a `Qrono` datetime at midnight. ```javascript qrono.date('2024-06-15').toDatetime().toString() // "2024-06-15T00:00:00.000Z" ``` ## Constants {#constants} ### Day of Week {#day-constants} These definitions follow ISO 8601, where Monday is 1 and Sunday is 7. ```javascript qrono.monday // 1 qrono.tuesday // 2 qrono.wednesday // 3 qrono.thursday // 4 qrono.friday // 5 qrono.saturday // 6 qrono.sunday // 7 ``` ## Accessors {#accessors} All component methods work as both getters (no argument) and setters (with argument). Setters return a new instance (immutable). ### year() {#year} ```javascript const time = qrono('2024-06-15') time.year() // 2024 (getter) time.year(2025) // New instance with year 2025 ``` ### month() {#month} ```javascript time.month() // 6 (getter, 1-12) time.month(12) // New instance with month 12 ``` ### day() {#day} ```javascript time.day() // 15 (getter) time.day(20) // New instance with day 20 ``` ### hour() {#hour} ```javascript time.hour() // 14 (getter, 0-23) time.hour(10) // New instance with hour 10 ``` ### minute() {#minute} ```javascript time.minute() // 30 (getter, 0-59) time.minute(45) // New instance with minute 45 ``` ### second() {#second} ```javascript time.second() // 45 (getter, 0-59) time.second(30) // New instance with second 30 ``` ### millisecond() {#millisecond} ```javascript time.millisecond() // 123 (getter, 0-999) time.millisecond(500) // New instance with millisecond 500 ``` ### offset() {#offset} Returns the time zone offset of the Qrono instance in minutes.\ A positive value indicates that the base time is ahead of UTC, and a negative value indicates that it is behind UTC. ::: tip This is the opposite sign convention of JavaScript's `Date.prototype.getTimezoneOffset`. ::: ```javascript qrono().context({ localtime: false }).offset() // 0 qrono().context({ localtime: true }).offset() // e.g., 540 (JST) ``` ## Context {#context-methods} ### qrono.context(options) {#default-context} Sets the default context for all new instances. ```javascript qrono.context({ localtime: true, disambiguation: 'earlier' }) ``` **Parameters:** * `localtime` - `boolean` - Use local time instead of UTC * `disambiguation` - `'compatible' | 'earlier' | 'later' | 'reject'` - How to resolve ambiguous local times at DST transitions (default: `'compatible'`) | Option | Gap (spring-forward) | Overlap (fall-back) | |----------------------------|-------------------------|-------------------------| | `'compatible'` *(default)* | Later (DST side) | Earlier (DST side) | | `'earlier'` | Earlier (standard side) | Earlier (DST side) | | `'later'` | Later (DST side) | Later (standard side) | | `'reject'` | Throws `RangeError` | Throws `RangeError` | ### context() {#context} Get or set context options. ```javascript // Get current context time.context() // { localtime: false, disambiguation: 'compatible' } // Set context (returns new instance) time.context({ localtime: true }) ``` ## Calculation {#calculation} When a `Qrono` instance is cast to a number, it represents the milliseconds since the UNIX epoch, just like a `Date` object. A `QronoDate` instance uses “days” as its unit. Therefore, expressions like the following work as expected. ```javascript qrono('2021-08-31 12:34') < qrono('2021-09-30 12:34') const today = qrono.date('2021-08-31') const tomorrow = qrono.date(today + 1) tomorrow - today === 1 ``` ### plus(duration) {#plus} Add time to the date.\ In operations using Object, `year`, `month`, and `day` are calculated *literally*.\ For example, adding one month at the end of a month results in the end of the following month.\ `hour`, `minute`, `second`, and `millisecond` are treated as a duration in calculations. ```javascript time.plus({ month: 2, day: 15 }) time.plus({ hour: 5, minute: 30, second: 45, millisecond: 500 }) time.plus(3600 * 1000) // add one hour via milliseconds time.plus([0, 1, 1, 4]) // add 1 month, 1 day, 4 hours time.plus({ minute: 15, second: 30 }) // add minutes + seconds ``` `QronoDate` variants also accept: ```javascript qrono.date('2024-01-01').plus(1) // +1 day qrono.date('2024-01-01').plus([0, 1, 1]) // +1 month, +1 day qrono.date('2024-01-01').plus({ year: 1 }) // same object form ``` ### minus(duration) {#minus} Subtract time from the date.\ In operations using Object, `year`, `month`, and `day` are calculated *literally*.\ For example, subtracting `{ month: 1 }` from July 31 results in June 28.\ `hour`, `minute`, `second`, and `millisecond` are treated as a duration in calculations. ```javascript time.minus({ year: 1 }) time.minus({ month: 2, day: 15 }) time.minus({ hour: 5, minute: 30 }) time.minus(15 * 60 * 1000) // subtract 15 minutes via milliseconds time.minus([0, 0, 0, 6]) // subtract 6 hours time.minus({ day: 1, minute: 45 }) // subtract days + minutes ``` `QronoDate` variants also accept: ```javascript qrono.date('2024-01-05').minus(2) // -2 days qrono.date('2024-01-05').minus([0, 0, 5]) // -5 days qrono.date('2024-01-05').minus({ month: 1 }) // subtract month ``` ### valid() {#valid} Check if the instance represents a valid date. ```javascript qrono('2024-01-15').valid() // true qrono(new Date('invalid')).valid() // false ``` ## Comparison {#comparison} ### isSame(other) {#issame} Check if two dates are equal. ```javascript time.isSame(qrono('2024-01-15')) // true or false time.isSame(new Date()) time.isSame(1704067200000) ``` ### isBefore(other) {#isbefore} Check if this date is before another. ```javascript time.isBefore(qrono('2024-12-31')) // true or false ``` ### isAfter(other) {#isafter} Check if this date is after another. ```javascript time.isAfter(qrono('2024-01-01')) // true or false ``` ### isSameOrBefore(other) {#issameorbefore} Check if this date is the same or before another. ```javascript time.isSameOrBefore(qrono('2024-12-31')) // true or false ``` ### isSameOrAfter(other) {#issameorafter} Check if this date is the same or after another. ```javascript time.isSameOrAfter(qrono('2024-01-01')) // true or false ``` ### isBetween(start, end) {#isbetween} Check if this date is between two dates (inclusive). ```javascript time.isBetween(qrono('2024-01-01'), qrono('2024-12-31')) // true or false ``` ## Time Unit Boundary {#boundary} ### startOfYear() {#startofyear} Get the start of the year. ```javascript qrono('2024-06-15 14:30:00').startOfYear() // 2024-01-01T00:00:00.000Z ``` ### startOfMonth() {#startofmonth} Get the start of the month. ```javascript qrono('2024-06-15 14:30:00').startOfMonth() // 2024-06-01T00:00:00.000Z ``` ### startOfDay() {#startofday} Get the start of the day. ```javascript qrono('2024-06-15 14:30:00').startOfDay() // 2024-06-15T00:00:00.000Z ``` ### startOfHour() {#startofhour} Get the start of the hour. ```javascript qrono('2024-06-15 14:30:45').startOfHour() // 2024-06-15T14:00:00.000Z ``` ### startOfMinute() {#startofminute} Get the start of the minute. ```javascript qrono('2024-06-15 14:30:45').startOfMinute() // 2024-06-15T14:30:00.000Z ``` ### startOfSecond() {#startofsecond} Get the start of the second. ```javascript qrono('2024-06-15 14:30:45.123').startOfSecond() // 2024-06-15T14:30:45.000Z ``` ### endOfYear() {#endofyear} Returns the last day of the year. ```javascript qrono.date('2024-06-15').endOfYear().toString() // "2024-12-31" ``` ### endOfMonth() {#endofmonth} Returns the last day of the month. ```javascript qrono.date('2024-06-15').endOfMonth().toString() // "2024-06-30" ``` ## Date Information {#date-info} ### dayOfWeek() {#dayofweek} Get the day of the week (Monday = 1, Sunday = 7). ```javascript qrono('2024-06-15').dayOfWeek() === qrono.saturday // 6 ``` ### dayOfYear() {#dayofyear} Get the day of the year (1-366). ```javascript qrono('2024-06-15').dayOfYear() // 167 ``` ### weekOfYear() {#weekofyear} Get the ISO week number. ```javascript qrono('2024-06-15').weekOfYear() // 24 ``` ### yearOfWeek() {#yearofweek} Get the year of the ISO week (may differ at year boundaries). ```javascript qrono('2025-12-29').yearOfWeek() // 2026 ``` ### isLeapYear() {#isleapyear} Check if the year is a leap year. ```javascript qrono('2024-01-01').isLeapYear() // true ``` ### daysInMonth() {#daysinmonth} Get the number of days in the current month. ```javascript qrono('2024-02-15').daysInMonth() // 29 ``` ### daysInYear() {#daysinyear} Get the number of days in the current year. ```javascript qrono('2024-01-01').daysInYear() // 366 ``` ### weeksInYear() {#weeksinyear} Get the number of ISO weeks in the current year (52 or 53). ```javascript qrono('2024-01-01').weeksInYear() // 52 ``` ## Daylight Saving Time {#dst} ### hasOffsetChangeInYear() {#hasOffsetChangeInYear} Check if the year has daylight saving time transitions. ```javascript qrono.context({ localtime: true }) qrono(1950, 1, 1).hasOffsetChangeInYear() // true qrono(2024, 1, 1).hasOffsetChangeInYear() // false (in Japan) ``` ### isInDst() {#isindst} Check if the current time is in daylight saving time. ```javascript qrono.context({ localtime: true }) qrono('1950-09-10 00:59:59').isInDst() // true ``` ### hasOffsetChangeInDay() {#hasOffsetChangeInDay} Check if the current day has a DST transition. ```javascript qrono.context({ localtime: true }) qrono('1950-05-07').hasOffsetChangeInDay() // true ``` ### minutesInDay() {#minutesinday} Get the number of minutes in the current day (accounts for DST). ```javascript qrono.context({ localtime: true }) qrono('1950-05-06').minutesInDay() // 1440 qrono('1950-05-07').minutesInDay() // 1380 (DST spring forward) qrono('1950-09-10').minutesInDay() // 1500 (DST fall back) ```