Являются устаревшими неуниверсальные наборы в.NET?

Во время недавнего опыта написания 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"

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

25
задан Marek Grzenkowicz 15 August 2011 в 21:25
поделиться

8 ответов

Неуниверсальные наборы являются столь устаревшими, что они были удалены из CoreCLR, используемого в Silverlight и Живой Сетке.

21
ответ дан Curt Hagenlocher 28 November 2019 в 18:20
поделиться

Существуют также проблемы с видимостью COM - взаимодействующие с COM, не может использоваться с дженериками

17
ответ дан Tony Lee 28 November 2019 в 18:20
поделиться

Продвижение только универсальных наборов должно использоваться. Существует также преимущество предотвращения упаковки/распаковывания типов в наборе. Это неэффективно, особенно когда у Вас есть набор типов значения, которые преобразовываются в Систему. Объект, когда сохранено на наборе, следовательно храня значения на "куче" вместо стека вызовов.

15
ответ дан Sean Chambers 28 November 2019 в 18:20
поделиться

Относительно использования неуниверсальных наборов для хранения неоднородных наборов материала можно всегда использовать List< object> выполнять то же самое. Поэтому один, я сказал бы, что нет почти никакой причины вообще для касания неуниверсальных наборов когда-либо снова.

исключение к этому должно было бы поддержать совместимость с системами, записанными на других языках, или против предыдущих версий платформы.NET, но это - "довольно острый" случай, если Вы спрашиваете меня.

7
ответ дан Mel 28 November 2019 в 18:20
поделиться

Я могу сказать Вам, что сериализация XAML наборов полагается на них реализующий или IList или IDictionary, таким образом, неуниверсальные наборы будут с нами в течение некоторого времени.

2
ответ дан 28 November 2019 в 18:20
поделиться

Я не перешел бы и сказал бы, что это является устаревшим или будет удаленным в ближайшее время. Это верно, что необходимо избегать использования неуниверсальных наборов, если у Вас нет причины не не, используют универсальную версию. Тысячи строк наследия (не так прежней версии) код все еще плавает вокруг (и будет в течение многих лет), что неуниверсальные наборы поддержки, такие как ArrayLists. Так как они были [только 110] наборы в.NET 1.0 и 1.1, она широко использовалась (и злоупотреблялась) в течение года.

я все еще иногда должен взаимодействовать со старым картопостроителем O/R, записанным в.NET 1.1, который возвращает объекты IList. У меня есть метод, который делает преобразование в универсальный List<>, который не эффективен, но это - способ, которым это.

И если необходимо хранить различные объекты в том же массиве (странный, но возможный) Вы будете нуждаться в неуниверсальном наборе. Штраф Упаковки и Распаковывания - что-то, что необходимо будет заплатить так или иначе.

не боятся использовать их, если Вы чувствуете, что имеете к.

1
ответ дан Martin Marconcini 28 November 2019 в 18:20
поделиться

Да, насколько я понимаю, что они только там для совместимости с существующими продуктами. Необходимо всегда использовать безопасную с точки зрения типов версию (т.е. использовать Систему. Наборы. Универсальный по Системе. Наборы).

http://msdn.microsoft.com/en-us/library/ms379564.aspx

0
ответ дан Mark Ingram 28 November 2019 в 18:20
поделиться

Могли бы быть экземпляры, где необходимо хранить объекты неизвестных типов или объекты нескольких различных типов, но если Вы действительно знаете тип объектов, которые Вы хотите хранить тогда, я не вижу причины не использовать универсальную версию.

Редактирование: Как прокомментировано можно просто использовать List<Object> - doh!

1
ответ дан samjudson 28 November 2019 в 18:20
поделиться
Другие вопросы по тегам:

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