date-fns возвращает неверную дату в сафари

Я использую date-fns для возврата некоторых значений, как показано ниже:

import { format, formatDistance } from "date-fns";

var date = new Date("2019-03-06 00:00:00");
console.log(format(new Date(date), "dd MMM, y"));

Он отлично работает в Chrome и возвращает We Mar, y

Но возвращает Invalid Date в Safari.

Я полагаю, это потому, что дата ("2019-03-06 00:00:00") не в формате ISO 8601. Но это формат, который я получаю от конечной точки. Есть ли возможность преобразовать это в правильный формат и заставить его работать в Safari?


person user1012181    schedule 12.04.2019    source источник
comment
Почему вы дважды анализируете дату?   -  person T.J. Crowder    schedule 12.04.2019
comment
Возможно: "2019-03-06 00:00:00".split(" ").join("T")   -  person epascarello    schedule 12.04.2019


Ответы (1)


Я вижу две проблемы:

  1. Вы полагаетесь на нестандартный формат ввода при первом анализе даты.

  2. Вы передаете Date в конструктор Date, который заставляет его преобразовать дату в строку, а затем проанализировать строку.

Я бы проанализировал его только один раз и использовал стандартную дату/время при первом вызове new Date:

import { format, formatDistance } from "date-fns";

var date = new Date("2019-03-06T00:00:00");
// Note -----------------------^
console.log(format(date, "dd MMM, y"));
// No `new Date`   ^

Обратите внимание, что ваша строка будет проанализирована как местное время (в механизмах JavaScript, соответствующих спецификациям¹), поскольку она включает часть строки, посвященную времени. К сожалению, это изменилось после того, как формат был добавлен в ES2015, обновлен в ES2016, но где он закончился:

Когда представление смещения в формате UTC отсутствует, формы, содержащие только дату, интерпретируются как время в формате UTC, а формы даты и времени интерпретируются как местное время.

Поскольку ваша строка не имеет смещения UTC (без Z или +00:00 или подобных) и имеет время, она анализируется по местному времени. (Опять же, на движках JavaScript, соответствующих спецификациям¹).

Я рекомендую либо не анализировать строки даты с помощью встроенного объекта Date, либо убедиться, что у вас всегда есть индикатор часового пояса в строке, если вы это делаете.


¹ RobG указал, что Safari анализирует new Date("2019-03-06T00:00:00") как UTC. К сожалению, это ошибка в JavaScriptCore, движке JavaScript от Apple. Это влияет не только на Safari, но и на Chrome на iOS (и, возможно, на любой другой браузер iOS; я тестировал Brave, Opera и Dolphin), поскольку Chrome должен использовать JavaScriptCore вместо своего обычного V8 на iOS, потому что приложения не могут выделять исполняемую память, поэтому механизмы JIT нельзя использовать на iOS. Но команда V8 сделала версию V8 только для интерпретатора, так что, возможно, Chrome (и Brave) на iOS будет обновлена, чтобы использовать это, если оно будет достаточно быстрым.

person T.J. Crowder    schedule 12.04.2019
comment
Есть ли способ преобразовать "2019-03-06 00:00:00" в "2019-03-06T00:00:00", поскольку я не контролирую то, что получаю от API? - person user1012181; 12.04.2019
comment
@ user1012181 - Замена строки: theDate = theDate.replace(/ /g, "T");. Вы захотите проверить, предназначено ли то, что предоставляет вам API, для UTC или местного времени. Если это UTC, добавьте Z в конце: theDate = theDate.replace(/ /g, "T") + "Z";. - person T.J. Crowder; 12.04.2019
comment
Спасибо, я проверю это - person user1012181; 12.04.2019
comment
… анализируется по местному времени.. Нет, синтаксический анализатор Safari не работает, new Date("2019-03-06T00:00:00") анализируется как UTC. :-( - person RobG; 12.04.2019
comment
@RobG - (в браузерах, соответствующих спецификациям) :-) (Но я вижу, что у меня нет этого в обоих местах.) Я удивлен, что Safari все еще на расхождение со спецификацией, однако, тьфу. Вот почему я не анализирую даты как строки без часового пояса. - person T.J. Crowder; 13.04.2019
comment
@RobG - Тьфу, это еще хуже: это не Safari как таковое (конечно), это JavaScriptCore, поэтому он влияет на Safari, а также на Chrome на iOS (поскольку Chrome должен использовать АО на iOS, потому что приложения не могут выделять исполняемую память, но в какой-то момент они могут использовать только интерпретаторский режим в V8. ). действительно раздражает то, что формат, который спецификация не определяет (mm/dd/yyyy HH:MM:SS), надежно анализируется как местное время в разных движках (и локалях, несмотря на то, что он специфичен для США): jsfiddle.net/tjcrowder/ojmh3fsv/2 Вздох - person T.J. Crowder; 13.04.2019
comment
Удивительно, но я не смог найти для него отчет об ошибке, поэтому добавил его. - person T.J. Crowder; 13.04.2019
comment
Система сообщений об ошибках Safari довольно удручающая. Я сообщил о некоторых ошибках несколько лет назад, насколько я знаю, они не исправлены. По состоянию на ECMAScript 2015< /a>, при передаче объекта Date конструктор больше не выполняет операцию date -> string -> date, он просто принимает значение времени. :-) Я все еще люблю использовать new Date(+date). - person RobG; 14.04.2019