Nodatime对Instant.FromDateTimeUtc的DateTime.Kind无效

时间:2017-09-18 17:31:14

标签: c# datetime nodatime

我试图了解我们遇到的这个时区问题。我们希望以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方法。

我提供了错误的格式,或者我在这里做错了什么?

2 个答案:

答案 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类型,例如InstantLocalDateTime等。

答案 1 :(得分:4)

这对我有用:

Instant instant = Instant.FromDateTimeUtc(DateTime.SpecifyKind(datetime, DateTimeKind.Utc));