0.1.6 • Published 3 months ago

@pubdate/dayjs-plugin-recurring v0.1.6

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

dayjs-plugin-recurring

A dayjs plugin to work with recurring dates.

Getting Started

NPM

npm i dayjs @pubdate/dayjs-plugin-recurring
import dayjs from 'dayjs'
import recurring from '@pubdate/dayjs-plugin-recurring'

dayjs.extend(recurring)

CDN

<script src="https://unpkg.com/dayjs"></script>
<script src="https://unpkg.com/@pubdate/dayjs-plugin-recurring"></script>

<script>
  dayjs.extend(dayjs_plugin_recurring)
</script>

Options

order

In chronological order (default):

  • The first occurrence is always the oldest.
  • The sequence continues from the oldest to the newest.
  • Arrays of occurrences are always ordered from the oldest to the newest.
dayjs.extend(recurring, { order: 'chronological' })
dayjs('R3/2020-01-01/P1Y').all() // [2020-01-01, 2021-01-01, 2022-01-01, 2023-01-01]
dayjs('R3/P1Y/2023-01-01').all() // [2020-01-01, 2021-01-01, 2022-01-01, 2023-01-01]

In relative order:

  • The first occurrence is start if provided, or end if provided, or context (the current dayjs instance).
  • If start is provided or end is not, the sequence continues from the oldest to the newest. And from the newest to the oldest otherwise.
  • Arrays of occurrences returned by all()/first(n) are ordered from the first (cf. first point) to the last.
  • Arrays of occurrences returned by last(n) are ordered from the last to the first (cf. first point).
  • Arrays of occurrences returned by prev(n)/next(n) are ordered from the closest of the current occurrence to the furthest.
dayjs.extend(recurring, { order: 'relative' })
dayjs('R3/2020-01-01/P1Y').all() // [2020-01-01, 2021-01-01, 2022-01-01, 2023-01-01]
dayjs('R3/P1Y/2023-01-01').all() // [2023-01-01, 2022-01-01, 2021-01-01, 2020-01-01]

Comparison:

all/first         1 - 2 - 3 - 4 - 5
chronological     ---------------->   [1, 2, 3, 4, 5]
relative (start)  ---------------->   [1, 2, 3, 4, 5]
relative (end)    <----------------   [5, 4, 3, 2, 1]

last              1 - 2 - 3 - 4 - 5
chronological     ---------------->   [1, 2, 3, 4, 5]
relative (start)  <----------------   [5, 4, 3, 2, 1]
relative (end)    ---------------->   [1, 2, 3, 4, 5]

prev              1 - 2 - 3 - 4 - 5
chronological     -----> now          [1, 2]
relative (start)  <----- now          [2, 1]
relative (end)           now ----->   [4, 5]

next              1 - 2 - 3 - 4 - 5
chronological            now ----->   [4, 5]
relative (start)         now ----->   [4, 5]
relative (end)    <----- now          [2, 1]

API

!NOTE Unless explicitly stated otherwise, all examples are in chronological order.

Create a recurring dayjs instance

To create a recurring dayjs instance, simply pass an ISO 8601 recurring time interval string to the dayjs factory. It will return the occurrence that matches start if provided, or end if provided, or now.

dayjs('R10/2020-01-01/P1Y') // 2020-01-01
dayjs('R10/2020-01-01/P1Y').last() // 2030-01-01

dayjs('R10/P1Y/2030-01-01') // 2030-01-01
dayjs('R10/P1Y/2030-01-01').first() // 2020-01-01

dayjs('R10/P1Y') // dayjs()
dayjs('R10/P1Y').last() // dayjs().add(10, 'years')

To generate a recurring instance from a regular instance, call recurring() with a string or an object. It will keep the date as current occurrence. And use it as start if the argument has no start and no end.

dayjs('2025-01-01').recurring('R10/2020-01-01/P1Y') //  2025-01-01
dayjs('2025-01-01').recurring('R10/2020-01-01/P1Y').last() // 2030-01-01

dayjs('2025-01-01').recurring({ times: 10, start: '2020-01-01', duration: 'P1Y' }) //  2025-01-01
dayjs('2025-01-01').recurring({ times: 10, start: '2020-01-01', duration: 'P1Y' }).last() // 2030-01-01

dayjs('2025-01-01').recurring('R10/P1Y') // 2025-01-01
dayjs('2025-01-01').recurring('R10/P1Y').last() // 2035-01-01

Pass an object with start and end but no times to automatically compute times.

dayjs('2025-01-01').recurring({ start: '2020-01-01', end: '2030-01-01', duration: 'P1Y' }) // times: 10
dayjs('2025-01-01').recurring({ start: '2020-01-01', duration: 'P1Y' }) // times: undefined

recurring()

Returns the recurring config.

dayjs('R10/2020-01-01/P1Y').recurring().toString({ dateFormat: 'YYYY-MM-DD' }) // 'R10/2020-01-01/P1Y'

isOccurrence()

Checks whether the current date is an occurrence or not.

dayjs('2023-01-01').recurring('R/2020-01-01/P1Y').isOccurrence() // true
dayjs('2023-01-10').recurring('R/2020-01-01/P1Y').isOccurrence() // false

isOccurrence(date, unit = 'milliseconds')

Checks whether date is an occurrence or not. If you want to limit the granularity to a unit other than milliseconds, pass it as the second parameter.

dayjs('R/2020-01-01/P1Y').isOccurrence('2023-01-01') // true
dayjs('R/2020-01-01/P1Y').isOccurrence('2023-01-10') // false
dayjs('R/2020-01-01/P1Y').isOccurrence('2023-01-10', 'year') // true

all()

!TIP Use allBetween to avoid null errors.

Returns all occurrences. Or null when there is no limit.

dayjs('R3/2020-01-01/P1Y').all() // [2020-01-01, 2021-01-01, 2022-01-01, 2023-01-01]
dayjs('R/2020-01-01/P1Y').all() // null

allBetween(a, b, unit = 'milliseconds', inclusion = '()')

Returns all occurrences between a and b. If you want to limit the granularity to a unit other than milliseconds, pass it as the third parameter. The fourth parameter is about inclusivity. A [ indicates inclusion of a value. A ( indicates exclusion.

dayjs('R/2020-01-01/P1Y').allBetween('2022-01-01', '2025-01-01') // [2023-01-01, 2024-01-01]
dayjs('R/2020-01-01/P1Y').allBetween('2022-01-01', '2025-01-01', undefined, '(]') // [2023-01-01, 2024-01-01, 2025-01-01]
dayjs('R/2020-01-10/P1Y').allBetween('2022-01-01', '2025-01-01', 'month', '(]') // [2023-01-10, 2024-01-10, 2025-01-10]

first()

Returns the first occurrence. Or null, in chronological order, when there is no start and no limit.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').first() // 2020-01-01
dayjs('2025-01-01').recurring('R/P1Y/2030-01-01').first() // null
dayjs('2025-01-01').recurring('R10/P1Y/2030-01-01').first() // 2020-01-01

first(n, query)

Returns the first n occurrences that match query. Or null, in chronological order, when there is no start and no limit.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').first(3) // [2020-01-01, 2021-01-01, 2022-01-01]
dayjs('2025-01-01').recurring('R/P1Y/2030-01-01').first(3) // null
dayjs('2025-01-01').recurring('R10/P1Y/2030-01-01').first(3) // [2020-01-01, 2021-01-01, 2022-01-01]

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').first(3, { isBefore: '2022-01-01' }) // [2020-01-01, 2021-01-01]

last()

Returns the first occurrence. Or null, in chronological order, when there is no start and no limit. Or null, in relative order, when there is no limit.

dayjs('2025-01-01').recurring('R/P1Y/2030-01-01').last() // 2030-01-01
dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').last() // null
dayjs('2025-01-01').recurring('R10/2020-01-01/P1Y').last() // 2030-01-01

last(n, query)

Returns the last n occurrences that match query. Or null, in chronological order, when there is no end and no limit. Or null, in relative order, when there is no limit.

dayjs('2025-01-01').recurring('R/P1Y/2030-01-01').last(3) // [2028-01-01, 2029-01-01, 2030-01-01]
dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').last(3) // null
dayjs('2025-01-01').recurring('R10/2020-01-01/P1Y').last(3) // [2028-01-01, 2029-01-01, 2030-01-01]

dayjs('2025-01-01').recurring('R/P1Y/2030-01-01').last(3, { isAfter: '2028-01-01' }) // [2029-01-01, 2030-01-01]

prev()

Returns the previous occurrence. Or null when the current occurrence is the first one.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').prev() // 2024-01-01
dayjs('2020-01-01').recurring('R/2020-01-01/P1Y').prev() // null

prev(n, query)

Returns the n previous occurrences that match query.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').prev(2) // [2023-01-01, 2024-01-01]
dayjs('2021-01-01').recurring('R/2020-01-01/P1Y').prev(2) // [2020-01-01]

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').prev(Infinity, { isAfter: '2021-01-01' }) // [2022-01-01, 2023-01-01, 2024-01-01]

next()

Returns the next occurrence. Or null when the current occurrence is the last one.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next() // 2026-01-01
dayjs('2030-01-01').recurring('R10/2020-01-01/P1Y').next() // null

next(n, query)

Returns the n next occurrences that match query.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next(2) // [2026-01-01, 2027-01-01]
dayjs('2029-01-01').recurring('R10/2020-01-01/P1Y').next(2) // [2030-01-01-01]
dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next(Infinity, { isBefore: '2029-01-01' }) // [2026-01-01, 2027-01-01, 2028-01-01]

Query

Some methods accept a query. These methods will stop the moment a date does not match the query. The query can be an object of which the keys are the name of dayjs comparison methods and the values are either a date or the arguments of said methods. It can also be a function that takes a date and returns a boolean.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next(Infinity, { isBefore: '2029-01-01' }) // [2026-01-01, 2027-01-01, 2028-01-01]
dayjs('2025-01-10').recurring('R/2020-01-10/P1Y').next(Infinity, { isBefore: ['2029-01-01', 'year'] }) // [2026-01-10, 2027-01-10, 2028-01-10]
dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next(Infinity, date => date.isBefore('2029-01-01')) // [2026-01-01, 2027-01-01, 2028-01-01]

The example below returns an empty array because, even though 2027-01-01 and 2028-01-01 match the query, 2026-01-01 does not.

dayjs('2025-01-01').recurring('R/2020-01-01/P1Y').next(Infinity, { isAfter: '2026-01-01', isBefore: '2029-01-01' }) // []
0.1.6

3 months ago

0.1.5

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago