Недействительная дата в реале Native - Дата JavaScript [duplicate]

Используя jQuery, scrollTop используется для установки вертикального положения scollbar для любого заданного элемента. есть также jquery scrollTo plugin , используемый для прокрутки с анимацией и различными опциями ( demos )

var myDiv = $("#div_id").get(0);
myDiv.scrollTop = myDiv.scrollHeight;

, если вы хотите использовать метод анимации jQuery для добавления анимации при прокрутке вниз, проверьте следующий фрагмент:

var myDiv = $("#div_id").get(0);
myDiv.animate({
    scrollTop: myDiv.scrollHeight
  }, 500);

288
задан RobG 28 March 2016 в 12:03
поделиться

11 ответов

До появления спецификации 5-го издания метод Date.parse был полностью зависимым от реализации (new Date(string) эквивалентен Date.parse(string) кроме последнего возвращает число, а не Date). В спецификации 5-го издания было добавлено требование о поддержке упрощенного (и немного неправильного) ISO-8601 , но кроме этого было требование no для того, что Date.parse / new Date(string) должны принять иное, чем то, что они должны были принять любой вывод Date # toString (не сказав, что это было).

Как и в ECMAScript 2017 (издание 8), реализации необходимо было проанализировать их вывод для Дата # toString и Дата # toUTCString , но формат этих строк не был указан.

Начиная с ECMAScript 2019 (версия 9) формат для Дата # toString и Дата # toUTCString указана как (соответственно):

  1. ddd MMM DD YYYY HH: mm: ss ZZ [(имя часового пояса)] например Вт 10 июля 2018 18:39:58 GMT + 0530 (IST)
  2. ddd, DD MMM YYYY HH: mm: ss Ze.g. Вт 10 июл 2018 13:09:58 GMT

предоставление еще 2 форматов, которые Date.parse должны корректно анализировать в новых реализациях (отмечая, что поддержка не является вездесущей и несовместимые реализации будут оставаться в использовании в течение некоторого времени).

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

// parse a date in yyyy-mm-dd format
function parseDate(input) {
  var parts = input.split('-');
  // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}
401
ответ дан RobG 19 August 2018 в 16:48
поделиться
  • 1
    Отлично, я должен был использовать это, поскольку Date.parse не вел себя с форматами даты в Великобритании по какой-то причине, я не мог работать – Ben 23 July 2012 в 11:59
  • 2
    Как насчет временных частей? – B T 30 November 2012 в 02:13
  • 3
    Временные части документированы в коде @CMS. Я использовал этот код с форматом даты «2012-01-31 12: 00: 00» return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]); Отлично работает, спасибо! – Richard Rout 13 February 2013 в 22:57
  • 4
    @RoyiNamir, это означает, что результаты зависят от того, какой веб-браузер (или другая реализация JavaScript) запускает ваш код. – Samuel Edwin Ward 29 March 2013 в 16:58
  • 5
    У меня также возникла проблема с новой Date (string) в разных браузерах, которые ведут себя по-другому. Это даже не вопрос о том, что он разбивается на старые версии IE, а разные браузеры просто несовместимы. Не используйте Date.parse или новую дату (строку). – Hoffmann 25 June 2013 в 17:20

Есть какой-то метод безумия. Как правило, если браузер может интерпретировать дату как ISO-8601, он будет. «2005-07-08» попадает в этот лагерь, и поэтому он анализируется как UTC. «8 июля 2005» не может, и поэтому он анализируется по местному времени.

Подробнее см. JavaScript и даты, What Mess! .

70
ответ дан Brad Koch 19 August 2018 в 16:48
поделиться
  • 1
    Следует отметить, что "2005-07-08" не обрабатывается в соответствии с ISO 8601. Если бы это было так, это рассматривалось бы как локальное, а не UTC. Как браузер обрабатывает "8 июля 2005 г." полностью зависит от реализации и всегда был, поэтому локальный, UTC и «Недействительная дата»; все являются совместимыми результатами. ;-) – RobG 22 February 2016 в 08:32

Хотя CMS верна , что передача строк в метод разбора, как правило, небезопасна, новая спецификация ECMA-262 5th Edition (aka ES5) в разделе 15.9.4.2 предлагает что Date.parse() фактически должны обрабатывать даты в формате ISO. В старой спецификации не было такого требования. Конечно, старые браузеры и некоторые современные браузеры по-прежнему не обеспечивают эту функциональность ES5.

Ваш второй пример не является неправильным. Это указано в UTC, что подразумевается Date.prototype.toISOString(), но отображается в вашем локальном часовом поясе.

4
ответ дан Community 19 August 2018 в 16:48
поделиться
  • 1
    И синтаксический анализ строк даты был снова изменен в ECMAScript 2015, так что «2005-07-08» является локальным, а не UTC. BTW, ES5 не был стандартом до июня 2011 года (и в настоящее время ECMAScript 2015). ;-) – RobG 23 September 2015 в 07:23
  • 2
    Чтобы просто сбить с толку, TC39 решил октябрь (всего через месяц после моего предыдущего сообщения), что «2005-07-08 & quot; должен быть UTC , однако "2005-07-08T00: 00: 00" должны быть локальными. Оба являются стандартами ISO 8601, оба без часового пояса, но обрабатываются по-разному. Идите фигуру. – RobG 22 February 2016 в 08:29

Оба правильные, но они интерпретируются как даты с двумя разными часовыми поясами. Итак, вы сравнили яблоки и апельсины:

// local dates
new Date("Jul 8, 2005").toISOString()            // "2005-07-08T07:00:00.000Z"
new Date("2005-07-08T00:00-07:00").toISOString() // "2005-07-08T07:00:00.000Z"
// UTC dates
new Date("Jul 8, 2005 UTC").toISOString()        // "2005-07-08T00:00:00.000Z"
new Date("2005-07-08").toISOString()             // "2005-07-08T00:00:00.000Z"

Я удалил вызов Date.parse(), так как он автоматически используется для строкового аргумента. Я также сравнивал даты с использованием формата ISO8601 , чтобы вы могли визуально сравнивать даты между вашими местными датами и датами UTC. Время разговора составляет 7 часов, что является разницей в часовом поясе и почему ваши тесты показывают две разные даты.

Другим способом создания этих же локальных / UTC-дат будет:

new Date(2005, 7-1, 8)           // "2005-07-08T07:00:00.000Z"
new Date(Date.UTC(2005, 7-1, 8)) // "2005-07-08T00:00:00.000Z"

Но я по-прежнему настоятельно рекомендую Moment.js , который как простой, но мощный :

// parse string
moment("2005-07-08").format()       // "2005-07-08T00:00:00+02:00"
moment.utc("2005-07-08").format()   // "2005-07-08T00:00:00Z"
// year, month, day, etc.
moment([2005, 7-1, 8]).format()     // "2005-07-08T00:00:00+02:00"
moment.utc([2005, 7-1, 8]).format() // "2005-07-08T00:00:00Z"
1
ответ дан DJDaveMark 19 August 2018 в 16:48
поделиться

Во время недавнего опыта написания JS-переводчика я много боролся с внутренней работой дат ECMA / JS. Итак, я полагаю, что я брошу свои 2 цента здесь. Надеемся, что совместное использование этого материала поможет другим с любыми вопросами о различиях между браузерами в том, как они обрабатывают даты.

Сторона входа

Все реализации хранят свои значения даты внутри себя как 64-разрядные номера которые представляют собой миллисекунды с 01.01.1970 UTC (GMT - это то же самое, что и UTC). Даты, возникающие после 1/1/1970 00:00:00, являются положительными числами, а даты предшествуют отрицательным.

Поэтому следующий код дает точный результат во всех браузерах.

Date.parse('1/1/1970');

В моей временной зоне ( EST), результат составляет 18000000, потому что это то, сколько мс составляет 5 часов (это всего 4 часа в летние месяцы). Значение будет отличаться в разных часовых поясах. Все основные браузеры делают это одинаково.

Вот и все. Несмотря на то, что в форматах входных строк есть некоторые отклонения, которые основные браузеры будут анализировать как даты, они по существу интерпретируют их одинаково с часовыми поясами и летней экономией. Один из них - формат ISO 8601. Это единственный формат, специально описанный в спецификации ECMA-262 v.5. Для всех других строковых форматов интерпретация зависит от реализации. По иронии судьбы, это формат, в котором браузеры могут отличаться. Ниже приведен сравнительный вывод Chrome vs Firefox для 1/1/1970 на моей машине с использованием формата строки ISO 8601.

Date.parse('1970-01-01T00:00:00Z');       // Chrome: 0         FF: 0
Date.parse('1970-01-01T00:00:00-0500');   // Chrome: 18000000  FF: 18000000
Date.parse('1970-01-01T00:00:00');        // Chrome: 0         FF: 18000000
  • Спецификатор «Z» указывает, что вход уже находится в UTC и не требует смещения перед хранением.
  • Спецификатор «-0500» указывает, что вход находится в GMT-05: 00, поэтому оба браузера интерпретируют ввод как находящийся в моем локальном часовом поясе. Это означает, что значение будет преобразовано в UTC перед сохранением. В моем случае это означает добавление 18000000 мс к внутреннему значению даты, что требует сдвига -18000000 мс (-05: 00), чтобы вернуть меня в локальное время.
  • Однако, когда спецификатор отсутствует, FF обрабатывает ввод в качестве локального времени, в то время как Chrome рассматривает его как время UTC. Для меня это создает 5-часовую разницу в сохраненной стоимости, что является проблематичным. В моей реализации я оказался на стороне FF здесь, потому что мне нравится вывод toString для соответствия моему входному значению, если я не укажу альтернативный часовой пояс, который я никогда не делаю. Отсутствие спецификатора должно предполагать местный вход времени.

Но здесь ситуация ухудшается, FF обрабатывает краткую форму формата ISO 8601 («YYYY -MM-DD ") по-разному, чем обрабатывает длинную форму (« YYYY-MM-DDTHH: mm: ss: sssZ ») без каких-либо логических причин. Вот результат из FF с длинными и короткими форматами даты ISO без спецификатора часового пояса.

Date.parse('1970-01-01T00:00:00');       // 18000000
Date.parse('1970-01-01');                // 0

Итак, чтобы ответить на вопрос первоначального вопросчика, "YYYY-MM-DD" - это короткая форма ISO 8601 "YYYY-MM-DDTHH:mm:ss:sssZ". Таким образом, это интерпретируется как время UTC, тогда как другое интерпретируется как локальное. Вот почему,

Это не jive:

console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08")).toString());

Это делает:

console.log(new Date(Date.parse("Jul 8, 2005")).toString());
console.log(new Date(Date.parse("2005-07-08T00:00:00")).toString());

Нижняя строка - это строка синтаксического анализа. Единственная строка ISO 8601, которую вы можете безопасно анализировать в браузерах, - это длинная форма. И ВСЕГДА используйте спецификатор «Z». Если вы это сделаете, вы можете спокойно перемещаться между локальным и UTC.

Это работает в браузерах (после IE9):

console.log(new Date(Date.parse("2005-07-08T00:00:00Z")).toString());

К счастью, большинство современных браузеров другие форматы ввода одинаково, включая наиболее часто используемые форматы «1/1/1970» и «1/1/1970 00:00:00 AM». Все следующие форматы (и другие) рассматриваются как локальный ввод времени во всех браузерах и конвертируются в UTC перед хранением. Таким образом, они совместимы с кросс-браузером. Выходной код этого кода во всех браузерах в моем часовом поясе одинаковый.

console.log(Date.parse("1/1/1970"));
console.log(Date.parse("1/1/1970 12:00:00 AM"));
console.log(Date.parse("Thu Jan 01 1970"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00"));
console.log(Date.parse("Thu Jan 01 1970 00:00:00 GMT-0500"));

Сторона выхода

. На стороне вывода все браузеры переводили часовые пояса одинаково, но они обрабатывать строковые форматы по-разному. Вот функции toString и то, что они выводят. Обратите внимание на то, что функции toUTCString и toISOString выводят на моей машине 5:00 AM.

Конвертирует с UTC в локальное время перед печатью

 - toString
 - toDateString
 - toTimeString
 - toLocaleString
 - toLocaleDateString
 - toLocaleTimeString

Прямая печать сохраненного времени UTC

 - toUTCString
 - toISOString 

In Chrome
toString            Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString        Thu Jan 01 1970
toTimeString        00:00:00 GMT-05:00 (Eastern Standard Time)
toLocaleString      1/1/1970 12:00:00 AM
toLocaleDateString  1/1/1970
toLocaleTimeString  00:00:00 AM

toUTCString         Thu, 01 Jan 1970 05:00:00 GMT
toISOString         1970-01-01T05:00:00.000Z

In Firefox
toString            Thu Jan 01 1970 00:00:00 GMT-05:00 (Eastern Standard Time)
toDateString        Thu Jan 01 1970
toTimeString        00:00:00 GMT-0500 (Eastern Standard Time)
toLocaleString      Thursday, January 01, 1970 12:00:00 AM
toLocaleDateString  Thursday, January 01, 1970
toLocaleTimeString  12:00:00 AM

toUTCString         Thu, 01 Jan 1970 05:00:00 GMT
toISOString         1970-01-01T05:00:00.000Z

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

Код new Date('12/4/2013').toString() проходит через следующее внутреннее псевдопреобразование:

  "12/4/2013" -> toUCT -> [storage] -> toLocal -> print "12/4/2013"

Надеюсь, этот ответ был полезен.

176
ответ дан drankin2112 19 August 2018 в 16:48
поделиться
  • 1
    Во-первых, это фантастическая рецензия. Однако я хотел указать на зависимость. Что касается спецификаторов часового пояса, вы заявили: «Отсутствие спецификатора должно предполагать местный ввод времени». К счастью, стандарт ECMA-262 устраняет любую необходимость. Он указывает : «Значение отсутствующего смещения временной зоны равно« Z ». Таким образом, строка даты / времени без указанного часового пояса считается UTC, а не местным временем. Конечно, как и в случае со многими вещами JavaScript, между реализациями мало что согласуется. – Daniel 4 April 2014 в 14:50
  • 2
    ... включая наиболее часто используемые форматы «1/1/1970» и «1/1/1970 00:00:00 AM». - наиболее часто используемый , где ? Это, конечно, не в моей стране. – ulidtko 15 April 2014 в 12:59
  • 3
    @ulidtko - Извините, я в США. Вау ... ты прямо в Киеве. Я надеюсь, что вы и ваша семья останетесь в безопасности и что там скоро стабилизируются. Позаботьтесь о себе и удачи всем. – drankin2112 15 April 2014 в 17:14
  • 4
    Просто заметьте здесь. Похоже, что это не работает для браузеров Safari (например, iOS или OSX). Это или у меня другая проблема. – keyneom 24 April 2014 в 23:59
  • 5
    Даниэль, к счастью, авторы ECMAScript зафиксировали свою ошибку в отношении отсутствующей временной зоны для представления даты и времени. Теперь строки даты и времени без часового пояса используют смещение часового пояса хоста (т. Е. «Локальное»). Смутно, что только даты ISO 8601 только формы являются обработаны как UTC (хотя это не особенно ясно из спецификации), тогда как ISO 8601 рассматривает их как локальные, поэтому они не исправили все. – RobG 29 January 2017 в 00:37

Согласно http://blog.dygraphs.com/2012/03/javascript-and-dates-what-mess.html формат «yyyy / mm / dd» решает обычные проблемы , Он говорит: «Придерживайтесь« YYYY / MM / DD »для строк даты, когда это возможно. Это универсально поддерживается и недвусмысленно. В этом формате все времена являются локальными». Я установил тесты: http://jsfiddle.net/jlanus/ND2Qg/432/ Этот формат: + избегает двусмысленности порядка дня и месяца, используя порядок ymd и 4-значный год + избегает UTC против локальной проблемы, не соответствующей формату ISO, с помощью косой черты + danvk, dygraphs , говорит, что этот формат хорош во всех браузерах.

5
ответ дан Juan Lanus 19 August 2018 в 16:48
поделиться
  • 1
    Вы можете увидеть ответ автора . – Brad Koch 24 October 2012 в 19:01
  • 2
    Я бы сказал, что решение с примером в jsFiddle работает достаточно хорошо, если вы используете jQuery, поскольку он использует парсер datepicker. В моем случае проблема связана с jqGrid, но обнаружил, что у нее есть свой метод parseDate. Но в любом случае этот пример помог мне, давая мне идею, так что +1 за это, спасибо. – Vasil Popov 14 March 2013 в 13:29
  • 3
    Эта статья о dygraphs неверна, и первый пример на странице ясно иллюстрирует, почему использование косых черт вместо дефиса - действительно плохой совет. В то время, когда статья была написана с использованием «2012/03/13», привел к тому, что браузер анализировал его как локальную дату вместо UTC. Спецификация ECMAScript определяет явную поддержку для использования «YYYY-MM-DD». (ISO8601), поэтому всегда используйте дефисы. Следует отметить, что в то время, когда я пишу этот комментарий, Chrome был исправлен для обработки косой черты как UTC. – Lachlan Hunt 10 March 2018 в 03:01

Ниже приведен короткий гибкий фрагмент, который преобразует строку datetime в безопасном для кросс-браузера стиле, как nicel, подробно описанный @ drankin2112.

var inputTimestamp = "2014-04-29 13:00:15"; //example

var partsTimestamp = inputTimestamp.split(/[ \/:-]/g);
if(partsTimestamp.length < 6) {
    partsTimestamp = partsTimestamp.concat(['00', '00', '00'].slice(0, 6 - partsTimestamp.length));
}
//if your string-format is something like '7/02/2014'...
//use: var tstring = partsTimestamp.slice(0, 3).reverse().join('-');
var tstring = partsTimestamp.slice(0, 3).join('-');
tstring += 'T' + partsTimestamp.slice(3).join(':') + 'Z'; //configure as needed
var timestamp = Date.parse(tstring);

Ваш браузер должен предоставить тот же результат временной метки, что и Date.parse с:

(new Date(tstring)).getTime()
2
ответ дан Lorenz Lo Sauer 19 August 2018 в 16:48
поделиться
  • 1
    Я бы предложил добавить T в регулярное выражение, чтобы уловить уже даты в формате JS: inputTimestamp.split (/ [T \ /: -] / g) – andig 15 July 2015 в 07:47
  • 2
    Если вы разделите строку на составные части, самым надежным следующим шагом будет использование этих частей в качестве аргументов конструктора Date. Создание другой строки, которая дает синтаксический анализатор, возвращает вас к шагу 1. & quot; 2014-04-29 13: 00: 15 & quot; должен быть проанализирован как локальный, ваш код переформатирует его как UTC. :-( – RobG 10 April 2017 в 06:40

Используйте moment.js для синтаксического анализа дат:

var caseOne = moment("Jul 8, 2005", "MMM D, YYYY", true).toDate();
var caseTwo = moment("2005-07-08", "YYYY-MM-DD", true).toDate();

Третий аргумент определяет строгий разбор (доступно с 2.3.0). Без него moment.js также может давать неверные результаты.

4
ответ дан Lukasz Wiktor 19 August 2018 в 16:48
поделиться

Другое решение состоит в создании ассоциативного массива с форматом даты и последующим переформатированием данных.

Этот метод полезен для даты, отформатированной беспорядочным способом.

Пример:

    mydate='01.02.12 10:20:43':
    myformat='dd/mm/yy HH:MM:ss';


    dtsplit=mydate.split(/[\/ .:]/);
    dfsplit=myformat.split(/[\/ .:]/);

    // creates assoc array for date
    df = new Array();
    for(dc=0;dc<6;dc++) {
            df[dfsplit[dc]]=dtsplit[dc];
            }

    // uses assc array for standard mysql format
    dstring[r] = '20'+df['yy']+'-'+df['mm']+'-'+df['dd'];
    dstring[r] += ' '+df['HH']+':'+df['MM']+':'+df['ss'];
7
ответ дан Pascal Belloncle 19 August 2018 в 16:48
поделиться

Ответ на принятый ответ от CMS верен, я только что добавил некоторые функции:

  • обрезка и чистые входные пространства
  • тишины, двоеточия и пробелы
  • имеют день и время по умолчанию

// parse a date time that can contains spaces, dashes, slashes, colons
function parseDate(input) {
    // trimes and remove multiple spaces and split by expected characters
    var parts = input.trim().replace(/ +(?= )/g,'').split(/[\s-\/:]/)
    // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
    return new Date(parts[0], parts[1]-1, parts[2] || 1, parts[3] || 0, parts[4] || 0, parts[5] || 0); // Note: months are 0-based
}
0
ответ дан Stephane L 19 August 2018 в 16:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: