2016-03-28 143 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));