استاندارد زمانها
زمان روی شبکه چطور است؟
زمان روی wire همیشه رشتهٔ ISO است — نه epoch-millis عددی. پاسخهای sync زمان UTC برمیگردانند، مثل 2026-10-01T08:00:00.000Z. نمایش جلالی یا میلادی، فقط نمایش است و لحظهٔ ذخیرهشده را عوض نمیکند.
اعتبارسنجی ورودی هر رشتهٔ قابل parse با Date.parse را میپذیرد، اما ISO UTC بفرستید. تاریخ غیرقابل parse قبل از ذخیره رد میشود و محل رد شدن بستگی به مسیر دارد:
| مسیر | رفتار |
|---|---|
| push | خطای همان آیتم (invalid_item)؛ بقیهٔ آیتمها مستقل ادامه مییابند |
| batch گزارش خطا | 400 برای کل درخواست، بدون درج هیچ آیتم |
هیچکدام از این دو، خطای 500 عمومی نیست.
| فیلد sync ← ستون DB | مالکیت |
|---|---|
createdAt ← created | ورودی اختیاری، فقط هنگام ساخت مؤثر؛ ویرایش بعدی تغییرش نمیدهد |
updatedAt ← updated | سرور (trigger) هنگام هر نوشتن |
deleted | زمان حذف نرم یا null؛ با عملیات delete/restore تغییر میکند |
version | رشتهٔ دهدهی از دنبالهٔ سرور — نه timestamp و نه عدد JSON |
چرا ساعت یا روز جابهجا شد؟
وب زمان ISO را با new Date() میخواند، ساعت فرم را در منطقهٔ زمانی دستگاه کاربر تفسیر میکند و با toISOString() به UTC تبدیل میکند. مثلاً 08:00Z در تهران ساعت 11:30 است — این دو نمایشِ یک لحظهاند، نه دو زمان متفاوت.
برای عیبیابی، سه چیز را کنار هم بگذارید: رشتهٔ ISO دریافتی، منطقهٔ زمانی دستگاه و تبدیلِ فرم. در رشتهٔ ISO دست نبرید (حذف Z یا اضافهکردن دوبارهٔ offset، داده را خراب میکند). اگر ذخیرهٔ محلی شما epoch-millis است، تبدیل را فقط در مرز شبکه انجام دهید.
منطقهٔ زمانی و تمامروز
- DTO فعلی رویداد فیلد
timezoneندارد؛ ستون رزروشدهٔ schema هم تضمینی برای حفظ منطقهٔ IANA نیست. allDayخودش زمانها را جابهجا نمیکند؛ فقط نحوهٔ نمایش/تفسیر را علامت میزند.- رفتار فعلی فرم وب: شروع را
۰۰:۰۰از روزِ شروعِ انتخابی و پایا ن را23:59:00از همان روزِ پایانِ انتخابشده، در زمان محلی دستگاه میسازد. پایانِ فرم، نیمهشبِ انحصاریِ روز بعد نیست — وقتی محدودهٔ تمامروز واقعی را محاسبه میکنید، باید این را لحاظ کنید. - فیلتر بازه در وب، شرط
event.start < range.end && event.end > range.startرا میگذارد.
از این رفتارها، قرارداد RFC/iCal یا رفتار همهٔ کلاینتها را نتیجه نگیرید.
تازگی داده
از ساعت دستگاه برای تشخیص تازهبودن داده استفاده نکنید؛ معیار سروری version (برای ردیف) و cursor (برای پیشرفت pull) است — توضیح در همگامسازی. trigger بهروزرسانی updated فقط برای چهار موجودیت Calendar/Event/Task/Reminder است.
منابع: apps/api/prisma/schema.prisma؛ در وب src/components/calendar-app/EventModal.tsx و src/features/events/mappers.ts و local.ts.