DateTimeOffset错误:本地dateTime的UTC偏移量与偏移量参数不匹配

Tox*_*ble 20 c# datetime

我正在尝试创建一个将时间从一个时区转换为另一个时区的小方法.我认为这很简单,但是当我部署它时,我得到了这个错误The UTC Offset of the local dateTime parameter does not match the offset argument.我的猜测是因为服务器与用户不在同一时区,因为这将在世界各地使用.

public object ConvertDate(DateTime inputTime, string fromOffset, string toZone)
{
    var fromTimeOffset = new TimeSpan(0, - int.Parse(fromOffset), 0);
    var to = TimeZoneInfo.FindSystemTimeZoneById(toZone);
    var offset = new DateTimeOffset(inputTime, fromTimeOffset);
    var destination = TimeZoneInfo.ConvertTime(offset, to); 
    return destination.DateTime;
}
Run Code Online (Sandbox Code Playgroud)

数字在哪里fromOffset,从用户时区转换为时间跨度,toZone是我们要转换为的区域的名称.此行发生错误var offset = new DateTimeOffset(inputTime, fromTimeOffset);

关于如何使这个工作的任何想法?

red*_*ted 27

请参阅文档以了解抛出异常的原因:

ArgumentException:dateTime.Kindequals Local并且offset不等于系统本地时区的偏移量.

DateTime您收到的参数的Kind属性设置为Local.解决这个问题最简单的方法是设置KindUndefined.

public object ConvertDate(DateTime inputTime, string fromOffset, string toZone)
{
    // Ensure that the given date and time is not a specific kind.
    inputTime = DateTime.SpecifyKind(inputTime, DateTimeKind.Unspecified);

    var fromTimeOffset = new TimeSpan(0, - int.Parse(fromOffset), 0);
    var to = TimeZoneInfo.FindSystemTimeZoneById(toZone);
    var offset = new DateTimeOffset(inputTime, fromTimeOffset);
    var destination = TimeZoneInfo.ConvertTime(offset, to); 
    return destination.DateTime;
}
Run Code Online (Sandbox Code Playgroud)

  • 这太荒谬了,这使得使用DateTimeOffsets成为一场噩梦.如果有人*明确地*在新的DTO上设置偏移量,他们可能已经意识到我们希望它有一个偏移量并因此允许它吗?他们是否意识到在大多数情况下,原始DateTime.Kind的设置不在我们手中?更糟糕的是,使用本地时间的不断假设(对不起,这对服务器来说是可怕的)让我们首先处于这种情况?这是一个令人沮丧的框架决定,会带来很多痛苦. (5认同)
  • 嗯,解决了这个问题,谢谢,我确实阅读了文档,但发现解释它有点困难 (2认同)
  • 您可以为线程设置文化,然后一切都使用正确的文化。遗憾的是,.NET 不允许您以类似方式设置时区并让 DateTimes“正常工作”。例如,DateTime.Now 将返回配置的时区的时间偏移量。这样一来,“搬迁”就变得非常容易。 (2认同)

Nic*_*sen 11

这是我用来解决这个令人难以置信的令人沮丧的框架决定的扩展方法。请参阅注释,处理此问题的最佳和最高效的方法是使用 的 ticks 构造函数DateTimeOffset,而不必分配另一个中间体DateTime来更改它的Kind属性。

    /// <summary>
    /// Converts a DateTime to a DateTimeOffset, without risking any onerous exceptions
    /// the framework quite unfortunately throws within the DateTimeOffset constructor, 
    /// such as they do when the source DateTime's Kind is not set to UTC. The best and 
    /// most performant way around this, which we do herein, is to simply construct the 
    /// new DateTimeOffset with the overload that excepts Ticks. Also, we will simply 
    /// return <see cref="DateTimeOffset.MinValue"/> if the source DateTime was 
    /// <see cref="DateTime.MinValue"/>.
    /// </summary>
    /// <param name="dt">Source DateTime.</param>
    /// <param name="offset">Offset</param>
    public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeSpan offset)
    {
        // adding negative offset to a min-datetime will throw, this is a 
        // sufficient catch. Note however that a DateTime of just a few hours can still throw
        if (dt == DateTime.MinValue)
            return DateTimeOffset.MinValue;

        return new DateTimeOffset(dt.Ticks, offset);
    }

    public static DateTimeOffset ToDateTimeOffset(this DateTime dt, double offsetInHours = 0)
        => ToDateTimeOffset(dt, offsetInHours == 0 ? TimeSpan.Zero : TimeSpan.FromHours(offsetInHours));
Run Code Online (Sandbox Code Playgroud)

  • 非常好的解决方案! (4认同)