2016-03-28 116 views
7

我试图创建一个将时间从一个时区转换为另一个时区的小方法。我认为它会很简单,但当我部署它时,我得到这个错误The UTC Offset of the local dateTime parameter does not match the offset argument.我的猜测是,这是因为服务器不在用户相同的时区,这是没有用的,因为这将来自世界各地使用。DateTimeOffset错误:本地dateTime的UTC偏移量与偏移量参数不匹配

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

fromOffset是一个数字,从用户的时区转换为时间跨度和toZone是我们转换到该区域的名称。 错误发生在这条线上var offset = new DateTimeOffset(inputTime, fromTimeOffset);

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

+0

什么是'inputTime,fromTimeOffset'要传递 –

+0

为例样本值可以是:'inputTime = 28/03/2016 6时09分49秒PM'和'fromTimeOffset = 13hrs' – Toxicable

+0

如果对于C#'DateTime',你会发现自己说“我认为它会很简单......”,值得一读的是Jon Skeet的着名的“DateTime有什么问题吗?”关于NodaTime图书馆的诞生的帖子:http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html – rob3c

回答

14

说明为何异常被抛出的documentation

ArgumentException: dateTime.Kind equals Local and offset does not equal the offset of the system's local time zone.

您收到有其Kind属性设置为LocalDateTime说法。解决此问题的最简单方法是将Kind设置为Undefined

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; 
} 
+0

啊,解决它谢谢,我没有阅读文档,但发现它是一个有点难以解释tbh – Toxicable

+0

这太荒谬了,它使得DateTimeOffsets成为一场噩梦。如果有人明确地设置了新的DTO上的偏移量,他们是否会意识到我们希望它具有偏移量并允许它?他们是否会意识到,在大多数情况下,原始DateTime.Kind的设置不在我们手中?更糟糕的是,使用当地时间的不断假设(对不起,这对服务器来说是可怕的)首先使我们处于这种情况下?这是一个令人沮丧的框架决定,会导致很多痛苦。 –

1

这是我用来解决这个令人难以置信的令人沮丧的框架决定的扩展方法。请参阅注释,处理此问题的最佳和最高效的方法是使用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));