Upstream spencermountain/spacetime state of the touched files before d9eaced13f
This commit is contained in:
commit
96f6f12e4e
3 files changed
+7931
No files matched your search
Generated
+7415
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,276 @@
|
|||||||
|
// javascript setX methods like setDate() can't be used because of the local bias
|
||||||
|
//these methods wrap around them.
|
||||||
|
import ms from '../../data/milliseconds.js'
|
||||||
|
import { mapping } from '../../data/months.js'
|
||||||
|
import walkTo from './walk.js'
|
||||||
|
import { isLeapYear } from '../../fns.js'
|
||||||
|
import { getMonthLength } from './_model.js'
|
||||||
|
|
||||||
|
const validate = (n) => {
|
||||||
|
//handle number as a string
|
||||||
|
if (typeof n === 'string') {
|
||||||
|
n = parseInt(n, 10)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond']
|
||||||
|
|
||||||
|
//reduce hostile micro-changes when moving dates by millisecond
|
||||||
|
const confirm = (s, tmp, unit) => {
|
||||||
|
const n = order.indexOf(unit)
|
||||||
|
const arr = order.slice(n, order.length)
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
const want = tmp[arr[i]]()
|
||||||
|
s[arr[i]](want)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow specifying setter direction
|
||||||
|
const fwdBkwd = function (s, old, goFwd, unit) {
|
||||||
|
if (goFwd === true && s.isBefore(old)) {
|
||||||
|
s = s.add(1, unit)
|
||||||
|
} else if (goFwd === false && s.isAfter(old)) {
|
||||||
|
s = s.minus(1, unit)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
const milliseconds = function (s, n) {
|
||||||
|
n = validate(n)
|
||||||
|
const current = s.millisecond()
|
||||||
|
const diff = current - n //milliseconds to shift by
|
||||||
|
return s.epoch - diff
|
||||||
|
}
|
||||||
|
|
||||||
|
const seconds = function (s, n, goFwd) {
|
||||||
|
n = validate(n)
|
||||||
|
const old = s.clone()
|
||||||
|
const diff = s.second() - n
|
||||||
|
const shift = diff * ms.second
|
||||||
|
s.epoch = s.epoch - shift
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'minute') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const minutes = function (s, n, goFwd) {
|
||||||
|
n = validate(n)
|
||||||
|
const old = s.clone()
|
||||||
|
const diff = s.minute() - n
|
||||||
|
const shift = diff * ms.minute
|
||||||
|
s.epoch -= shift
|
||||||
|
confirm(s, old, 'second')
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'hour') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const hours = function (s, n, goFwd) {
|
||||||
|
n = validate(n)
|
||||||
|
if (n >= 24) {
|
||||||
|
n = 24
|
||||||
|
} else if (n < 0) {
|
||||||
|
n = 0
|
||||||
|
}
|
||||||
|
const old = s.clone()
|
||||||
|
let diff = s.hour() - n
|
||||||
|
let shift = diff * ms.hour
|
||||||
|
s.epoch -= shift
|
||||||
|
// oops, did we change the day?
|
||||||
|
if (s.date() !== old.date()) {
|
||||||
|
s = old.clone()
|
||||||
|
if (diff > 1) {
|
||||||
|
diff -= 1
|
||||||
|
}
|
||||||
|
if (diff < 1) {
|
||||||
|
diff += 1
|
||||||
|
}
|
||||||
|
shift = diff * ms.hour
|
||||||
|
s.epoch -= shift
|
||||||
|
}
|
||||||
|
walkTo(s, {
|
||||||
|
hour: n
|
||||||
|
})
|
||||||
|
confirm(s, old, 'minute')
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'day') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = function (s, str, goFwd) {
|
||||||
|
let m = str.match(/([0-9]{1,2})[:h]([0-9]{1,2})(:[0-9]{1,2})? ?(am|pm)?/)
|
||||||
|
if (!m) {
|
||||||
|
//fallback to support just '2am'
|
||||||
|
m = str.match(/([0-9]{1,2}) ?(am|pm)/)
|
||||||
|
if (!m) {
|
||||||
|
return null // invalid time string - mark as invalid
|
||||||
|
}
|
||||||
|
m.splice(2, 0, '0') //add implicit 0 minutes
|
||||||
|
m.splice(3, 0, '') //add implicit seconds
|
||||||
|
}
|
||||||
|
let h24 = false
|
||||||
|
let hour = parseInt(m[1], 10)
|
||||||
|
let minute = parseInt(m[2], 10)
|
||||||
|
if (minute >= 60) {
|
||||||
|
minute = 59
|
||||||
|
}
|
||||||
|
if (hour > 12) {
|
||||||
|
h24 = true
|
||||||
|
}
|
||||||
|
//make the hour into proper 24h time
|
||||||
|
if (h24 === false) {
|
||||||
|
if (m[4] === 'am' && hour === 12) {
|
||||||
|
//12am is midnight
|
||||||
|
hour = 0
|
||||||
|
}
|
||||||
|
if (m[4] === 'pm' && hour < 12) {
|
||||||
|
//12pm is noon
|
||||||
|
hour += 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handle seconds
|
||||||
|
m[3] = m[3] || ''
|
||||||
|
m[3] = m[3].replace(/:/, '')
|
||||||
|
const sec = parseInt(m[3], 10) || 0
|
||||||
|
const old = s.clone()
|
||||||
|
s = s.hour(hour)
|
||||||
|
s = s.minute(minute)
|
||||||
|
s = s.second(sec)
|
||||||
|
s = s.millisecond(0)
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'day') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = function (s, n, goFwd) {
|
||||||
|
n = validate(n)
|
||||||
|
//avoid setting february 31st (leap-aware, same as add())
|
||||||
|
if (n > 28) {
|
||||||
|
const max = getMonthLength(s.month(), s.year())
|
||||||
|
if (n > max) {
|
||||||
|
n = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//avoid setting < 0
|
||||||
|
if (n <= 0) {
|
||||||
|
n = 1
|
||||||
|
}
|
||||||
|
const old = s.clone()
|
||||||
|
walkTo(s, {
|
||||||
|
date: n
|
||||||
|
})
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'month') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const month = function (s, n, goFwd) {
|
||||||
|
if (typeof n === 'string') {
|
||||||
|
if (n === 'sept') {
|
||||||
|
n = 'sep'
|
||||||
|
}
|
||||||
|
n = mapping()[n.toLowerCase()]
|
||||||
|
}
|
||||||
|
n = validate(n)
|
||||||
|
//don't go past december
|
||||||
|
if (n >= 12) {
|
||||||
|
n = 11
|
||||||
|
}
|
||||||
|
if (n <= 0) {
|
||||||
|
n = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let d = s.date()
|
||||||
|
//there's no 30th of february, etc. (leap-aware, same as add())
|
||||||
|
const max = getMonthLength(n, s.year())
|
||||||
|
if (d > max) {
|
||||||
|
//make it as close as we can..
|
||||||
|
d = max
|
||||||
|
}
|
||||||
|
const old = s.clone()
|
||||||
|
walkTo(s, {
|
||||||
|
month: n,
|
||||||
|
date: d
|
||||||
|
})
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'year') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = function (s, n) {
|
||||||
|
// support '97
|
||||||
|
if (typeof n === 'string' && /^'[0-9]{2}$/.test(n)) {
|
||||||
|
n = n.replace(/'/, '').trim()
|
||||||
|
n = Number(n)
|
||||||
|
// '89 is 1989
|
||||||
|
if (n > 30) {
|
||||||
|
//change this in 10y
|
||||||
|
n = 1900 + n
|
||||||
|
} else {
|
||||||
|
// '12 is 2012
|
||||||
|
n = 2000 + n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = validate(n)
|
||||||
|
walkTo(s, {
|
||||||
|
year: n
|
||||||
|
})
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
const week = function (s, n, goFwd) {
|
||||||
|
const old = s.clone()
|
||||||
|
n = validate(n)
|
||||||
|
|
||||||
|
// don't set week=1, if we're already week=1 in late december
|
||||||
|
// because this could send us to another year
|
||||||
|
if (n === 1) {
|
||||||
|
if (s.monthName() === 'december' && s.date() >= 29) {
|
||||||
|
if (s.week() === 1) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the first week of the year
|
||||||
|
s = s.month(0)
|
||||||
|
s = s.date(1)
|
||||||
|
s = s.day('monday', false)//go backwards to monday
|
||||||
|
// did we go back too far?
|
||||||
|
if (s.monthName() === 'december' && s.date() < 29) {
|
||||||
|
s = s.add(1, 'week')
|
||||||
|
}
|
||||||
|
n -= 1 //1-based
|
||||||
|
s = s.add(n, 'weeks')
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'year') // specify direction
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayOfYear = function (s, n, goFwd) {
|
||||||
|
n = validate(n)
|
||||||
|
const old = s.clone()
|
||||||
|
n -= 1 //days are 1-based
|
||||||
|
if (n <= 0) {
|
||||||
|
n = 0
|
||||||
|
} else if (n >= 365) {
|
||||||
|
if (isLeapYear(s.year())) {
|
||||||
|
n = 365
|
||||||
|
} else {
|
||||||
|
n = 364
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = s.startOf('year')
|
||||||
|
s = s.add(n, 'day')
|
||||||
|
confirm(s, old, 'hour')
|
||||||
|
s = fwdBkwd(s, old, goFwd, 'year') // specify direction
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
milliseconds,
|
||||||
|
seconds,
|
||||||
|
minutes,
|
||||||
|
hours,
|
||||||
|
time,
|
||||||
|
date,
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
week,
|
||||||
|
dayOfYear,
|
||||||
|
}
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
import test from 'tape'
|
||||||
|
import spacetime from './lib/index.js'
|
||||||
|
|
||||||
|
test('set', (t) => {
|
||||||
|
let s = spacetime('June 22, 2017 20:12:01', 'Canada/Pacific')
|
||||||
|
|
||||||
|
s = s.date(5)
|
||||||
|
t.equal(s.date(), 5, '.date(5)')
|
||||||
|
|
||||||
|
s = s.date('24')
|
||||||
|
t.equal(s.date(), 24, '.date-string-int')
|
||||||
|
|
||||||
|
s = s.date(12)
|
||||||
|
t.equal(s.date(), 12, '.date()')
|
||||||
|
|
||||||
|
s = s.year(2015)
|
||||||
|
t.equal(s.year(), 2015, '.year()')
|
||||||
|
|
||||||
|
s = s.hour(5)
|
||||||
|
t.equal(s.hour(), 5, '.hour()')
|
||||||
|
|
||||||
|
s = s.minute(8)
|
||||||
|
t.equal(s.minute(), 8, '.minute()')
|
||||||
|
|
||||||
|
s = s.month('february')
|
||||||
|
t.equal(s.month(), 1, '.month()')
|
||||||
|
|
||||||
|
s = s.month('June')
|
||||||
|
t.equal(s.monthName(), 'june', '.month()')
|
||||||
|
|
||||||
|
s = s.month('apr')
|
||||||
|
t.equal(s.monthName(), 'april', '.month()')
|
||||||
|
|
||||||
|
s = s.week(1) //mon dec 29th
|
||||||
|
t.equal(s.monthName(), 'december', '.week()')
|
||||||
|
|
||||||
|
s = s.quarter(1)
|
||||||
|
t.equal(s.quarter(), 1, '.quarter()')
|
||||||
|
|
||||||
|
s = s.hourFloat(7.25)
|
||||||
|
t.equal(s.hour(), 7, '.hour()')
|
||||||
|
t.equal(s.minute(), 15, '.minute()')
|
||||||
|
|
||||||
|
s = s.dayOfYear(15)
|
||||||
|
t.equal(s.monthName(), 'january', 'dayOfYear-.month()')
|
||||||
|
t.equal(s.date(), 15, '.dayofYear-date')
|
||||||
|
|
||||||
|
s = s.month(1)
|
||||||
|
t.equal(s.monthName(), 'february', '.monthNum()')
|
||||||
|
|
||||||
|
s = s.season('summer')
|
||||||
|
t.equal(s.monthName(), 'june', 'season-.month()')
|
||||||
|
t.equal(s.date(), 1, 'season-.date()')
|
||||||
|
|
||||||
|
s = s.hour(7)
|
||||||
|
s = s.ampm('am')
|
||||||
|
t.equal(s.ampm(), 'am', 'ampm-already-ampm()')
|
||||||
|
t.equal(s.hour(), 7, 'ampm-already-hour()')
|
||||||
|
|
||||||
|
s = s.ampm('pm')
|
||||||
|
t.equal(s.hour(), 19, 'ampm-hour()')
|
||||||
|
t.equal(s.ampm(), 'pm', 'ampm-ampm()')
|
||||||
|
|
||||||
|
s = s.time('5:25')
|
||||||
|
t.equal(s.hour(), 5, 'time-hour()')
|
||||||
|
t.equal(s.minute(), 25, 'time-minute()')
|
||||||
|
|
||||||
|
s = s.time('5:20pm')
|
||||||
|
t.equal(s.hour(), 17, 'time-hour-pm()')
|
||||||
|
t.equal(s.minute(), 20, 'time-minute-pm()')
|
||||||
|
|
||||||
|
s = s.time('5:20 pm')
|
||||||
|
t.equal(s.hour(), 17, 'time-hour-pm-with-space()')
|
||||||
|
t.equal(s.minute(), 20, 'time-minute-pm-with-space()')
|
||||||
|
|
||||||
|
s = s.time('5pm')
|
||||||
|
t.equal(s.hour(), 17, 'time-hour-pm-hour-only()')
|
||||||
|
t.equal(s.minute(), 0, 'time-minute-pm-hour-only()')
|
||||||
|
|
||||||
|
s = s.time('6 pm')
|
||||||
|
t.equal(s.hour(), 18, 'time-hour-pm-hour-only-with-space()')
|
||||||
|
t.equal(s.minute(), 0, 'time-minute-pm-hour-only-with-space()')
|
||||||
|
|
||||||
|
s = s.time('13:20pm')
|
||||||
|
t.equal(s.hour(), 13, 'time-hour-24h()')
|
||||||
|
t.equal(s.minute(), 20, 'time-minute-24h()')
|
||||||
|
t.equal(s.era(), 'AD', '2017 ad')
|
||||||
|
|
||||||
|
s = s.era('bc')
|
||||||
|
t.equal(s.era(), 'BC', '2015 bc')
|
||||||
|
// t.equal(s.year(), -2015, '-2015') //may be broken?
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('set by weekday', (t) => {
|
||||||
|
let s = spacetime([2017, 2, 22], 'Canada/Eastern') //wednesday
|
||||||
|
//make sure it's in the right place
|
||||||
|
t.equal(s.date(), 22, '.date()')
|
||||||
|
t.equal(s.dayName(), 'wednesday', '.day()')
|
||||||
|
|
||||||
|
s = s.day('thursday')
|
||||||
|
t.equal(s.date(), 23, 'now thursday')
|
||||||
|
|
||||||
|
s = s.day('friday')
|
||||||
|
t.equal(s.date(), 24, 'now friday')
|
||||||
|
|
||||||
|
s = s.day('sat')
|
||||||
|
t.equal(s.date(), 25, 'now saturday')
|
||||||
|
|
||||||
|
s = s.day('sunday')
|
||||||
|
//never click-into the next week
|
||||||
|
t.equal(s.date(), 19, 'now sunday')
|
||||||
|
|
||||||
|
s = s.day('monday')
|
||||||
|
t.equal(s.date(), 20, 'now monday')
|
||||||
|
|
||||||
|
s = s.day(2)
|
||||||
|
t.equal(s.date(), 21, 'now tuesday')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('set-tricky', (t) => {
|
||||||
|
let s = spacetime('June 22, 2017 13:01:00', 'Canada/Eastern') //the 22rd
|
||||||
|
t.equal(s.date(), 22, '.date()')
|
||||||
|
t.equal(s.hour(), 13, '.hour()')
|
||||||
|
t.equal(s.ampm(), 'pm', 'night-here')
|
||||||
|
|
||||||
|
s = s.goto('Australia/Brisbane') //the 23rd
|
||||||
|
t.equal(s.date(), 23, 'tomorrow-there')
|
||||||
|
t.equal(s.ampm(), 'am', 'am-there')
|
||||||
|
//make it 1oclock
|
||||||
|
s = s.hour(13)
|
||||||
|
t.equal(s.hour(), 13, '.hour-remote')
|
||||||
|
//make it 1:30pm
|
||||||
|
s = s.minute(30)
|
||||||
|
t.equal(s.minute(), 30, '.minute-remote')
|
||||||
|
//make it the 5th (not working)
|
||||||
|
s = s.date(5)
|
||||||
|
t.equal(s.date(), 5, 'set-date-remotely')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('rollback-in-constructor', (t) => {
|
||||||
|
let s = spacetime('June 22, 2017 5:01:00', 'Australia/Brisbane')
|
||||||
|
t.equal(s.hour(), 5, 'hour-australia')
|
||||||
|
s = spacetime('June 22, 2017 5:01:00', 'Canada/Pacific')
|
||||||
|
t.equal(s.hour(), 5, 'hour-pacific')
|
||||||
|
s = spacetime('June 22, 2017 5:01:00', 'Canada/Eastern')
|
||||||
|
t.equal(s.hour(), 5, 'hour-eastern')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('set-date-fancy', (t) => {
|
||||||
|
let s = spacetime('June 22, 2017 20:01:00', 'Australia/Brisbane') //the 22rd
|
||||||
|
t.equal(s.date(), 22, '.date-before')
|
||||||
|
s = s.date(15)
|
||||||
|
t.equal(s.date(), 15, '.date-after')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('military time format', (t) => {
|
||||||
|
let s = spacetime('2018-10-21')
|
||||||
|
s = s.time('13h00')
|
||||||
|
t.equal(s.time(), '1:00pm', '13h00')
|
||||||
|
s = s.time('2h30')
|
||||||
|
t.equal(s.time(), '2:30am', '2h30')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('add-a-week-bug', (t) => {
|
||||||
|
const a = spacetime('2018-10-21').goto('America/Adak').add(1, 'week')
|
||||||
|
const b = spacetime('2018-10-22').goto('America/Adak').add(1, 'week')
|
||||||
|
t.notEqual(a.format('iso'), b.format('iso'), 'two days are not the same')
|
||||||
|
t.equal(a.diff(b, 'day'), 1, 'still one day apart')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('set time', (t) => {
|
||||||
|
const a = spacetime('2018-10-21').time('5:00pm').time('3:90pm')
|
||||||
|
t.equal(a.time(), '3:59pm', 'dont overflow minutes in time format')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('invalid time parsing', (t) => {
|
||||||
|
// Invalid time formats should return isValid() === false
|
||||||
|
let s = spacetime.now()
|
||||||
|
|
||||||
|
s = s.time('abc')
|
||||||
|
t.equal(s.isValid(), false, 'abc is invalid')
|
||||||
|
|
||||||
|
s = spacetime.now().time('2')
|
||||||
|
t.equal(s.isValid(), false, '2 (no am/pm) is invalid')
|
||||||
|
|
||||||
|
s = spacetime.now().time('hello world')
|
||||||
|
t.equal(s.isValid(), false, 'hello world is invalid')
|
||||||
|
|
||||||
|
s = spacetime.now().time('')
|
||||||
|
t.equal(s.isValid(), false, 'empty string is invalid')
|
||||||
|
|
||||||
|
s = spacetime.now().time('not a time')
|
||||||
|
t.equal(s.isValid(), false, 'not a time is invalid')
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('time parsing edge cases', (t) => {
|
||||||
|
let s = spacetime.now()
|
||||||
|
|
||||||
|
s = s.time('12am')
|
||||||
|
t.equal(s.isValid(), true, '12am is valid')
|
||||||
|
t.equal(s.hour(), 0, '12am is midnight (hour 0)')
|
||||||
|
|
||||||
|
s = spacetime.now().time('12pm')
|
||||||
|
t.equal(s.isValid(), true, '12pm is valid')
|
||||||
|
t.equal(s.hour(), 12, '12pm is noon (hour 12)')
|
||||||
|
|
||||||
|
s = spacetime.now().time('1:00am')
|
||||||
|
t.equal(s.isValid(), true, '1:00am is valid')
|
||||||
|
|
||||||
|
s = spacetime.now().time('11:59pm')
|
||||||
|
t.equal(s.isValid(), true, '11:59pm is valid')
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('month()/date() setters clamp the day to the month length', (t) => {
|
||||||
|
const iso = (s) => s.format('iso-short')
|
||||||
|
// .month() must clamp the day to the target month's length
|
||||||
|
t.equal(iso(spacetime('2020-01-31').month('april')), '2020-04-30', 'jan 31 -> april clamps to the 30th')
|
||||||
|
t.equal(iso(spacetime('2020-01-31').month('june')), '2020-06-30', 'jan 31 -> june clamps to the 30th')
|
||||||
|
// leap-year february
|
||||||
|
t.equal(iso(spacetime('2020-01-31').month('february')), '2020-02-29', 'jan 31 -> feb 29 in a leap year')
|
||||||
|
t.equal(iso(spacetime('2024-01-31').month('february')), '2024-02-29', 'jan 31 -> feb 29 in a leap year')
|
||||||
|
t.equal(iso(spacetime('2021-01-31').month('february')), '2021-02-28', 'jan 31 -> feb 28 in a common year')
|
||||||
|
// .date() must clamp to the same leap-aware length
|
||||||
|
t.equal(iso(spacetime('2020-02-10').date(31)), '2020-02-29', 'date(31) in a leap february clamps to the 29th')
|
||||||
|
t.equal(iso(spacetime('2020-02-10').date(30)), '2020-02-29', 'date(30) in a leap february clamps to the 29th')
|
||||||
|
t.equal(iso(spacetime('2021-02-10').date(31)), '2021-02-28', 'date(31) in a common february clamps to the 28th')
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
Reference in new issue
Block a user