Skip to content

Fix of ISO dates in ±12h timezones, and non-negative isEmpty types

Latest

Choose a tag to compare

@uatisdeproblem uatisdeproblem released this 15 Oct 11:22

A fix for the dates computed in the timezones at ±12 hours from UTC and beyond (toISODateString, nowISODateString), two new isEmpty types for values where 0 is valid, and a stricter TimeInterval.validate().

Nothing breaking for valid data: outside those timezones the dates are the same as 7.4.0, the new isEmpty types are only additions, and TimeInterval.validate() rejects only a from that was already invalid.

🐛 Fixes

toISODateString and nowISODateString give the right day in every timezone (#32). From an offset of +12h onwards, or at −12h, the day could shift by one: in Fiji toISODateString('2026-07-15') returned 2026-07-16, in New Zealand's summer a Date at midday gave the day before. Besides the timezones in the issue (Fiji, New Zealand, Chatham, Tonga, Samoa, Kiribati), the other +12h ones were affected too: Kamchatka, Anadyr, Marshall Islands, Tarawa, Tuvalu, Nauru, Wallis, Wake, Norfolk in summer.

  • A day YYYY-MM-DD keeps its date in any timezone.
  • A Date, an epoch or an ISO date-time string gives its day in the local timezone.

Everywhere else the results are the same as 7.4.0, invalid inputs included (they still throw a RangeError): checked in every IANA timezone, in V8 (Node.js, Chrome, Android) and JavaScriptCore (Safari, iOS).
→ If an app had users in those timezones, the dates saved from their devices may be one day off.

TimeInterval.validate() rejects a from that isn't a valid number. A non-numeric from (loaded as NaN) used to pass, since NaN < 0 is false.

✨ New: non-negative numbers in isEmpty (#22)

Two new field types for isEmpty() / Resource.iE(), for values where 0 is valid but negatives aren't (amounts, quantities, durations, …). Until now every numeric type treated 0 as empty.

  • 'nonNegativeNumber' — empty if not a finite number, or < 0. iE(price, 'nonNegativeNumber') replaces !Number.isFinite(price) || price < 0.
  • 'nonNegativeInteger' — empty if not an integer, or < 0. iE(qty, 'nonNegativeInteger') replaces !Number.isInteger(qty) || qty < 0.

Unlike a plain x < 0 — which lets NaN through, since NaN < 0 is false — they also reject NaN, ±Infinity and non-numbers.

A percentage type was considered and left out: the right range depends on the context ([0,100], [1,100], [0,1], …). With the new type it's a one-liner: iE(vat, 'nonNegativeNumber') || vat > 100.