我试图了解我们遇到的这个时区问题。我们希望以UTC格式存储所有日期时间,然后将日期时间转换为用户时区。
我们决定使用Nodatime,因为这似乎是正确的方法。但是我们遇到了一些问题
这是我们将日期时间转换为UTC的方式(注意:我现在硬编码了usersTimeZone)
public static DateTime ConvertLocaltoUTC(this DateTime dateTime)
{
LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
var usersTimezoneId = "Europe/Copenhagen";
var usersTimezone = timeZoneProvider[usersTimezoneId];
var zonedDbDateTime = usersTimezone.AtLeniently(localDateTime);
var returnThis = zonedDbDateTime.ToDateTimeUtc();
return zonedDbDateTime.ToDateTimeUtc();
}
以下是我们如何将其转换回来
public static DateTime ConvertUTCtoLocal(this DateTime dateTime)
{
Instant instant = Instant.FromDateTimeUtc(dateTime);
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
var usersTimezoneId = "Europe/Copenhagen"; //just an example
var usersTimezone = timeZoneProvider[usersTimezoneId];
var usersZonedDateTime = instant.InZone(usersTimezone);
return usersZonedDateTime.ToDateTimeUnspecified();
}
然而,当我们将其转换回本地时,它会引发异常:
参数异常:Instant.FromDateTimeUtc的DateTime.Kind无效
在第一行" ConvertUTCtoLocal()" 日期时间的一个例子可以是:" 9/18/2017 5:28:46 PM" - 是的,这是通过ConvertLocalToUTC方法。
我提供了错误的格式,或者我在这里做错了什么?
答案 0 :(得分:7)
您展示的例外:
参数异常:Instant.FromDateTimeUtc的DateTime.Kind无效
从此代码抛出:
Instant instant = Instant.FromDateTimeUtc(dateTime);
这意味着dateTime.Kind
需要DateTimeKind.Utc
才能转换为Instant
,无论出于何种原因,它都不是。{/ p>
如果您查看ConvertLocaltoUTC
方法的结果,就会发现 有.Kind == DateTimeKind.Utc
。
因此,问题出在您的代码的其他位置,无论您在哪里创建了dateTime
,您都会传入ConvertUTCtoLocal
。
您可能会发现解决方案可能是以下任何一种:
您可能需要调用DateTime.SpecifyKind
将类型设置为UTC,但请注意,只有在您的值实际为UTC并且未设置类型时才执行此操作。例如,在从数据库加载基于UTC的DateTime
时使用此选项。
您可能需要致电.ToUniversalTime()
,但如果机器的当地时区与您的情况相关,请务必小心。例如,在UI控件选择日期的桌面或移动应用程序中执行此操作,但您的意思是表示UTC而不是本地时间。
您可能需要将解析字符串的方式更改为DateTime
值,例如将DateTimeStyles.RoundTripKind
传递给DateTime.Parse
来电(或任何例如,如果您正在从text,csv等中读取数据,请执行此操作。
如果您想避免决定,请不要编写以DateTime
作为输入或将DateTime
作为输出的函数。相反,请尽早使用DateTimeOffset
或使用Noda-Time类型,例如Instant
,LocalDateTime
等。
答案 1 :(得分:4)
这对我有用:
Instant instant = Instant.FromDateTimeUtc(DateTime.SpecifyKind(datetime, DateTimeKind.Utc));