New:Socket for Asana Is Now Available.Learn more
Get Started

@ultimat3/time

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ultimat3/time - npm Package Compare versions

Comparing version
17.0.0
to
18.0.0
+9
-0
CLAUDE.md

@@ -159,2 +159,11 @@ # @ultimat3/time — agent notes

breaks the signed-duration contract `toSeconds` is built on.
- **`toMs(duration, subject?, option?)` names the caller's knob in the refusal, `As of 2026-08-26`.**
`pass a finite duration to toMs` names a function an app author reached THROUGH rather than
wrote: `@ultimat3/testing`'s `clock.advance('3s')` hands its argument straight down, and so does
any wrapper an app builds. The two names are the same two, in the same order, that
`@ultimat3/jobs`' `finiteDurationMs` takes — one shape, not two. They are **optional** here and
required there because this one is published API: making them required is `TS2554` at every
existing call site in every app, a major for a better sentence. The defaults reproduce today's
message byte for byte, so the only observable change is at a call site that supplies them.
`toSeconds` threads them too and defaults its subject to **`toSeconds`**, not to the delegate.
- Tests must cover a spring-forward gap, a fall-back overlap and a non-hour offset zone.

@@ -161,0 +170,0 @@

+3
-3
{
"name": "@ultimat3/time",
"version": "17.0.0",
"version": "18.0.0",
"description": "UTC instants, DST-correct zone math, cron, durations and Intl formatting with an explicit timezone",

@@ -30,3 +30,3 @@ "license": "MIT",

"engines": {
"bun": ">=1.3.0"
"bun": ">=1.4.0"
},

@@ -38,4 +38,4 @@ "scripts": {

"dependencies": {
"@ultimat3/core": "17.0.0"
"@ultimat3/core": "18.0.0"
}
}

@@ -78,6 +78,18 @@ /**

* `@ultimat3/notify`'s `toDurationMs` does; narrowing here would break both.
*
* `subject` and `option` name the knob the APP AUTHOR wrote, for the refusal only. They default to
* this function's own name, which is the right answer for the caller who typed `toMs(…)` and the
* wrong one for every caller reached THROUGH it: `clock.advance('3s')` in `@ultimat3/testing`
* passes its argument straight down, and `pass a finite duration to toMs` sends that author
* looking for a knob their code does not contain. Same two names, same order, as
* `@ultimat3/jobs`' `finiteDurationMs` — one shape, not two.
*
* OPTIONAL rather than required, unlike that one, because this function is published API: a
* required parameter is `TS2554` at every existing call site in every app, which is a major for a
* better sentence. The default reproduces today's message byte for byte, so supplying them is the
* only observable change.
*/
export function toMs(duration: string | number): number {
export function toMs(duration: string | number, subject = 'toMs', option = 'duration'): number {
return typeof duration === 'number'
? finiteOption('toMs', 'duration', duration)
? finiteOption(subject, option, duration)
: parseDuration(duration);

@@ -91,5 +103,13 @@ }

* framework's one statement of this, and `signed()` there is why zero never comes back as `-0`.
*
* The screen is `toMs`'s, threaded — but the default subject is `toSeconds`, because that is the
* name a direct caller wrote. Naming the delegate would point them at a function they never typed,
* which is the whole defect this pair of parameters exists to fix.
*/
export function toSeconds(duration: string | number): number {
const ms = toMs(duration);
export function toSeconds(
duration: string | number,
subject = 'toSeconds',
option = 'duration',
): number {
const ms = toMs(duration, subject, option);
const seconds = Math.round(Math.abs(ms) / SECOND);

@@ -96,0 +116,0 @@ if (seconds === 0) return 0;