import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { addJalaliMonths, endOfJalaliMonth, formatTehranJalali, jalaliMonthName, rewriteGregorianDates, toGregorian, toJalali, } from '../src/common/jalali'; import { addDays, dayDiff, eachDay, isDayKey, isTimeOfDay, jalaliDayOfMonth, persianWeekday, tehranDateTime, tehranDayKey, tehranHour, weekStartKey, } from '../src/routines/routine-dates'; import { formatTehranJalaliNumeric, isDueInDays, } from '../src/finance/cheque-reminder.util'; describe('تبدیل تاریخ شمسی', () => { const pairs: Array<[[number, number, number], [number, number, number]]> = [ [[2026, 10, 8], [1405, 7, 16]], [[2025, 3, 21], [1404, 1, 1]], [[2024, 3, 20], [1403, 1, 1]], [[2025, 3, 20], [1403, 12, 30]], [[2000, 1, 1], [1378, 10, 11]], ]; for (const [[gy, gm, gd], [jy, jm, jd]] of pairs) { it(`${gy}-${gm}-${gd} ⇄ ${jy}/${jm}/${jd}`, () => { assert.deepEqual(toJalali(gy, gm, gd), { jy, jm, jd }); assert.deepEqual(toGregorian(jy, jm, jd), { gy, gm, gd }); }); } it('رفت‌وبرگشت برای هر روز دو سال', () => { const d = new Date(Date.UTC(2024, 0, 1)); for (let i = 0; i < 731; i += 1) { const gy = d.getUTCFullYear(); const gm = d.getUTCMonth() + 1; const gd = d.getUTCDate(); const j = toJalali(gy, gm, gd); assert.deepEqual(toGregorian(j.jy, j.jm, j.jd), { gy, gm, gd }); d.setUTCDate(gd + 1); } }); it('ماه‌ها', () => { assert.deepEqual(addJalaliMonths(1405, 12, 1), { jy: 1406, jm: 1 }); assert.deepEqual(addJalaliMonths(1405, 1, -1), { jy: 1404, jm: 12 }); assert.equal(jalaliMonthName(7), 'مهر'); assert.equal(jalaliMonthName(13), ''); const end = endOfJalaliMonth(1405, 6); const j = toJalali(end.getFullYear(), end.getMonth() + 1, end.getDate()); assert.deepEqual(j, { jy: 1405, jm: 6, jd: 31 }); }); }); describe('روزهای روتین (وقت تهران)', () => { it('کلید روز با منطقهٔ زمانی تهران', () => { // ۰۰:۳۰ بامداد تهران = ۲۱:۰۰ UTC روز قبل assert.equal(tehranDayKey(new Date('2026-10-07T21:00:00Z')), '2026-10-08'); assert.equal(tehranDayKey(new Date('2026-10-07T20:29:00Z')), '2026-10-07'); assert.equal(tehranHour(new Date('2026-10-07T21:00:00Z')), 0); }); it('اعتبارسنجی', () => { assert.ok(isDayKey('2026-10-08')); assert.ok(!isDayKey('1405/07/16')); assert.ok(isTimeOfDay('23:59')); assert.ok(!isTimeOfDay('24:00')); }); it('محاسبات روز و هفته', () => { assert.equal(addDays('2026-12-31', 1), '2027-01-01'); assert.equal(dayDiff('2026-10-01', '2026-10-08'), 7); assert.equal(persianWeekday('2026-10-08'), 5); // پنجشنبه assert.equal(persianWeekday('2026-10-03'), 0); // شنبه assert.equal(weekStartKey('2026-10-08'), '2026-10-03'); assert.equal(jalaliDayOfMonth('2026-10-08'), 16); assert.deepEqual(eachDay('2026-10-01', '2026-10-03'), ['2026-10-01', '2026-10-02', '2026-10-03']); assert.equal(tehranDateTime('2026-10-08', '09:00').toISOString(), '2026-10-08T05:30:00.000Z'); }); }); describe('یادآور چک', () => { it('تاریخ شمسی به وقت تهران', () => { assert.equal(formatTehranJalaliNumeric(new Date('2026-10-08T10:00:00Z')), '۱۴۰۵/۰۷/۱۶'); assert.equal(formatTehranJalaliNumeric(new Date('2026-10-07T21:00:00Z')), '۱۴۰۵/۰۷/۱۶'); }); it('سررسید سه روز بعد', () => { const now = new Date('2026-10-08T06:00:00Z'); assert.ok(isDueInDays(new Date('2026-10-11T12:00:00Z'), 3, now)); assert.ok(!isDueInDays(new Date('2026-10-12T12:00:00Z'), 3, now)); }); }); describe('بازنویسی تاریخ میلادی در متن', () => { const now = new Date('2026-10-13T08:00:00Z'); it('۲۱ سپتامبر را شمسی می‌کند و مهر را دست نمی‌زند', () => { const out = rewriteGregorianDates('آخرین خرید در تاریخ 21 سپتامبر انجام شده', now); assert.equal(out.includes('سپتامبر'), false); assert.match(out, /۱۴۰۵\/۰۶\/۳۰/); assert.equal(rewriteGregorianDates('مهلت تا 21 مهر ۱۴۰۵', now), 'مهلت تا 21 مهر ۱۴۰۵'); assert.equal(rewriteGregorianDates('می‌شود 21 بار', now), 'می‌شود 21 بار'); }); it('September و تاریخ عددی میلادی را شمسی می‌کند', () => { assert.match(rewriteGregorianDates('bought on September 21, 2025', now), /۱۴۰۴\/۰۶\/۳۰/); assert.equal(rewriteGregorianDates('due 2026-09-21', now), 'due ۱۴۰۵/۰۶/۳۰'); assert.equal(formatTehranJalali(new Date('2026-09-21T08:00:00Z')), '۱۴۰۵/۰۶/۳۰'); }); });