Он делает, но только через какие-то темная магию повозки, запряженные волы происходят под капотом.
Когда вы посмотрите на DateTimeKind
, вы увидите три варианта: Unspecified
, Utc
и Local
. Эта информация упакована в два бита внутреннего 64-битного представления. Поскольку существует четыре возможных значения, которые могут быть представлены двумя битами, это оставляет место для четвертого рода.
И как Джон Скит раскрыл и описал in this blog post, действительно есть скрытый четвертый вид! В основном, это Local
, но при решении двусмысленных времен обрабатывается по-разному.
Конечно, вне .Net, DateTime
с Local
вид не круглый поездка в любом случае. Он обращается как Unspecified
с возвратом - если не указано иное. Я писал об этом here. Лучшей альтернативой является DateTimeOffset
.
Конечно, это всего лишь одна из многих шуточных вещей с DateTime
в .Net. Еще одна замечательная статья от Jon Skeet here обсуждает некоторые из них.
Лучшим решением является прекращение использования любых встроенных типов даты и времени и знакомство с Noda Time. Возможно, вам придется использовать DateTime
или DateTimeOffset
при взаимодействии с другими системами, но вы можете использовать Noda Time внутренне и позволить ему делать все конверсии для вас.
Дополнительная информация
Вы спрашивали о кругооборот через другой формат, например, клещами или строку.
DateTime.Ticks
в .NET не большой формат сериализации, потому что он не прилипает к одной точке отсчета. Они представляют собой целое число 100-наносекундных интервалов с полуночи 1 января 0001 года. Но они не соответствуют UTC - скорее, они совпадают с используемым Kind
. Другими словами:
var utcNow = DateTime.UtcNow;
var now = utcNow.ToLocalTime();
var equal = utcNow.Ticks == now.Ticks; // false
Сравните это с JavaScript, который использует Jan 1 1970 точка отсчета - в полночь по Гринвичу. Каждый раз, когда вы получаете количество тиков, например, с .getTime()
, оно отражает UTC. Вы не можете получать тики по местному времени с помощью простого вызова метода, потому что они не имеют смысла в JavaScript. Другие языки тоже работают.
Кроме того, григорианский календарь, который мы используем, не вступил в силу до 1582 года, поэтому он является отвратительным, что 1/1/0001 является их точкой отсчета.Даты до 1582 года бессмысленны в наших нынешних масштабах и должны быть переведены.
Строки могут быть отличным способом передачи значений даты и времени, поскольку они являются читабельными для человека. Но вы также должны убедиться, что они читаются машиной без какой-либо двусмысленности. Например, не используйте значение 1/4/2013
, потому что без дополнительной информации о культуре вы не узнаете, что это 4 января или 1 апреля. Вместо этого используйте один из форматов ISO8601.
При использовании их с DateTime
вы можете использовать строку формата "o"
, которая может перемещаться по кругу. Он добавляет Z
для Utc
видов или локальное смещение для Local
видов.
var dt = new DateTime(2013,6,4,8,56,0); // Unspecified Kind
var iso = dt.ToString("o"); // 2013-06-04T08:56:00.0000000
var dt = DateTime.UtcNow; // Utc Kind
var iso = dt.ToString("o"); // 2013-06-04T15:56:00.0000000Z
var dt = DateTime.Now; // Local Kind
var iso = dt.ToString("o"); // 2013-06-04T08:56:00.0000000-07:00
При разборе от этого формата, если вы не имеете смещение, то вид будет Unspecified
. Но если у вас есть Z
или любое смещение, то по умолчанию будет Local
. Он также будет применять любое смещение, которое вы предоставляете, чтобы результат был эквивалентным местным времени. Поэтому, если вы хотите применить его правильно, вы должны явно указать его на округление.
var dt = DateTime.Parse("2013-01-04T15:56:00.0000000Z");
var kind = dt.Kind; // Local - incorrect!
var s = dt.ToString("o"); // "2013-01-04T08:56:00.0000000-07:00" (ouch!)
Вместо:
var dt = DateTime.Parse("2013-01-04T15:56:00.0000000Z",
CultureInfo.InvariantCulture,
DateTimeStyles.RoundtripKind);
var kind = dt.Kind; // Utc - that's better.
var s = dt.ToString("o"); // "2013-01-04T15:56:00.0000000Z" (nice!)
Конечно, вы гораздо лучше работать с DateTimeOffset
. Когда вы сериализуете в формате ISO8601, вы всегда получите полное представление:
var dto = DateTimeOffset.Now;
var iso = dto.ToString("o"); // 2013-06-04T08:56:00.0000000-07:00
Этот формат совпадал с RFC3339, который описывает этот профиль ISO8601 спецификации, и быстро становится де-факто стандартом для сериализации метки времени между разнородные системы. ИМХО - вы должны использовать этот формат, когда это возможно. Это значительно превосходит другие форматы, такие как RFC1123, которые вы обычно видите в Интернете. Here are some more details on various date/time formats.
DateTimeOffset
значения всегда будут в обе стороны, поскольку они несут всю соответствующую информацию в последовательном формате. Так будет Unspecified
и Utc
видов DateTime
. Просто избегайте Local
видов DateTime
. Те легко могут попасть в неприятности.
Ответ Пожалуйста?
Просто прочитав это снова, и понял, что я предоставил много деталей, я не сделал напрямую ответ на ваш вопрос. Тесты потерпят неудачу, если входной вид уже первого типа, к которому вы конвертируете. Давайте посмотрим на двух тестовых условиях:
someDateTime == someDateTime.ToUniversalTime().ToLocalTime()
Это будет ошибкой, если исходное значение имеет уже Utc
рода.
Этот тест также потерпит неудачу, если исходное значение недействительно в локальном часовом поясе во время перехода к летнему переходу DST.Например, 2013-03-10 02:00:00
не существует в тихоокеанском времени США. Однако, поскольку он не существует, вы, вероятно, не столкнетесь с этим в своих данных. Таким образом, это, вероятно, не является допустимым условием тестирования.
someDateTime == someDateTime.ToLocalTime().ToUniversalTime()
Это будет ошибкой, если исходное значение имеет уже Local
рода.
Также обратите внимание, что свойство Kind
не участвует в проверке равенства. Таким образом, хотя вход любого из них может быть Unspecified
, выход теста 1 всегда будет иметь вид Local
, а выход теста 2 всегда будет иметь вид Utc
- , но испытания пройдут в любом случае.
Хорошо знать. Эта информация применима к моему варианту использования. Но что, если я должен отбросить эту информацию (возможно, путем кругового отключения над строковым представлением или «Ticks»)? – usr
@usr - См. Обновление. –
Спасибо. Мое дело, по сути, сериализация со стилем «o». Мне было досадно, что при разборе его нужно указать специальные параметры (из-за постфикса «z»). Я ожидал получить неизмененное значение DateTime типа Utc или Unspecified. DateTime.Parse конвертируется в локальный, поэтому я попытался использовать ToUniversalTime. Вот откуда мой вопрос. Это, по-видимому, недостаток дизайна. Я не вижу причин, почему он должен это делать. – usr