#javascript #react-native #timezone #date-fns
#javascript #react-native #Часовой пояс #дата-fns
Вопрос:
У меня проблема с отображением одной и той же даты во всех часовых поясах. Вводимые пользователем данные, например, 01-01-2002, и я сохраняю их как дату с Eureope/Berlin
часовым parseFromTimeZone(String(birthDate), { timeZone: 'Europe/Berlin' })
поясом, а результатом parseFromTimeZone
является эта строка '2001-12-31T23:00:00.000Z'
. Строковая дата считается с часовым поясом в Берлине, поэтому она сдвинута на один час.
И мне нужно получить от '2001-12-31T23:00:00.000Z'
этого 01-01-2002
во всех часовых поясах.
Я использую formatISO(new Date(date), { representation: 'date' }))
это 01-01-2002
, когда мой часовой пояс равен Europe/Prague
или Europe/Berlin
но когда я меняю часовой пояс на America/Tijuana
then formatISO
возвращает 2001-12-31
, и это неправильно, мне нужно иметь ту же дату, Europe/Berlin
что и всегда! Bud для Asia/Tokyo
этой функции возвращает 01-01-2002
правильное значение …
Какие-нибудь идеи? Я перепробовал много решений, но ни одно из них не работает для всех часовых поясов…
Я использую "date-fns": "^2.15.0"
, "date-fns-timezone": "^0.1.4"
Ответ №1:
Попробуйте использовать эту функцию с датой ISO_8601, затем измените часовой пояс в настройках вашего компьютера и повторите попытку с новым часовым поясом. Он должен печатать одну и ту же дату на вашей веб-странице для обоих часовых поясов.
getDateFromISO(iso_string: string): string | Date {
if (!iso_string)
return null;
const isIsoDate = /d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z/.test(iso_string); // check if string is in format 2022-01-01T00:00:00.000Z
const isDateTimeWithoutZone = /d{4}-d{2}-d{2}Td{2}:d{2}:d{2}/.test(iso_string); // check if string is in format 2022-01-01T00:00:00
const isDateYMD = /d{4}-d{2}-d{2}/.test(iso_string); // check if string is in format 2022-01-01
if (!isIsoDate amp;amp; isDateTimeWithoutZone)
iso_string = '.000Z';
else if (!isIsoDate amp;amp; isDateYMD)
iso_string = 'T00:00:00.000Z';
else if (isIsoDate)
iso_string = iso_string;
else
return iso_string;
const dateFromServer = new Date(iso_string);
const localOffset = new Date().getTimezoneOffset(); // in minutes
const localOffsetMillis = 60 * 1000 * localOffset;
const localDate = new Date(dateFromServer.getTime() localOffsetMillis);
return localDate;
}
Ответ №2:
Date
Объект, несмотря на его имя, не представляет «дату». Он представляет временную метку. Все, что он хранит внутри, — это количество миллисекунд, прошедших с эпохи Unix (которая основана на UTC). Он выводит значения, основанные либо на UTC, либо на местном часовом поясе компьютера, на котором он запущен, в зависимости от вызываемой функции.
Таким образом, если вы создаете Date
объект из значения только для даты, вы действительно берете «время в полночь» из этого часового пояса и настраиваете его на UTC. Это демонстрируется вашим примером 2002-01-01
in Europe/Berlin
. Вы рассматриваете это как 2002-01-01T00:00:00.000 01:00
, который действительно имеет эквивалент UTC 2001-12-31T23:00:00.000Z
и, следовательно, не содержит те же элементы года, месяца и дня, что и предполагаемый часовой пояс.
На самом деле у вас есть только два варианта обработки значений только для даты, если вы хотите предотвратить их смещение:
-
Ваш первый вариант — использовать
Date
объект, но обрабатывать входные данные как UTC и использовать только функции на основе UTC. Например:var dt = new Date(Date.UTC(2002, 0, 1)); // "2002-01-01T00:00:00.000Z" var y = dt.getUTCFullYear(); // 2002 var m = dt.getUTCMonth() 1; // 1 var d = dt.getUTCDate(); // 1 var dtString = d.toISOString().substring(0, 10) // "2002-01-01"
-
Если вам нужно проанализировать строку даты, имейте в виду, что текущая спецификация ECMAScript обрабатывает значения только для даты как UTC (что вам и нужно), но в прошлом такое поведение не было определено. Таким образом, некоторые браузеры могут создавать результат по местному времени из
new Date('2002-01-01')
. Возможно, вы захотите явно добавить время иZ
, например,new Date('2002-01-01' 'T00:00:00.000Z')
на всякий случай. -
Если вы собираетесь использовать date-fns, будьте осторожны — функции
parseISO
иformatISO
используют местное время, а не UTC.
-
-
Второй вариант — не использовать
Date
объект. Сохраняйте даты в их строковой форме (в формате ISO 8601 гггг-мм-дд) или храните их в другом объекте либо вашей собственной конструкции, либо из библиотеки.
Временное предложение ECMAScript TC39 предназначено для устранения таких недостатков в JavaScript. В частности, Temporal.Date
объект (предварительное имя) можно будет использовать для значений только для даты без проблем со сдвигом, с которыми столкнулись вы и многие другие. В настоящее время предложение находится на стадии 2 процесса ECMAScript, поэтому сегодня оно недоступно для использования, но эта проблема будет решена в конечном итоге!