Недійсна дата в сафарі


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

chrome, ff не має з цим проблем, але сафарі кричить "недійсна дата". Чому?

редагувати: добре, згідно з коментарями нижче, я використав розбір рядків і спробував це:

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

правити 22 березня 2018 : Схоже , люди до цих пір посадка тут - Сьогодні, я хотів би використовувати momentабо date-fnsі зробити з неї. Date-fns також є безболісним і легким.


Тільки для інших, хто дивиться на ту ж проблему: я в кінцевому підсумку використовував DateJS, який вирішив мою проблему в цілому. Деталі див. У прийнятій відповіді.
Shrinath

2
використовувати moment.js для розбору часової позначки. Особливо при роботі з веб-платформами
Ming Yuen

1
Це старе питання. Станом на ECMAScript 2015, рядки, що містять лише дату ISO 8601, аналізуються як UTC. Однак, все ж можуть існувати старіші веб-переглядачі, які або взагалі не будуть їх розбирати, або вважатимуть їх локальними.
RobG

Відповіді:


167

Шаблон yyyy-MM-ddне є офіційно підтримуваним форматом для Dateконструктора. Firefox, здається, підтримує це, але не розраховуйте, що інші браузери роблять те саме.

Ось кілька підтримуваних рядків:

  • MM-dd-yyyy
  • рр. рр. / ММ / дд
  • MM / dd / yyyy
  • MMMM dd, yyyy
  • MMM dd, yyyy

DateJS здається гарною бібліотекою для розбору нестандартних форматів дати.

Редагувати : щойно перевірено стандарт ECMA-262 . Цитуючи з розділу 15.9.1.15:

Формат рядка часу часу

ECMAScript визначає формат обміну рядками для дат, заснований на спрощенні розширеного формату ISO 8601. Формат виглядає наступним чином: РРРР-ММ-DDTHH: мм: ss.sssZ Якщо поля такі:

  • РРРР - це десяткові цифри року за григоріанським календарем.
  • "-" (гіфон) з'являється буквально двічі в рядку.
  • MM - місяць року з 01 (січень) до 12 (грудень).
  • DD - день місяця з 01 по 31 рік.
  • "T" відображається буквально в рядку, щоб вказати на початок елемента часу.
  • HH - кількість повних годин, що пройшли з півночі у вигляді двох десяткових цифр.
  • ":" (двокрапка) відображається буквально двічі в рядку.
  • мм - кількість закінчених хвилин з початку години у вигляді двох десяткових цифр.
  • ss - кількість повних секунд з моменту початку хвилини у вигляді двох десяткових цифр.
  • "." (крапка) з'являється буквально в рядку.
  • sss - кількість повних мілісекунд з початку другої як три десяткових цифри. Обидва "." і поле мілісекунд може бути опущене.
  • Z - зсув часового поясу, вказаний як "Z" (за UTC) або "+" або "-" з подальшим часовим виразом hh: mm

Цей формат включає форми лише для дати:

  • РРРР
  • РРРР-ММ
  • РРРР-ММ-ДД

Він також включає форми, що містять лише час, з додатковим зміщенням часового поясу:

  • 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");

4
Формат ISO8601 використовується в 5-му випуску стандарту ECMAScript, і поки він не підтримується, найбезпечніший спосіб перейти до IMO, проаналізувати дату вручну :(
CMS

1
Це було дуже корисно чувак .. Дякую .. :) Нарешті я використала datejs для форматування.
Shrinath

для тих, хто в майбутньому, зауважте, що хоч datejs є фантастичним у більшості аспектів, він не вирішує всіх проблем із форматуванням дати, особливо із сафарі. це PITA, але найкраще робити це вручну, якщо у вас все ще є проблеми.
totalNotLizards

@darioo Отже, я спробував вашу відповідь так: "var start = Date.parseExact (мітка часу," РРРР-DD-MM HH: мм: SS ");" часова мітка - "2016-01-28 00:00:00". Однак тепер я отримую помилку, що "Date.parseExact не є функцією". Чи знаєте ви, що тут відбувається?
трок

5
Моя аналогічна проблема була викликана тим, що Safari не знав, як читати часовий пояс у форматі часового поясу RFC 822. Мені вдалося виправити це за допомогою формату ISO 8601. Якщо у вас є контроль над формою дати, я отримав це, працюючи з "yyyy-MM-dd'T'HH: mm: ss.ssssXXX", який створює, тобто. "2018-02-06T20: 00: 00.000 + 00: 00". З будь-якої причини Safari не може прочитати "2018-02-06T20: 00: 00.000 + 0000", помітьте відсутність двокрапки у форматі часового поясу.
Олмстов

224

Для мене реалізація нової бібліотеки лише тому, що Safari не вміє правильно це робити, це занадто багато, а регулярний вираз є надмірним. Ось онлінер :

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

Якщо отримання косою рисою була лише моєю проблемою, я б "прийняв" вашу відповідь (хоча це було моєю єдиною метою, коли я задав це запитання). Тепер, коли я знайшов dateJS, я впровадив формат MMM DD, YYYY для більш зручного користування !!!
Shrinath

13
Ця допомога на один рядок була ідеальною для моєї потреби! Дякую!
Кирило Н.

4
Це було досить просто і для мене. Не можу повірити, що Safari не подобається - але працює той самий формат із \\. Дякуємо @Elzo і дякуємо Shrinath за розміщення питання
Піт

1
Я думаю, що це найкраща відповідь, яку я, як правило, забуваю / - / g замість '-'
Jacek Pietal

12
оплески за невтілення бібліотеки.
Lharby

56

Я зіткнувся з подібним питанням. Date.Parse("DATESTRING")працював над Chrome (версія 59.0.3071.115), але не над Safari (версія 10.1.1 (11603.2.5))

Сафарі:

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

Chrome:

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

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

Сафарі:

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

Chrome:

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

Зауважте, що відповідь браузера Safari на 8 годин (28800000 мс) менше, ніж відповідь, відображена в браузері Chrome, оскільки Safari повернув відповідь у місцевому TZ (на 8 годин поза UTC)

Щоб отримати обидва рази в одному ТЗ

Сафарі:

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

Chrome:

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

Або якщо ви не хочете, щоб обидві дати були однаковими в Safari та Chrome, ви можете використовувати new Date(year, month, date, hours, minutes, seconds, milliseconds)конструктор. Проаналізуйте дату рядка до масиву його компонентів, щоб використовувати ці компоненти в конструкторі. @nizantz було б чудово, якби ти думаєш, що такий приклад можна було б додати до вашої відповіді.
h3dkandi

Не особливо корисно, оскільки ви отримуєте дату в UTC, а не за місцевим часом.
Jonas Äppelgran

1
Цей dateString.replace(/ /g,"T")чарівний рядок коду працював у мене. :)
Mazdak Shojaie

замінити (/ - / g, '/')
Джек Ху

11

Я використовую момент для вирішення проблеми. Наприклад

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

10

Щоб рішення працювало на більшості браузерів, вам слід створити об’єкт дати у такому форматі

(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: Об'єкт дати (JavaScript)

Мережа Mozilla Dev: дата


6

перетворити рядок у Date fromat (ви повинні знати часовий пояс сервера)

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

де +08: 00 = timeZone від сервера


Це не враховує DST. Зсув TZ може коливатися, і це залежить від самої дати (та часу).
коста

5

У мене був той самий випуск. Тоді я використав момент. Дж. Проблема зникла.

Створюючи момент з рядка, ми спочатку перевіряємо, чи відповідає рядок відомим форматам ISO 8601, а потім повертаємося до нової дати (рядка), якщо відомий формат не знайдено.

Попередження: Підтримка браузера для розбору рядків суперечлива. Оскільки немає специфікації, які формати слід підтримувати, те, що працює в деяких браузерах, не працюватиме в інших браузерах.

Для послідовного аналізу результатів будь-якого іншого, крім рядків ISO 8601, слід використовувати String + Format.

напр

var date= moment(String);

3

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

Якщо у вас вже є частини дати, ви можете замість цього спробувати скористатися Date.UTC () . Якщо ви цього не зробите, але ви повинні використовувати YYYY-MM-DDформат, я пропоную використовувати регулярний вираз, щоб проаналізувати відомі вам фрагменти, а потім передати їх Date.UTC().


Гадаю, синтаксичний аналіз - це шлях :(
Shrinath

1

Використовуйте формат нижче, він буде працювати на всіх браузерах

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 GMT"

Зауважте, що тепер dateObj показує час у форматі GMT, також врахуйте, що дата та час були змінені відповідно.

Функція "toUTCSting" отримує відповідний час на меридіані Грінвіча. Це досягається шляхом встановлення різниці в часі між вашим поточним часовим поясом до часового поясу Грінвічського меридіану.

У наведеному вище випадку час до конверсії становив 00:00 годин і хвилин 23 березня 2016 року. А після переходу з GMT + 0530 (IST) годин у GMT (в основному віднімається 5,30 годин від заданої часової позначки в цьому випадок) час відображається на 18 березня 22 березня 2016 року (приблизно на 5,30 годин після першого разу).

Далі конвертувати будь-який об’єкт дати у часові позначки, які ви можете використовувати

alert(dateObj.getTime());

// вихід буде виглядати щось подібне до цього "1458671400000"

Це дасть вам унікальну позначку часу



1

Найкращий спосіб зробити це за допомогою наступного формату:

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

Це підтримується у всіх браузерах і не матиме жодних проблем. Зверніть увагу, що місяці записуються від 0 до 11.


Добре працює в Safari та Chrome, але все ще має проблеми з Firefox. Safari: var date = нова дата (2018,06,08,19,17) Sun Jul 08 2018 19:17:00 GMT + 0800 (+08) Chrome: var date = нова дата (2018,06,08,19, 17) Sun Jul 08 2018 19:17:00 GMT + 0800 (Малайзійський час) Firefox: var date = нова дата (2018,06,08,19,17) Дата 2018-07-08T11: 17: 00.000Z
Biranchi

0

Та ж проблема, з якою стикається в Safari, була вирішена, вставивши її на веб-сторінку

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

Сподіваємось, це також спрацює і у вашій справі

Дякую


Як ви думаєте, чому це спрацює? Я переглянув сценарій і, здається, не перекриває методи в об'єкті Date. Я поїхав сюди: polyfill.io/v3/url-builder, і, здається, нічого про розбір дат.
коста

0

Як згадувалося раніше @nizantz, використання Date.parse () не працювало для мене в Safari. Після невеликих досліджень я дізнався, що властивість lastDateModified для об’єкта File застаріле і Safari більше не підтримується. Використання lastModified властивості об’єкта File вирішило мої проблеми. Звичайно, не люблю це, коли погана інформація знайдена в Інтернеті.

Дякую всім, хто долучився до цієї публікації, яка допомогла мені піти шляхом, необхідному мені, щоб дізнатися про свою проблему. Якби не ця інформація, я ніколи не зрозумів би свою проблему з коренем. Можливо, це допоможе комусь іншому в моїй подібній ситуації.


0

Я також стикаюся з тією ж проблемою у браузері 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 

0

Це не найкраще рішення, хоча я просто вловлюю помилку і повертаю назад поточну дату. Особисто мені здається, що не вирішувати проблеми Safari, якщо користувачі хочуть використовувати браузер, що не відповідає стандартам sh * t, - їм доведеться жити з химерністю.

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.


З усією повагою, якщо ви маєте на увазі, що користувачі повинні використовувати браузер, для якого ви написали код, це загалом виглядає погано. Це також залежить від наших випадків використання та цільової аудиторії - якщо веб-сайт буде створений для споживання масового ринку, ми, як мінімум, підтримуватимемо IE10. Я впевнений, що хтось із MS думав так само, коли розробляв / кодував для Internet Explorer. Всі ми знаємо, як зараз про це говорять.
Shrinath

-1

використовуйте формат 'mm / dd / yyyy'. Наприклад: - нова дата ('02 / 28/2015 '). Він добре працює у всіх браузерах.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.