fix: stop birth dates from saving one day early in Tehran time

This commit is contained in:
2026-10-20 15:20:47 +03:30
parent 9a86f63f48
commit 9127fa334b
3 changed files with 28 additions and 5 deletions
+25
View File
@@ -170,9 +170,34 @@ export function parseAmount(raw?: string): number | null {
}
/** تاریخ تولد: سال زیر ۱۷۰۰ شمسی است، سال ۱۷۰۰ به بعد میلادی. ظهر UTC تا روز جابه‌جا نشود. */
/** «۲۰۲۴-۰۵-۰۱T۱۹:۳۰:۰۰Z» و مشابه: لحظهٔ دقیق با منطقهٔ زمانی */
const ZONED_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})$/i;
function tehranCalendarDay(d: Date): { y: number; m: number; d: number } {
const [y, m, day] = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Tehran',
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.format(d)
.split('-')
.map(Number);
return { y, m, d: day };
}
export function parseBirthDate(raw?: string | null): Date | null {
const text = toAsciiDigits(String(raw ?? '')).trim();
if (!text || text === '-' || text === '0' || text === '0000-00-00') return null;
// تاریخ تولد فقط «روز» است. لحظهٔ UTC (مثلاً نیمه‌شب تهران که به روز قبلِ UTC می‌افتد)
// باید با تقویم تهران به روز تبدیل شود، نه با بریدن بخش تاریخِ UTC.
if (ZONED_TIMESTAMP.test(text)) {
const instant = new Date(text);
if (!Number.isNaN(instant.getTime())) {
const day = tehranCalendarDay(instant);
return new Date(Date.UTC(day.y, day.m - 1, day.d, 12, 0, 0));
}
}
const datePart = text.split(/[T\s]/)[0] ?? text;
const match = /^(\d{3,4})[\/\-.](\d{1,2})[\/\-.](\d{1,2})$/.exec(datePart);
if (!match) {
+1 -3
View File
@@ -206,9 +206,7 @@ async function saveEdit() {
region: editForm.value.region.trim() || null,
source: editForm.value.source.trim() || null,
instagram: editForm.value.instagram.trim() || null,
birthDate: editForm.value.birthDate
? (parseLocalInput(editForm.value.birthDate)?.toISOString() ?? null)
: null,
birthDate: editForm.value.birthDate || null,
trade: editForm.value.trade.trim() || null,
notes: editForm.value.notes.trim() || null,
});
+2 -2
View File
@@ -36,7 +36,7 @@ import {
import { api } from '@/lib/api';
import type { CompanyDto, CreatePersonRequest, PersonDto, PersonMood } from '@mento/shared';
import { PERSON_MOOD_LABELS, PERSON_MOODS } from '@/lib/person-mood';
import { formatLocalDateInput, parseLocalInput, toFaDigits } from '@/lib/jalali';
import { formatLocalDateInput, toFaDigits } from '@/lib/jalali';
import JalaliDateInput from '@/components/JalaliDateInput.vue';
import {
filterPhoneContacts,
@@ -327,7 +327,7 @@ function payload(): CreatePersonRequest {
position: position.value || undefined,
website: website.value || undefined,
instagram: instagram.value || undefined,
birthDate: birthDate.value ? parseLocalInput(birthDate.value)?.toISOString() ?? null : null,
birthDate: birthDate.value || null,
referrer: referrer.value || undefined,
addresses: addresses.value.map((a) => a.trim()).filter(Boolean),
notes: notes.value || undefined,