refactor: normalize date handling to Tehran timezone

- Updated date handling in BlogSeoFields and ScheduleSection to use Tehran timezone utilities for consistency.
- Introduced `toTehranClockTime`, `tehranWallClockToUnix`, and `todayIso` functions for accurate date representation.
- Modified various components to utilize these new utilities, ensuring that date strings are correctly formatted and timestamps are accurately converted.
- Enhanced API documentation to clarify the handling of date fields, emphasizing the importance of server-local midnight.
- Added tests to verify that date overrides and holidays maintain the correct day without shifting due to timezone discrepancies.
This commit is contained in:
hamed
2026-07-27 19:37:44 +03:30
parent 2963e2ac74
commit b423a0ae4d
21 changed files with 267 additions and 57 deletions
+40
View File
@@ -16,6 +16,10 @@ import {
formatDate,
formatDateTime,
toGregorianDate,
toTehranClockTime,
tehranWallClockToUnix,
unixToIso,
todayIso,
maskMobile,
cn,
toEnglishDigits,
@@ -107,6 +111,42 @@ describe('toGregorianDate', () => {
});
});
describe('unixToIso / todayIso / toTehranClockTime', () => {
// نیمه‌شبِ ۲۹ ژوئیهٔ ۲۰۲۶ به وقت تهران = ۲۸ ژوئیه ۲۰:۳۰ UTC. تبدیل با
// toISOString همین‌جا یک روز عقب می‌رفت — رگرسیونِ «تاریخ خاص یک روز قبل».
const tehranMidnight = Math.floor(Date.UTC(2026, 6, 28, 20, 30, 0) / 1000);
it('timestamp نیمه‌شبِ تهران همان روز را می‌دهد، نه روز قبل', () => {
expect(unixToIso(tehranMidnight)).toBe('2026-07-29');
});
it('لحظهٔ آخر شب به وقت تهران هنوز همان روز است', () => {
const lateNight = Math.floor(Date.UTC(2026, 6, 29, 20, 0, 0) / 1000); // ۲۳:۳۰ تهران
expect(unixToIso(lateNight)).toBe('2026-07-29');
});
it('مقدار خالی رشتهٔ تهی می‌دهد', () => {
expect(unixToIso(null)).toBe('');
expect(unixToIso(undefined)).toBe('');
});
it('todayIso همان تاریخ تهرانِ لحظهٔ جاری است', () => {
expect(todayIso()).toBe(toGregorianDate(new Date()));
expect(todayIso()).toMatch(/^\d{4}-\d{2}-\d{2}$/);
});
it('ساعت دیواری تهران با رقم لاتین و ۲۴ساعته برمی‌گردد', () => {
expect(toTehranClockTime(new Date(tehranMidnight * 1000))).toBe('00:00');
expect(toTehranClockTime(new Date(Date.UTC(2026, 6, 29, 10, 0, 0)))).toBe('13:30');
});
it('رفت‌وبرگشتِ tehranWallClockToUnix ↔ unixToIso روز را جابه‌جا نمی‌کند', () => {
const ts = tehranWallClockToUnix('2026-07-29', '00:00');
expect(ts).toBe(tehranMidnight);
expect(unixToIso(ts)).toBe('2026-07-29');
});
});
describe('maskMobile', () => {
it('شماره ۱۱ رقمی را ماسک می‌کند', () => {
expect(maskMobile('09123456789')).toBe('0912***789');