将我的DateTime转换为UTC有问题

我在我的数据库中以UTC格式存储所有date。 我问用户他们的时区,我想使用他们的时区加上我猜测是服务器时间来找出他们的UTC。

一旦我有,我想要做一个search,看看使用他们新转换的UTCdate在数据库中的范围。

但我总是得到这个例外。

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

编辑2 @ Jon Skeet

我只是想,我可能甚至不需要这样做。 时间的东西混淆了我,所以这就是为什么这个职位可能不太清楚,应该是。 我永远不知道到底是怎么了(我试图改变我的时区到另一个时区,并保持我的本地时间)。

这是我想要的东西。 用户来到网站添加一些警报,现在得到保存为utc(之前是DateTime.Now然后有人build议存储所有的UTC)。

所以在用户来到我的网站之前,根据我的托pipe服务器的位置,可能会在第二天。 因此,如果警报声明是在8月30日(他们的时间)显示的,但由于服务器的时间差异,他们可能会在8月29日到来,警报将显示。

所以我想打击。 所以现在我不知道应该只存储他们的本地时间,然后使用这个抵消的东西? 或者只是储存UTC时间。 仅仅存储UTC时间仍然可能是错误的,因为用户仍然可能会考虑在当地时间,我不知道UTC如何真正的工作,它仍然可以结束时间的差异。

EDIT3

  var info = TimeZoneInfo.FindSystemTimeZoneById(id) DateTimeOffset usersTime = TimeZoneInfo.ConvertTime(DataBaseUTCDate, TimeZoneInfo.Utc, info); 

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 

您需要将Kind设置为Unspecified ,如下所示:

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

DateTimeKind.Local表示在本地时区,而不是任何其他时区。 这就是为什么你得到错误。

正如dtb所说,如果你想存储具有特定时区的date/时间,你应该使用DateTimeOffset

然而,从你的文章来看,你真的不需要清楚。 你只给出使用DateTime.Now例子,你说你猜测你正在使用服务器时间。 你什么时候想要? 如果您只需要UTC中的当前时间,请使用DateTime.UtcNowDateTimeOffset.UtcNow 。 您不需要知道时区即可了解当前的UTC时间,正因为它是通用的。

如果您以其他方式从用户那里获得date/时间,请提供更多信息 – 这样我们就可以计算出您需要做的事情。 否则,我们只是猜测。

其他人的答案似乎过于复杂。 我有一个具体的要求,这对我很好:

 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 AM

道具为未指定种类的技巧。 这就是我所缺less的。 但所有关于只有两种date(本地和UTC)的讨论只是混淆了我的问题。

仅供参考 – 我运行这台机器是在中部时区,DST没有生效。

UTC只是每个人都认同的标准时区。 具体来说,这是一个包含伦敦,英国的时区。 编辑 :请注意,它不是完全相同的时区; 例如,UTC没有DST。 (谢谢,Jon Skeet)

UTC唯一特别的地方是在.Net中使用比任何其他时区( DateTime.UtcNowDateTime.ToUniversalTime和其他成员)要容易得多。

因此,正如其他人所说的,最好的办法是在数据库中存储UTC的所有date,然后转换为用户的本地时间(通过在显示之前写入TimeZoneInfo.ConvertTime(time, usersTimeZone)


如果您想更有趣,可以将用户的IP地址进行地理定位,以自动猜测其时区。