Upstream spencermountain/spacetime state of the touched files before d9eaced13f

This commit is contained in:
upstream committed 2026-09-04 09:43:57 +02:00
commit 96f6f12e4e
3 files changed
+7931

No files matched your search

+276
View File
@@ -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,
}