172 lines
5.3 KiB
TypeScript
172 lines
5.3 KiB
TypeScript
|
|
import { test } from 'node:test';
|
||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import dayjs from 'dayjs';
|
||
|
|
import {
|
||
|
|
today,
|
||
|
|
yesterday,
|
||
|
|
timeHour,
|
||
|
|
timeMinute,
|
||
|
|
timeAmPm,
|
||
|
|
timeDay,
|
||
|
|
timeMon,
|
||
|
|
timeMonth,
|
||
|
|
timeYear,
|
||
|
|
timeHourMinute,
|
||
|
|
timeDayMonYear,
|
||
|
|
timeDayMonthYear,
|
||
|
|
daysInMonth,
|
||
|
|
dateFor,
|
||
|
|
inSameDay,
|
||
|
|
minuteDifference,
|
||
|
|
hour24to12,
|
||
|
|
hour12to24,
|
||
|
|
secondsToMs,
|
||
|
|
minutesToMs,
|
||
|
|
hoursToMs,
|
||
|
|
daysToMs,
|
||
|
|
getToday,
|
||
|
|
getYesterday,
|
||
|
|
} from './time';
|
||
|
|
|
||
|
|
test('today is true for now and false for other days', () => {
|
||
|
|
assert.equal(today(Date.now()), true);
|
||
|
|
assert.equal(today(dayjs().subtract(1, 'day').valueOf()), false);
|
||
|
|
assert.equal(today(dayjs().add(1, 'day').valueOf()), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('yesterday is true only for the previous day', () => {
|
||
|
|
assert.equal(yesterday(dayjs().subtract(1, 'day').valueOf()), true);
|
||
|
|
assert.equal(yesterday(Date.now()), false);
|
||
|
|
assert.equal(yesterday(dayjs().subtract(2, 'day').valueOf()), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeHour formats 24h and 12h zero-padded', () => {
|
||
|
|
const ts = Date.now();
|
||
|
|
// 24-hour clock: two digits 00-23
|
||
|
|
assert.match(timeHour(ts, true), /^([01]\d|2[0-3])$/);
|
||
|
|
// 12-hour clock: two digits 01-12
|
||
|
|
assert.match(timeHour(ts, false), /^(0[1-9]|1[0-2])$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeMinute is two digits 00-59', () => {
|
||
|
|
assert.match(timeMinute(Date.now()), /^[0-5]\d$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeAmPm is AM or PM', () => {
|
||
|
|
assert.match(timeAmPm(Date.now()), /^(AM|PM)$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeDay is day-of-month without leading zero', () => {
|
||
|
|
const out = timeDay(Date.now());
|
||
|
|
assert.match(out, /^([1-9]|[12]\d|3[01])$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeMon is a three-letter month abbreviation', () => {
|
||
|
|
// Use a fixed UTC timestamp far from month boundaries to avoid tz drift.
|
||
|
|
const midMonth = dayjs('2021-06-15T12:00:00Z').valueOf();
|
||
|
|
assert.equal(timeMon(midMonth), 'Jun');
|
||
|
|
assert.match(timeMon(Date.now()), /^[A-Z][a-z]{2}$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeMonth is a full month name', () => {
|
||
|
|
const midMonth = dayjs('2021-06-15T12:00:00Z').valueOf();
|
||
|
|
assert.equal(timeMonth(midMonth), 'June');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeYear is a four-digit year', () => {
|
||
|
|
const ts = dayjs('2021-06-15T12:00:00Z').valueOf();
|
||
|
|
assert.equal(timeYear(ts), '2021');
|
||
|
|
assert.match(timeYear(Date.now()), /^\d{4}$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeHourMinute structure for 24h and 12h', () => {
|
||
|
|
const ts = Date.now();
|
||
|
|
assert.match(timeHourMinute(ts, true), /^([01]\d|2[0-3]):[0-5]\d$/);
|
||
|
|
assert.match(timeHourMinute(ts, false), /^(0[1-9]|1[0-2]):[0-5]\d (AM|PM)$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeDayMonYear honors the provided format string', () => {
|
||
|
|
const ts = dayjs('2021-06-15T12:00:00Z').valueOf();
|
||
|
|
assert.equal(timeDayMonYear(ts, 'YYYY'), '2021');
|
||
|
|
assert.equal(timeDayMonYear(ts, 'MMMM'), 'June');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('timeDayMonthYear shape is "D MMMM YYYY"', () => {
|
||
|
|
assert.match(timeDayMonthYear(Date.now()), /^([1-9]|[12]\d|3[01]) [A-Z][a-z]+ \d{4}$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('daysInMonth returns correct counts', () => {
|
||
|
|
assert.equal(daysInMonth(2, 2020), 29); // leap year February
|
||
|
|
assert.equal(daysInMonth(2, 2021), 28);
|
||
|
|
assert.equal(daysInMonth(4, 2021), 30); // April
|
||
|
|
assert.equal(daysInMonth(1, 2021), 31); // January
|
||
|
|
});
|
||
|
|
|
||
|
|
test('dateFor returns a timestamp matching the given date', () => {
|
||
|
|
const ts = dateFor(2021, 6, 15);
|
||
|
|
const d = dayjs(ts);
|
||
|
|
assert.equal(d.year(), 2021);
|
||
|
|
assert.equal(d.month() + 1, 6);
|
||
|
|
assert.equal(d.date(), 15);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('inSameDay compares calendar days in local time', () => {
|
||
|
|
const a = new Date(2021, 5, 15, 1, 0, 0).getTime();
|
||
|
|
const b = new Date(2021, 5, 15, 23, 0, 0).getTime();
|
||
|
|
const c = new Date(2021, 5, 16, 0, 0, 0).getTime();
|
||
|
|
assert.equal(inSameDay(a, b), true);
|
||
|
|
assert.equal(inSameDay(a, c), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('minuteDifference is absolute and rounded', () => {
|
||
|
|
const base = 1_600_000_000_000;
|
||
|
|
assert.equal(minuteDifference(base, base + 60_000), 1);
|
||
|
|
assert.equal(minuteDifference(base + 60_000, base), 1); // absolute value
|
||
|
|
assert.equal(minuteDifference(base, base + 90_000), 2); // rounds 1.5 -> 2
|
||
|
|
assert.equal(minuteDifference(base, base), 0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('hour24to12 maps 24h to 12h clock', () => {
|
||
|
|
assert.equal(hour24to12(0), 12);
|
||
|
|
assert.equal(hour24to12(12), 12);
|
||
|
|
assert.equal(hour24to12(13), 1);
|
||
|
|
assert.equal(hour24to12(23), 11);
|
||
|
|
assert.equal(hour24to12(9), 9);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('hour12to24 maps 12h clock to 24h', () => {
|
||
|
|
assert.equal(hour12to24(12, false), 0); // 12 AM -> 0
|
||
|
|
assert.equal(hour12to24(12, true), 12); // 12 PM -> 12
|
||
|
|
assert.equal(hour12to24(1, false), 1); // 1 AM
|
||
|
|
assert.equal(hour12to24(1, true), 13); // 1 PM
|
||
|
|
assert.equal(hour12to24(11, true), 23); // 11 PM
|
||
|
|
});
|
||
|
|
|
||
|
|
test('millisecond conversion helpers', () => {
|
||
|
|
assert.equal(secondsToMs(1), 1000);
|
||
|
|
assert.equal(minutesToMs(1), 60_000);
|
||
|
|
assert.equal(hoursToMs(1), 3_600_000);
|
||
|
|
assert.equal(daysToMs(1), 86_400_000);
|
||
|
|
assert.equal(daysToMs(2), 172_800_000);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('getToday returns the start-of-today timestamp', () => {
|
||
|
|
const ts = getToday();
|
||
|
|
assert.equal(today(ts), true);
|
||
|
|
const d = dayjs(ts);
|
||
|
|
const now = dayjs();
|
||
|
|
assert.equal(d.year(), now.year());
|
||
|
|
assert.equal(d.month(), now.month());
|
||
|
|
assert.equal(d.date(), now.date());
|
||
|
|
});
|
||
|
|
|
||
|
|
test('getYesterday returns the start-of-yesterday timestamp', () => {
|
||
|
|
const ts = getYesterday();
|
||
|
|
assert.equal(yesterday(ts), true);
|
||
|
|
const d = dayjs(ts);
|
||
|
|
const expected = dayjs().subtract(1, 'day');
|
||
|
|
assert.equal(d.year(), expected.year());
|
||
|
|
assert.equal(d.month(), expected.month());
|
||
|
|
assert.equal(d.date(), expected.date());
|
||
|
|
});
|