Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/meduzen/datetime-attribute
Get a `datetime` attribute for the HTML `<time>` element (and others).
https://github.com/meduzen/datetime-attribute
date datetime duration html-attributes html-time iso-8601 javascript temporal time timezone typescript
Last synced: about 1 month ago
JSON representation
Get a `datetime` attribute for the HTML `<time>` element (and others).
- Host: GitHub
- URL: https://github.com/meduzen/datetime-attribute
- Owner: meduzen
- License: wtfpl
- Created: 2021-03-13T22:27:51.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2024-11-01T11:30:32.000Z (2 months ago)
- Last Synced: 2024-11-15T19:07:23.120Z (about 2 months ago)
- Topics: date, datetime, duration, html-attributes, html-time, iso-8601, javascript, temporal, time, timezone, typescript
- Language: JavaScript
- Homepage:
- Size: 1.32 MB
- Stars: 18
- Watchers: 4
- Forks: 1
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# datetime-attribute
Get a [`datetime` attribute](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTimeElement/datetime) for HTML `
It covers the [whole WHATWG specification](https://html.spec.whatwg.org/multipage/text-level-semantics.html#attr-time-datetime) in 4 functions:
- [**`datetime()`**](#expressing-moments-with-datetime) for a specific moment ([641 B compressed](https://bundlejs.com/?q=datetime-attribute&treeshake=[{datetime}]&config={"compression"%3A"brotli"}&bundle));
- [**`datetimeTz()`**](#adding-a-timezone-offset-to-a-moment-with-datetimetz) for a specific moment in a given timezone ([903 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{datetimeTz}]&config={"compression"%3A"brotli"}&bundle));
- [**`duration()`**](#expressing-durations-with-duration) for a duration ([284 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{duration}]&config={"compression"%3A"brotli"}&bundle));
- [**`tzOffset()`**](#expressing-timezone-offsets-with-tzoffset) for a timezone offset ([332 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{tzOffset}]&config={"compression"%3A"brotli"}&bundle)).Additionally, a [`DateTime` class](#the-datetime-class) ([710 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{DateTime}]&config={"compression"%3A"brotli"}&bundle)) and some [other functions](#other-functions) are provided.
[![Node.js CI](https://github.com/meduzen/datetime-attribute/actions/workflows/node.js.yml/badge.svg)](https://github.com/meduzen/datetime-attribute/actions/workflows/node.js.yml)
The package is lightweight ([~ 1.37 KB compressed](https://bundlejs.com/?q=datetime-attribute&config={"compression"%3A"brotli"}&bundle) for `import *`), tree-shakeable, typed and tested.
## Table of contents
- [Summary usage](#summary-usage)
- [Installation](#installation)
- Usage
- [**`datetime()`**](#expressing-moments-with-datetime) to express a **moment** at different [levels of precision](#available-precision-keywords):
- [date](#date)
- [time and UTC time](#time-and-utc-time)
- [datetime and UTC datetime](#datetime-and-utc-datetime)
- alternative to the UTC syntax with [`utc()`](#the-utc-shortcut)
- [datetime separator](#datetime-separator)
- [**`tzOffset()`**](#expressing-timezone-offsets-with-tzoffset) to express a **timezone offset**
- [hours-minutes separator](#hours-minutes-separator)
- [real-world timezone offset](#real-world-timezone-offset)
- [timezone configuration](#timezone-configuration)
- [**`datetimeTz()`**](#adding-a-timezone-offset-to-a-moment-with-datetimetz) to express a **moment with a specific timezone** offset
- [**`duration()`**](#expressing-durations-with-duration) to expressing a **duration**
- [units overflow](#units-overflow)
- [The **`DateTime`** class](#the-datetime-class)
- [**`.getWeek()`**](#datetimeprototypegetweek)
- [**`.setWeek()`**](#datetimeprototypesetweek)
- [**`.to()`**](#datetimeprototypeto)
- Other functions
- [**`daysBetween()`**](#daysbetween) to get the number of **days between two dates**
- [**`weekNumber()`**](#weeknumber) to get the **week number** (in the year) of a date
- Various:
- [Changelog](#changelog)
- [Browser and tooling support](#browser-and-tooling-support)
- [Not only in `## Summary usage
```js
import * from 'datetime-attribute'const now = new Date()
datetime(now) // '2021-03-14'
datetime(now, 'time') // '10:29'
datetimeTz(now, 'datetime', -7) // '2021-03-14T10:29-07:00'
utc(now, 'time') // '09:29Z'tzOffset(-9, -30) // '-09:30' (Marquesas Islands)
duration({ d: 4, h: 3, m: 17 }) // 'P4DT3H17M'const importantMeeting = new DateTime(2021, 12, 17, 19, 00) // 17/11
const meetingWeek = importantMeeting.getWeek() // 46importantMeeting.setWeek(meetingWeek + 1) // meeting now on 24/11
importantMeeting.to('week') // 2021W47
importantMeeting.to('datetime') // 2021-11-24T19:00daysBetween(now, importantMeeting) // 248
```## Installation
Install the package:
`npm install datetime-attribute`
Then, import the functions you need in your script:
```js
// if you only need `datetime` and `duration`
import { datetime, duration } from 'datetime-attribute'// if you need everything
import * from 'datetime-attribute'
```Not using a package manager? Download [the package files](https://github.com/meduzen/datetime-attribute/releases) in your project and take the files in `/src`.
## Expressing moments with `datetime()`
`datetime()` accepts two optional arguments: a [Date object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date), and a [_precision_ keywords](#available-precision-keywords).
```js
import { datetime } from 'datetime-attribute'const now = new Date() // We’re 14 March 2021 and it’s 10:29 in Brussels.
datetime(now) // '2021-03-14'
datetime(now, 'datetime') // '2021-03-14T10:29'
```Without argument, it defaults to _today_:
```js
datetime() // today formatted in YYYY-mm-dd
datetime((new Date()), 'day') // same
```### Available precision keywords
By default, `datetime()` precision is `day`, resulting in a `YYYY-mm-dd`
output. Many other values are available.#### Date
| precision | example output | description
|--|--|--|
| `day` | `2021-03-14` | the default, fitting a calendar |
| `year` | `2021` | only the year |
| `yearless` | `03-14` | a day in a month |
| `month` | `2021-03` | a month in a year |
| `week` | `2021W10` | the week number ([ISO-8601 spec](https://en.wikipedia.org/wiki/ISO_week_date)) and its year |#### Time and UTC time
Time:
| precision | example output | description
|--|--|--|
| `time` | `10:29` | hours and minutes, like most clocks
| `second` | `10:29:00` | time with precision up to seconds
| `ms` | `10:29:00.000` | time with precision up to millisecondsTo get UTC time, add ` utc` to the time keyword:
| precision | example output | description
|--|--|--|
| `time utc` | `09:29Z` | `time`, shifted to UTC time
| `second utc` | `09:29:00Z` | `second`, shifted to UTC time
| `ms utc` | `09:29:00.000Z` | `ms`, shifted to UTC time#### Datetime and UTC datetime
Datetime:
| precision | example output | description
|--|--|--|
`datetime` | `2021-03-14T10:29` | a local datetime (= date + time separated by `T`)
`datetime second` | `2021-03-14T10:29:00` | time with precision up to seconds
`datetime ms` | `2021-03-14T10:29:00.000` | time with precision up to millisecondsTo get UTC datetime, add ` utc` to the datetime keyword:
| precision | example output | description
|--|--|--|
`datetime utc` | `2021-03-14T09:29Z` | `datetime`, shifted to UTC time
`datetime second utc` | `2021-03-14T09:29:00Z` | `datetime second`, shifted to UTC time
`datetime ms utc` | `2021-03-14T09:29:00.000Z` | `datetime ms`, shifted to UTC time#### The `utc` shortcut
💡 Instead of adding ` utc` to a [time](#time-and-utc-time) or [datetime](#datetime-and-utc-datetime) keyword, you can use `utc(date, precision)`, which has `datetime` as default precision:
```js
import { datetime, utc } from 'datetime-attribute'const now = new Date() // We’re 14 March 2021 and it’s 10:29 in Brussels.
// These are the same:
utc(now, 'time') // `09:29Z`
datetime(now, 'time utc') // `09:29Z`// These are the same:
utc(now) // `2021-03-14T09:29Z`
utc(now, 'datetime') // `2021-03-14T09:29Z`
datetime(now, 'datetime utc') // `2021-03-14T09:29Z`
```### Datetime separator
[Per spec](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#local-dates-and-times), the separator between date and time can be `T` (default) or ` ` (1 space).
To change the separator globally, use `setTimeSeparator`:
```js
import { setTimeSeparator } from 'datetime-attribute'setTimeSeparator(' ')
// All next datetime functions will follow the new setting.
datetime(now) // `2021-03-14 10:29`// Switch back to the default.
setTimeSeparator('T') // or `setTimeSeparator()`
```Setting the separator to a space can be useful to deal with [MySQL](https://dev.mysql.com/doc/refman/8.0/en/datetime.html) or [MariaDB `DATETIME`](https://mariadb.com/kb/en/datetime/) column.
## Expressing timezone offsets with `tzOffset()`
Timezone offsets are a comparison against [UTC time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). For example, `+01:00` means “one hour ahead of UTC time” and `-05:00` means “five hours behind UTC time”.
`tzOffset()` accepts three optional arguments for hours, minutes, and [compliance to real-world boundaries](#real-world-timezone-offset). Without argument, the local timezone offset is returned (and may differ based on daylight saving time).
```js
import { tzOffset } from 'datetime-attribute'tzOffset(3) // '+03:00' (Moscow)
tzOffset(-9, -30) // '-09:30' (Marquesas Islands)
tzOffset(-9.5) // '-09:30' (same with 1 parameter)tzOffset(5, -30) // '+04:30' (Afghanistan)
tzOffset(5, 30) // '+05:30' (India)tzOffset(0) // 'Z' (Ghana; 'Z' is equal to '+00:00')
// in Belgium
tzOffset() // '+01:00'
tzOffset() // '+02:00' (under daylight saving time)
```### Hours-minutes separator
[Per spec](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#time-zones), the separator between hours and minutes is optional. The allowed values are:
- (default) a colon caracter (`:`);
- an empty string.To change the separator globally, use `setTzSeparator`:
```js
import { setTzSeparator } from 'datetime-attribute'setTzSeparator('')
// All next timezone-related functions will follow the new setting.
tzOffset(3) // '+0300'
tzOffset(-9, -30) // '-0930'// Switch back to the default.
setTzSeparator(':')
```### Real-world timezone offset
The timezone offset will always be adjusted to fit in the spec range (from `-23:59` to `+23:59`). This means `tzOffset(44)` will output `+20:00` instead of `+44:00`.
However, timezone offsets of countries in the world are all between `-12:00` and `+14:00`. If you want `tzOffset(44)` to output `-04:00` (instead of `+20:00`) so that it matches real-world boundaries, give it a third parameter (default: `false`):
```js
tzOffset(44) // '+20:00'
tzOffset(44, 0, true) // '-04:00'
```To change the behaviour globally, use `setTzInRealWorldRange`:
```js
import { setTzInRealWorldRange } from 'datetime-attribute'setTzInRealWorldRange(true)
// All next timezone-related functions will follow the new setting.
tzOffset(20) // '-04:00'
tzOffset(-14, -30) // '+09:30'// Switch back to the default.
setTzInRealWorldRange(false) // or setTzInRealWorldRange()
```Curious about timezones? Have a look at [the timezone map](https://fr.m.wikipedia.org/wiki/Fichier:World_Time_Zones_Map.png) and the [daylight saving time chaos](https://en.wikipedia.org/wiki/Daylight_saving_time_by_country).
### Timezone configuration
If you need both timezone configuration functions described in the previous section (`setTzSeparator` for the [hours-minutes separator](#hours-minutes-separator) and `setTzInRealWorldRange` for [timezones boundaries](#real-world-timezone-offset)), you can directly use `setTzConfig()`:
```js
import { setTzConfig } from 'datetime-attribute'setTzConfig({
inRealWorldRange: false, // see `setTzInRealWorldRange`
separator: ':', // see `setTzSeparator`
})// Switch back to the default.
setTzConfig()
```## Adding a timezone offset to a moment with `datetimeTz()`
As `datetime()` doesn’t care about timezones, you can use `datetimeTz()` when you need to be explicit about the timezone of a moment.
💡 `datetimeTz()` is basically a concatenation of [`datetime(date, precision)`](#expressing-moments-with-datetime) and [`tzOffset(hours, minutes)`](#expressing-timezone-offsets-with-tzoffset), so be sure to read about them.
It accepts the same 5 parameters, all optional:
```js
datetimeTz(date, precision, offsetHours, offsetMinutes, inRealWorldRange)
```1. A date object (default: `new Date()`)
2. A [precision keywords](#available-precision-keywords) among:
- `time`
- `second`
- `ms`
- `datetime` (default)
- `datetime second`
- `datetime ms`
3. Hours offset like in [`tzOffset()`](#expressing-timezone-offsets-with-tzoffset)
4. Minutes offset like in [`tzOffset()`](#expressing-timezone-offsets-with-tzoffset)
5. Boundaries of the timezone offset like in [`tzOffset()`](#real-world-timezone-offset)When hours and minutes are not specified, the local timezone offset is used.
```js
import { datetime, datetimeTz } from 'datetime-attribute'const now = new Date() // We’re 2 April 2021 and it’s 23:51 in Brussels.
datetime(now) // '2021-04-02'
datetimeTz(now) // '2021-04-02T23:51+02:00'datetime(now, 'time') // '23:51'
datetime(now, 'time utc') // '21:51Z' (same as previous, converted to UTC)
datetimeTz(now, 'time', 0) // '23:51Z' (datetimeTz does not convert)
datetimeTz(now, 'time') // '23:51+02:00' (fall back on local timezone)
datetimeTz(now, 'time', 9) // '23:51+09:00'
datetimeTz(now, 'time', -3, 30) // '23:51-03:30'
datetimeTz(now, 'time', -14, 0, true) // '23:51+10:00'
````datetimeTz()` **does not convert** your moment to another timezone: it **only adds the wanted timezone** to the moment. Its purpose is to generate a valid `datetime` attribute saying “here’s a moment, it has this [hours, minutes and] timezone offset”.
Let’s take this sentence and its HTML:
> When I’m in Brussels, I wake up at 8 o’clock every day.
```html
When I’m in Brussels, I wake up every day.
```Here’s how you can get the `datetime` attribute fitting this sentence:
```js
// const awakeningAt = new Date(…) // a Date object with 08:00 as timedatetimeTz(awakeningAt, 'time', 2) // '08:00+02:00'
```## Expressing durations with `duration()`
`duration()` requires an object with entries for different levels of durations, from seconds to weeks. It also accepts a second parameter to control the [conversion of units overflow](#units-overflow) (default: `true`).
```js
import { duration } from 'datetime-attribute'const countdownBeforeBigParty = {
w: 3, // 3 weeks
d: 5, // 5 days
h: 10, // 10 hours
m: 43, // 43 minutes
s: 2.61 // 2.610 seconds
}duration(countdownBeforeBigParty) // 'P3W5DT10H43M2'
```All object keys are optional:
```js
duration({ h: 17 }) // 'PT17H'
```### Units overflow
Values exceeding a unit are converted to upper units:
```js
duration({ h: 31, m: 63, s: 175 }) // 'P1DT8H5M55S'
```If you don’t need this behaviour, pass `false` as second parameter (default value: `true`).
```js
duration({ m: 175 }) // 'PT2H55M'
duration({ m: 175 }, false) // 'PT175M'
```## The `DateTime` class
The **`DateTime` class extends the native `Date` object** with methods allowing you to interact with the week number or to output a `datetime` string.
### Constructor
Its constructor remains the same as [the `Date` one](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date).
```js
import { DateTime } from 'datetime-attribute'// One of the many ways to instantiate a `Date`, and this `DateTime`.
const summer = new DateTime(2021, 5, 21) // June 21, 2021
```### `DateTime.prototype.getWeek()`
Returns the week of the year, giving the same output as [`weekNumber()`](#weeknumber).
```js
const summer = new DateTime(2021, 5, 21) // June 21, 2021summer.getWeek() // 25
```### `DateTime.prototype.setWeek()`
Shifts the date to the provided week, while preserving its initial day. In other words, if the initial date is a Friday, then the shifted date remains a Friday.
```js
const summer = new DateTime(2021, 5, 21) // June 21, 2021summer.setWeek(26) // shifts the date to June 28, 2021
summer.getWeek() // now it’s 26
```### `DateTime.prototype.to()`
Returns a `datetime` attribute. `DateTime.to()` accepts the same [`precision` keywords](#available-precision-keywords) as [`datetime()`](#expressing-moments-with-datetime).
```js
const summer = new DateTime(2021, 5, 21) // June 21, 2021summer.to('month') // 2021-06
summer.to('yearless') // 06-21
summer.to('datetime second') // 2021-06-21T00:00:00
```## Other functions
Under the hood, the core features of `datetime-attribute` uses additional functions that you can also `import` individually.
### `daysBetween()`
Calculate the difference between 2 dates in days, **discarding the time of day**. It subtracts the first `Date` object from the second one.
```js
import { daysBetween } from 'datetime-attribute'const january1st2021 = new Date(2021, 0, 1, 10, 10, 12)
const january11th = new Date(2021, 0, 11, 10, 10, 12)
const january19th = new Date(2021, 0, 19, 10, 10, 12)daysBetween(january1st2021, january11th) // 10
daysBetween(january19th, january11th) // -8
```([110 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{daysBetween}]&config={"compression"%3A"brotli"}&bundle))
### `weekNumber()`
Get the week number as [defined by the WHATWG](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#weeks), following the ISO-8601 specs:
- [a week starts on Monday](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#concept-week);
- the first week of the year includes a Thursday;
- [week numbers go from 1 to 53](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#week-number-of-the-last-day).It accepts a `Date` object.
```js
import { weekNumber } from 'datetime-attribute'const january1st2021 = new Date(2021, 0, 1, 10, 10, 12)
const january11th = new Date(2021, 0, 11, 10, 10, 12)
const togoIndependanceDay = new Date(1960, 3, 27)weekNumber(togoIndependanceDay) // 17
weekNumber(january1st2021) // 53: it’s a Friday!
weekNumber(january11th) // 2
```([183 B](https://bundlejs.com/?q=datetime-attribute&treeshake=[{weekNumber}]&config={"compression"%3A"brotli"}&bundle))
## Changelog
See [CHANGELOG.md](https://github.com/meduzen/datetime-attribute/blob/main/CHANGELOG.md) or the [releases](https://github.com/meduzen/datetime-attribute/releases).
## Browser and tooling support
`datetime-attribute` is provided [as module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#browser_compatibility) for [modern browsers usage](https://github.com/meduzen/datetime-attribute/blob/main/browserslist) with standard JavaScript syntax:
- it is up to you to transpile it for legacy browsers;
- you can’t import it using `require('datetime-attribute')`;
- if you don’t transpile it, `DateTime` requires support for [`class` fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields#browser_compatibility) (Safari 14.0) starting `v1.32.0`.[Read more about ESModules](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
## Not only in `
[`
## Security
See the [security policy](https://github.com/meduzen/datetime-attribute/blob/main/SECURITY.md).
## Contributing
See the [contributing guidelines](https://github.com/meduzen/datetime-attribute/blob/main/CONTRIBUTING.md).
## License
The _datetime-attribute_ package is open-sourced software licensed under the [DWTFYWTPL](https://github.com/meduzen/datetime-attribute/blob/main/LICENSE).