Неверная дата в сафари

 alert(new Date('2010-11-29'));

chrome, ff не имеет проблем с этим, но сафари выкрикивает "недопустимая дата". Зачем?

edit: хорошо, согласно комментариям ниже, я использовал разбор строк и попробовал это:

alert(new Date('11-29-2010')); //doesn't work in safari
alert(new Date('29-11-2010')); //doesn't work in safari
alert(new Date('2010-29-11')); //doesn't work in safari

edit 22 марта 2018: похоже, что люди все еще приземляются здесь - сегодня я бы использовал moment или же date-fns и покончим с этим. Date-fns также очень безболезненный и легкий.

23 ответа

Решение

Шаблон yyyy-MM-dd не является официально поддерживаемым форматом для Date конструктор. Firefox, кажется, поддерживает это, но не рассчитывайте на то, что другие браузеры будут делать то же самое.

Вот некоторые из поддерживаемых строк, взятых с этого сайта:

  • ММ-дд-гггг
  • дд гггг / ММ /
  • ММ / дд / гггг
  • ММММ дд, гггг
  • МММ дд, гггг

DateJS кажется хорошей библиотекой для анализа нестандартных форматов дат.

Редактировать: только что проверил стандарт ECMA-262. Цитата из раздела 15.9.1.15:

Дата Время Формат строки

ECMAScript определяет формат обмена строк для даты и времени на основе упрощенного расширенного формата ISO 8601. Формат выглядит следующим образом: ГГГГ-ММ-ДДЧЧ: мм: сс.ссс Z Где следующие поля:

  • YYYY - десятичные цифры года в григорианском календаре.
  • "-" (гифон) появляется буквально дважды в строке.
  • MM - месяц года с 01 (январь) до 12 (декабрь).
  • ДД это день месяца с 01 по 31.
  • Буква "Т" появляется буквально в строке, чтобы указать начало элемента времени.
  • ЧЧ - количество полных часов, прошедших с полуночи в виде двух десятичных цифр.
  • ":" (двоеточие) появляется буквально дважды в строке.
  • мм - количество полных минут с начала часа в виде двух десятичных цифр.
  • ss - количество полных секунд с начала минуты в виде двух десятичных цифр.
  • "" (точка) появляется буквально в строке.
  • sss - это число полных миллисекунд с начала секунды в виде трех десятичных цифр. Оба "." и поле миллисекунд может быть опущено.
  • Z - это смещение часового пояса, указанное как "Z" (для UTC) или "+" или "-", за которым следует выражение времени чч: мм

Этот формат включает формы только для даты:

  • YYYY
  • YYYY-MM
  • YYYY-MM-DD

Он также включает в себя только временные формы с добавлением необязательного смещения часового пояса:

  • THH: мм
  • THH: мм: сс
  • THH: мм: СС.ссс

Также включены "дата-время", которые могут представлять собой любую комбинацию из вышеперечисленного.

Похоже, что YYYY-MM-DD включен в стандарт, но по некоторым причинам Safari его не поддерживает.

Обновление: после просмотра документации datejs и ее использования, ваша проблема должна быть решена с помощью следующего кода:

var myDate1 = Date.parseExact("29-11-2010", "dd-MM-yyyy");
var myDate2 = Date.parseExact("11-29-2010", "MM-dd-yyyy");
var myDate3 = Date.parseExact("2010-11-29", "yyyy-MM-dd");
var myDate4 = Date.parseExact("2010-29-11", "yyyy-dd-MM");

Для меня реализация новой библиотеки только потому, что Safari не может сделать это правильно, - это слишком много, и регулярное выражение является излишним. Вот кто такой:

console.log (new Date('2011-04-12'.replace(/-/g, "/")));

Я столкнулся с аналогичной проблемой. Date.Parse("DATESTRING") работал на Chrome (версия 59.0.3071.115), но не на Safari (версия 10.1.1 (11603.2.5))

Сафари:

Date.parse("2017-01-22 11:57:00")
NaN

Хром:

Date.parse("2017-01-22 11:57:00")
1485115020000

Решение, которое работало для меня, заключалось в замене пробела в dateString на "T". (пример: dateString.replace(/ /g,"T"))

Сафари:

Date.parse("2017-01-22T11:57:00")
1485086220000

Хром:

Date.parse("2017-01-22T11:57:00")
1485115020000

Обратите внимание, что ответ от браузера Safari на 8 часов (28800000 мс) меньше, чем ответ браузера Chrome, потому что Safari возвратил ответ в локальной TZ (что на 8 часов позже UTC)

Чтобы получить оба раза в одном и том же TZ

Сафари:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

Хром:

Date.parse("2017-01-22T11:57:00Z")
1485086220000

Я использую момент, чтобы решить проблему. Например

var startDate = moment('2015-07-06 08:00', 'YYYY-MM-DD HH:mm').toDate();

Чтобы решение работало в большинстве браузеров, вы должны создать объект date с этим форматом.

(year, month, date, hours, minutes, seconds, ms)

например:

dateObj = new Date(2014, 6, 25); //UTC time / Months are mapped from 0 to 11
alert(dateObj.getTime()); //gives back timestamp in ms

отлично работает с IE, FF, Chrome и Safari. Даже более старые версии.

IE Dev Center: объект Date (JavaScript)

Сеть разработчиков Mozilla: Дата

Преобразовать строку в дату от fromat (вы должны знать часовой пояс сервера)

new Date('2015-06-16 11:00:00'.replace(/\s+/g, 'T').concat('.000+08:00')).getTime()  

где +08:00 = часовой пояс с сервера

Для людей, использующих date-fnsмы можем parseISOдату и использовать ее для форматирования

Инвалид

      import _format from 'date-fns/format';

export function formatDate(date: string, format: string): string {
  return _format(new Date(date), format);
}

Эта функция в сафари бросает ошибку с Invalid date.

Решение
Чтобы исправить это, мы должны использовать:

      import _format from 'date-fns/format';
import _parseISO from 'date-fns/parseISO';

export function formatDate(date: string, format: string): string {
  return _format(_parseISO(date), format);
}

У меня была та же проблема. Затем я использовал момент. JS. Проблема исчезла.

При создании момента из строки мы сначала проверяем, соответствует ли строка известным форматам ISO 8601, а затем возвращаемся к новой дате (строка), если известный формат не найден.

Предупреждение. Браузерная поддержка для разбора строк противоречива. Поскольку нет спецификации, какие форматы должны поддерживаться, то, что работает в некоторых браузерах, не будет работать в других браузерах.

Для согласованного анализа результатов, отличных от строк ISO 8601, следует использовать String + Format.

например

var date= moment(String);

Хотя вы можете надеяться, что браузеры будут поддерживать ISO 8601 (или только его подмножества дат), это не так. Все браузеры, о которых я знаю (по крайней мере, в США / английском языке, которые я использую), могут анализировать ужасные США. MM/DD/YYYY формат.

Если у вас уже есть части даты, вы можете вместо этого попробовать использовать Date.UTC (). Если вы этого не сделаете, но вы должны использовать YYYY-MM-DD формат, я предлагаю использовать регулярное выражение, чтобы разобрать фрагменты, которые вы знаете, а затем передать их Date.UTC(),

Для меня проблема заключалась в том, что я забыл добавить 0перед однозначной цифрой месяца или дня в формате.
Что я разбирал: 2021-11-5
Что это должно быть: 2021-11-05

Итак, я написал небольшую утилиту, которая конвертирует YYYY-M-Dк YYYY-MM-DDто есть 2021-1-1к 2021-01-01:

      const date = "2021-1-1"
const YYYY = date.split("-")[0];

    //convert M->MM i.e. 2->02
    const MM =
      date.split("-")[1].length == 1
        ? "0" + date.split("-")[1]
        : date.split("-")[1];

    //convert D->DD i.e. 2->02
    const DD =
      date.split("-")[2].length == 1
        ? "0" + date.split("-")[2]
        : date.split("-")[2];

    // YYYY-MM-DD
    const properDateString = `${YYYY + "-" + MM + "-" + DD}`;

    const dateObj = new Date(properDateString);

Как насчет угона Date с фиксированной датой? Без зависимостей, min + gzip = 280 B

Я также сталкиваюсь с той же проблемой в браузере Safari

var date = new Date("2011-02-07");
console.log(date) // IE you get ‘NaN’ returned and in Safari you get ‘Invalid Date’

Вот решение:

var d = new Date(2011, 01, 07); // yyyy, mm-1, dd  
var d = new Date(2011, 01, 07, 11, 05, 00); // yyyy, mm-1, dd, hh, mm, ss  
var d = new Date("02/07/2011"); // "mm/dd/yyyy"  
var d = new Date("02/07/2011 11:05:00"); // "mm/dd/yyyy hh:mm:ss"  
var d = new Date(1297076700000); // milliseconds  
var d = new Date("Mon Feb 07 2011 11:05:00 GMT"); // ""Day Mon dd yyyy hh:mm:ss GMT/UTC 

Опоздал на вечеринку, но в нашем случае мы столкнулись с этой проблемой в Safari и iOS при использовании обратного тика ES6 вместо String() для ввода cast

Это давало ошибку "неверная дата"

const dateString = '2011-11-18';
const dateObj = new Date(`${dateString}`); 

Но это работает

const dateObj = new Date(String(dateString)); 

Лучший способ сделать это - использовать следующий формат:

new Date(year, month, day, hours, minutes, seconds, milliseconds)
var d = new Date(2018, 11, 24, 10, 33, 30, 0);

Это поддерживается во всех браузерах и не доставит вам никаких проблем. Обратите внимание, что месяцы написаны от 0 до 11.

Используйте приведенный ниже формат, он будет работать на всех браузерах

var year = 2016;
var month = 02;           // month varies from 0-11 (Jan-Dec)
var day = 23;

month = month<10?"0"+month:month;        // to ensure YYYY-MM-DD format
day = day<10?"0"+day:day;

dateObj = new Date(year+"-"+month+"-"+day);

alert(dateObj); 

// Ваш вывод будет выглядеть так: "Ср 23 марта 2016 00:00:00 GMT+0530 (IST)"

// Обратите внимание, что это будет в текущем часовом поясе, в данном случае, обозначенном IST, чтобы преобразовать в часовой пояс UTC, который вы можете включить

alert(dateObj.toUTCSting);

// Ваш вывод будет выглядеть так: "Вт, 22 марта 2016 г., 18:30:00 по Гринвичу"

Обратите внимание, что теперь dateObj показывает время в формате GMT, также обратите внимание, что дата и время были изменены соответственно.

Функция "toUTCSting" извлекает соответствующее время по гринвичскому меридиану. Это достигается путем установления разницы во времени между вашим текущим часовым поясом и часовым поясом Гринвичского меридиана.

В приведенном выше случае время до преобразования составляло 00:00 часов и минут 23 марта 2016 года. А после преобразования из GMT+0530 (IST) часов в GMT (в основном это вычитает 5,30 часов из данной временной метки в этом случай) время отражает 18.30 часов 22 марта 2016 года (ровно 5.30 часов после первого раза).

Далее для преобразования любого объекта даты в метку времени вы можете использовать

alert(dateObj.getTime());

// вывод будет выглядеть примерно так: "1458671400000"

Это даст вам уникальную метку времени

В моем случае это было не форматирование, а то, что в моей серверной модели Node.js я определял переменную базы данных как String вместо Date.

Моя внутренняя модель базы данных Node сказала:

      starttime:{
  type: String,
}

вместо правильного:

       starttime:{
    type: Date,
  }

В качестве аргумента new Date() просто напишите числа вместо строки.
И Safari, и Chrome понимают этот синтаксис.

      alert(new Date(2010, 29, 11));

Как ранее упоминалось @nizantz, использование Date.parse() не помогло мне в Safari. После небольшого исследования я узнал, что свойство lastDateModified для объекта File устарело и больше не поддерживается Safari. Использование свойства lastModified объекта File решило мои проблемы. Конечно, не нравится, когда плохая информация найдена в Интернете.

Спасибо всем, кто внес вклад в этот пост, который помог мне пойти по пути, который мне нужен, чтобы узнать о моей проблеме. Если бы не эта информация, я бы, наверное, не разобрался в своей основной проблеме. Может быть, это поможет кому-то еще в моей аналогичной ситуации.

Я решил эту проблему следующим образом:

старый код, с ошибкой:

moment(new Date(date)).format("DD/MM/YYYY [às] HH:mm")

новый код с решением:

moment(date, "YYYY-MM-DD HH:mm:ss").format("DD/MM/YYYY [às] HH:mm")

Используйте формат "мм / дд / гггг". Например:- новая дата ('02/28/2015'). Хорошо работает во всех браузерах.

Та же самая проблема, с которой сталкиваются в Safari, была решена путем вставки этого в веб-страницу

 <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"></script> 

Надеюсь, это будет работать и ваш случай тоже

Спасибо

Так не пойдет alert(new Date('2010-11-29')); у сафари есть какой-то странный / строгий способ обработки формата даты alert(new Date(String('2010-11-29'))); попробуйте вот так.

(Или же)

Однако использование Moment js решит проблему, после ios 14 сафари становится даже странным

Попробуйте это предупреждение (moment(String("2015-12-31 00:00:00")));

Момент JS

Это не лучшее решение, хотя я просто ловлю ошибку и отправляю текущую дату обратно. Я лично считаю, что не решаю проблемы Safari, если пользователи хотят использовать дерьмовый браузер, не соответствующий стандартам - им приходится жить с причудами.

function safeDate(dateString = "") {
  let date = new Date();
  try {
    if (Date.parse(dateString)) {
      date = new Date(Date.parse(dateString))
    }
  } catch (error) {
    // do nothing.
  }
  return date;
}

Я бы предложил, чтобы ваш бэкэнд отправлял даты ISO.

Другие вопросы по тегам