2009-08-30 3 views
47

Я сохраняю все свои даты в формате UTC в моей базе данных. Я спрашиваю у пользователя их часовой пояс, и я хочу использовать их часовой пояс, а также то, что я предполагаю, это время сервера, чтобы определить для них UTC.Проблемы с преобразованием даты DateTime в UTC

Как только у меня есть это, я хочу выполнить поиск, чтобы узнать, что такое диапазон в базе данных, используя их новую дату UTC.

но я всегда получаю это исключение.

System.ArgumentException was unhandled by user code 
Message="The conversion could not be completed because the 
supplied DateTime did not have the Kind property set correctly. 
For example, when the Kind property is DateTimeKind.Local, 
the source time zone must be TimeZoneInfo.Local. 
Parameter name: sourceTimeZone" 

Я не знаю, почему я получаю это.

Я попробовал 2 способа

TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(id); 
// I also tried DateTime.UtcNow 
DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone); 

Это не удалось, так что я устал

DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
var utc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, 
              ZoneId, TimeZoneInfo.Utc.Id); 

Это также не как с той же ошибкой. Что я делаю не так?

Редактировать эту работу?

DateTime localServerTime = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local); 
TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(id); 

var usersTime = TimeZoneInfo.ConvertTime(localServerTime, info); 

var utc = TimeZoneInfo.ConvertTimeToUtc(usersTime, userInfo); 

Edit 2 @ Jon тарелочкам

Я. Я просто думал о том, что я не мог бы даже не нужно делать все это. Время вещи меня смущает, поэтому сообщение может быть не таким ясным, как должно быть. Я никогда не знаю, что делает heck DateTime.Now (я пытался изменить свой часовой пояс на другой часовой пояс, и он продолжал получать мое местное время).

Это то, что я хотел, чтобы мои вещи делали. Пользователь приходит на сайт, добавляет некоторое предупреждение, и теперь он сохраняется как utc (до того, как он был DateTime.Now, тогда кто-то предложил хранить все UTC).

Итак, перед тем, как пользователь придет на мой сайт и в зависимости от того, где мой сервер хостинга мог бы быть на следующий день. Поэтому, если предупреждение было объявлено 30 августа (их время), но с разницей во времени сервера они могут появиться 29 августа, и будет показано предупреждение.

Так что я хотел бороться с этим. Итак, теперь я не уверен, должен ли я просто хранить свое местное время, а затем использовать этот материал смещения? Или просто сохраните время UTC. С сохранением времени UTC все еще может быть неправильно, поскольку пользователь все еще, вероятно, будет думать в местном масштабе, и я не уверен, что UTC действительно работает, он все равно может закончиться разницей времени.

Edit3

var info = TimeZoneInfo.FindSystemTimeZoneById(id) 

DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(DataBaseUTCDate, 
              TimeZoneInfo.Utc, info); 
+0

'DateTime.Now.Kind' уже' Local'; вам не нужно называть 'SpecifyKind'. – SLaks

+0

@Edit 2: сохранить оповещения в формате UTC и показать их в часовом поясе, предоставленном пользователем, как показано в моем ответе. – dtb

+0

Так как это будет работать? Я получаю DateTime.UtcNow, а затем фильтрует предупреждения из db? затем преобразовать найденные результаты в их местное время? – chobo2

ответ

30

DateTime структура поддерживает только два часовых поясов:.

  • местный часовой пояс машина работает в
  • и UTC.

Посмотрите на структуру DateTimeOffset.

var info = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); 

DateTimeOffset localServerTime = DateTimeOffset.Now; 

DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(localServerTime, info); 

DateTimeOffset utc = localServerTime.ToUniversalTime(); 

Console.WriteLine("Local Time: {0}", localServerTime); 
Console.WriteLine("User's Time: {0}", usersTime); 
Console.WriteLine("UTC:   {0}", utc); 

Выход:

Local Time: 30.08.2009 20:48:17 +02:00 
User's Time: 31.08.2009 03:48:17 +09:00 
UTC:   30.08.2009 18:48:17 +00:00 
+0

Это похоже на работу. Время сбивает меня с толку. Я должен прочитать этот DAteTimeOffSet и почему он работает, а что нет. Но мне интересно, не могу ли я просто DateTime.UtcNow? например, когда я это делаю, он конвертирует время моего сервера в дату utc, что то же самое, если я сделал ваш материал dateoffSet (используя время в Западной Африке). Или они будут другими? – chobo2

+1

Как говорит Джон Скит, если вам просто нужно текущее время в UTC, просто используйте 'DateTime.UtcNow' или' DateTimeOffset.UtcNow'. – dtb

+0

Интересно, почему DateTime не предоставляет свойство TimeZoneInfo, поэтому мы можем указать дату и время вместе с часовым поясом !? – brighty

85

Вы должны установить Kind в Unspecified, как это:

DateTime now = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Unspecified); 
var utc = TimeZoneInfo.ConvertTimeToUtc(now , zone); 

DateTimeKind.Local означает в местном часовом поясе, а не какой-либо другой часовой пояс. Вот почему вы получили ошибку.

+0

Хорошо, я попробую это. Будет ли то, что я только что отредактировал? Кажется, что это не так (Западная Африка TimeZone отключилась примерно на 10 минут), когда вы переходите из одного часового пояса в другой, но UTC был правильным временем. – chobo2

+0

Хм, так что это не работает, потому что он не знает правильный часовой пояс? Затем я все еще что-то делаю, потому что думаю, что получаю неправильное время utc. – chobo2

+0

Я неправильно читаю ваш код; это действительно сработает. – SLaks

6

Как указано в dtb, вы должны использовать DateTimeOffset, если хотите сохранить дату/время в определенном часовом поясе.

Однако от вашего поста это совершенно не ясно, что вам действительно нужно. Вы приводите только примеры, используя DateTime.Now, и вы говорите, что вы используете , угадывая, что вы используете серверное время. В какое время вы действительно хотите? Если вам просто нужно текущее время в UTC, используйте DateTime.UtcNow или DateTimeOffset.UtcNow. Вам не нужно знать часовой пояс, чтобы узнать текущее время UTC, именно потому, что оно универсально.

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

+0

см. Мое оригинальное сообщение Edit2 – chobo2

2

UTC - это всего лишь часовой пояс, в котором все согласны как стандартный часовой пояс. В частности, это часовой пояс, который содержит Лондон, Англия. EDIT: Обратите внимание, что это не тот же часовой пояс; например, UTC не имеет DST. (Спасибо, Jon Skeet)

Единственная особенность в UTC заключается в том, что его гораздо проще использовать в .Net, чем в любой другой часовой пояс (DateTime.UtcNow, DateTime.ToUniversalTime и другие участники).

Поэтому, как уже упоминалось, лучше всего для вас сделать, это хранить все даты в формате UTC в базе данных, а затем преобразовать местное время пользователя (путем записи TimeZoneInfo.ConvertTime(time, usersTimeZone) перед отображением.


Если вы хотите быть любителем, вы можете geolocate IP-адрес ваших пользователей автоматически угадать их часовые пояса

+0

Это будущие версии lol. Поначалу нужно было убрать основы. – chobo2

+0

Тогда что вы хотите знать сейчас? – SLaks

+0

Таким образом, это не дало бы времени другим. Как сначала получать все оповещения по UTC, а затем менять их на локальное время после их обнаружения, не приведет к пропущению каких-либо предупреждений? Как их не будет, что где-то где-то, где, где на пару минут или что-то еще? – chobo2

5

все остального ответа кажется слишком сложным, я имел конкретное требование, и это работало нормально для меня..

void Main() 
{ 
    var startDate = DateTime.Today; 
    var StartDateUtc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.SpecifyKind(startDate.Date, DateTimeKind.Unspecified), "Eastern Standard Time", "UTC"); 
    startDate.Dump(); 
    StartDateUtc.Dump(); 
} 

Какие выходы (от LINQPad), что я ожидал:

12/20/2013 12:00:00 AM

12/20/2013 5:00:00

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

FYI - машина, с которой я работал, была в Центральном часовом поясе, и DST не действовал.

Смежные вопросы