---
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-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)
```