Skip to content

Commit

Permalink
Add datetime using the Temporal API
Browse files Browse the repository at this point in the history
  • Loading branch information
meduzen committed Nov 25, 2023
1 parent f89f1a8 commit a771a0e
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 3 deletions.
89 changes: 89 additions & 0 deletions src/temporal/datetime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { weekNumber } from './utils/date.js'
import { p } from '../utils/string.js'
import { tzOffset } from '../timezone.js'
import { config } from '../config/datetime'
import { Temporal, Intl, toTemporalInstant } from '@js-temporal/polyfill'

Date.prototype.toTemporalInstant = toTemporalInstant

/**
* Create `datetime="2021-12-02"` attribute for `<time>`.
*
* Support all format from the spec.
* https://html.spec.whatwg.org/multipage/text-level-semantics.html#attr-time-datetime
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLTimeElement/datetime
*
* See also: https://www.brucelawson.co.uk/2012/best-of-time/
*
* @param {Date=} date
* @param {Precision=} precision
* @returns {string}
*/
export function datetime(date = new Date(), precision = 'day') {
if (!(date instanceof Date)) {
throw new TypeError('Input date should be of type `Date`')
}

const instant = date.toTemporalInstant();
const zoned = instant.toZonedDateTimeISO(Temporal.Now.timeZoneId())

const yearISO = y => {

// Year 0 doesn’t exists in real life, but does in the ISO-8601 spec.
const sign = y < 0 ? '-' : '' // no sign if year is not negative

// Remove sign (stored separately, see previous line).
y = Math.abs(y)

let bigYearDigits = ''

// Cut last 4 digits of the year from the others to ease further computation.
if (y > 9999) {
[bigYearDigits, y] = (y / 10000).toFixed(4).split('.')
}

return sign + bigYearDigits + y.toString().padStart(4, 0)
}

// const iso = date.toISOString();

const temporalFormat = {
year: () => yearISO(Temporal.PlainYearMonth.from(zoned).year), // 1960
// year: () => date.getFullYear(), // 1960
month: () => Temporal.PlainYearMonth.from(zoned), // 1960-04
day: () => Temporal.PlainDate.from(zoned), // 1960-04-27

week: () => date.getFullYear() + '-W' + p(weekNumber(date)), // 1960-W17
yearless: () => Temporal.PlainMonthDay.from(zoned), // 04-27

time: () => Temporal.PlainTime.from(zoned).toString({ smallestUnit: 'minutes' }), // 00:00
second: () => Temporal.PlainTime.from(zoned), // 00:00:00
ms: () => Temporal.PlainTime.from(zoned).toString({ smallestUnit: 'milliseconds' }), // 00:00:00.123

datetime: () => Temporal.PlainDateTime.from(zoned).toString({ smallestUnit: 'minutes' }), // 1960-04-27T00:00
'datetime second': () => Temporal.PlainDateTime.from(zoned), // 1960-04-27T00:00:00
'datetime ms': () => Temporal.PlainDateTime.from(zoned).toString({ smallestUnit: 'milliseconds' }), // 1960-04-27T00:00:00.123

'datetime utc': () => instant.toString({ smallestUnit: 'minute' }), // 1960-04-26T23:00Z
'datetime second utc': () => instant, // 1960-04-26T23:00:00Z
'datetime ms utc': () => instant.toString({ fractionalSecondDigits: 3 }), // 1960-04-26T23:00:00.000Z

'time utc': () =>
instant.toString({ smallestUnit: 'minute' }).substr(11, 6), // 23:00Z
'second utc': () => instant.toString().substr(11, 9), // 23:00:00Z
'ms utc': () =>
instant.toString({ fractionalSecondDigits: 3 }).substr(11, 13), // 23:00:00.000Z
}

return (temporalFormat[precision] || temporalFormat.day)().toString().replace('T', config.separator)
}

/**
* Supported precision keywords.
*
* @typedef { 'day' | 'year' | 'yearless' | 'month' | 'week' |
* 'time' | 'second' | 'ms' |
* 'time utc' | 'second utc' | 'ms utc' |
* 'datetime' | 'datetime second' | 'datetime ms' |
* 'datetime utc' | 'datetime second utc' | 'datetime ms utc' } Precision
*/
1 change: 1 addition & 0 deletions src/temporal/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { duration } from './duration.js'
export { datetime } from './datetime.js'
5 changes: 2 additions & 3 deletions tests/temporal/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import { describe, expect, test } from 'vitest'

import {
DateTime,
datetime,
utc,
datetimeTz,
tzOffset,
setTimeSeparator,
setTzSeparator,
} from '../../src'

import { duration } from '../../src/temporal'
import { duration, datetime } from '../../src/temporal'
import { daysBetween, weekNumber } from '../../src/temporal/utils/date'

/**
Expand All @@ -37,7 +36,7 @@ const year10k = new Date(10000, 0, 1)

const tzOffsetInMinutes = (new Date()).getTimezoneOffset() * -1

describe.todo('datetime', () => {
describe('datetime', () => {
test('is a function', () => expect(datetime).toBeInstanceOf(Function))
test('wrong type', () => expect(() => datetime(123)).toThrow(TypeError))

Expand Down

0 comments on commit a771a0e

Please sign in to comment.