pcp-tgu-ops-ui: единый UTC во времени; дефолтный диапазон Планы

Время бэка (naive LocalDateTime и OffsetDateTime) разбиралось через
new Date(string)/Date.parse, из-за чего naive-строки трактовались как
локальное время браузера: вкладки расходились по времени, а путь создания
заявки сдвигал введённое время на офсет. Ввёл единую точку utils/utcTime
(parseUtc/formatUtc*/toUtcInputValue/toUtcIso) и перевёл на неё вкладки
«Планы», «Заявки», «Карта 2D» — чтение, пикеры диапазона, создание заявки.

Плюс на вкладке «Планы» график по умолчанию открывается на интервал
сейчас−30 мин … сейчас+3 дня.

docs/tasks/TASK_datetime-utc-consistency.md — ТЗ на сверку всей группы
сервисов pcp на единообразие времени.
This commit is contained in:
Дмитрий Соловьев
2026-06-02 16:53:48 +03:00
parent faf264e416
commit fb0332a030
12 changed files with 304 additions and 73 deletions
@@ -0,0 +1,51 @@
/**
* Единый разбор и форматирование времени в UTC.
*
* Бэкенд (Kotlin `LocalDateTime`) отдаёт время как ISO-строку без зоны
* (например `"2026-05-29T01:00:00"`) и по соглашению системы это UTC.
* Конструктор `Date`/`Date.parse` трактует такую строку как локальное время
* браузера, поэтому naive-строки нужно парсить явно как UTC, а отображать —
* с `timeZone: "UTC"`. Весь интерфейс ТГУ работает в UTC.
*/
/** Разбирает ISO-строку как UTC: если зоны нет — добавляет `Z`. */
export function parseUtc(value: string): number {
const hasZone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(value);
return Date.parse(hasZone ? value : `${value}Z`);
}
/** Дата-время в UTC, формат ru-RU. */
export function formatUtcDateTime(ms: number): string {
return new Date(ms).toLocaleString("ru-RU", {
timeZone: "UTC",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
});
}
/** Дата (дд.мм) в UTC. */
export function formatUtcDate(ms: number): string {
return new Date(ms).toLocaleDateString("ru-RU", { timeZone: "UTC", day: "2-digit", month: "2-digit" });
}
/** Время (чч:мм) в UTC. */
export function formatUtcTime(ms: number): string {
return new Date(ms).toLocaleTimeString("ru-RU", { timeZone: "UTC", hour: "2-digit", minute: "2-digit" });
}
/** Значение для `<input type="datetime-local">` в UTC (`YYYY-MM-DDTHH:mm`). */
export function toUtcInputValue(ms: number): string {
return new Date(ms).toISOString().slice(0, 16);
}
/**
* Naive-строку (из `datetime-local`) трактует как UTC и возвращает ISO с `Z`.
* Для бэкендов с `OffsetDateTime` на границе API (напр. pcp-request-service):
* пользователь вводит время по UTC, отправляем его же как UTC-смещение.
*/
export function toUtcIso(value: string): string {
return new Date(parseUtc(value)).toISOString();
}