2016-03-28 12 views
7

Ich versuche, eine kleine Methode zu erstellen, die die Zeit von einer Zeitzone in eine andere konvertiert. Ich dachte, es wäre einfach genug, aber wenn ich es bereitstellen, bekomme ich diesen Fehler The UTC Offset of the local dateTime parameter does not match the offset argument. Meine Vermutung ist, dass es weil der Server nicht in der gleichen Zeitzone wie der Benutzer ist, der nicht hilfreich ist, da dies aus der ganzen Welt verwendet werden würde.DateTimeOffset Fehler: UTC-Offset von lokalen dateTime stimmt nicht mit dem Offset-Argument überein

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

Wo fromOffset eine Zahl ist, umgerechnet auf den Zeitraum von der Benutzer Zeitzone und toZone ist der Name der Zone wir sind zu konvertieren. Der Fehler tritt in dieser Zeile auf var offset = new DateTimeOffset(inputTime, fromTimeOffset);

Irgendwelche Ideen, wie man das funktioniert?

+0

was die Beispielwerte für 'inputTime sind, fromTimeOffset', die Sie –

+0

ein Beispiel sind vorbei sein könnte:' inputTime = 28/03/2016 06.09.49 PM' und 'fromTimeOffset = 13hrs' – Toxicable

+0

Wenn Sie finden sich immer wieder "Ich dachte, es wäre einfach genug ..." in Bezug auf die C# 'DateTime', es lohnt sich Jon Skeets (in) berühmten" Was ist falsch mit DateTime überhaupt? " Post über die Geburt der NodaTime-Bibliothek: http://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html – rob3c

Antwort

14

Siehe documentation dafür, warum die Ausnahme ausgelöst wird:

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

Das DateTime Argument, das Sie erhalten, hat seine Kind Eigenschaft auf Local gesetzt. Der einfachste Weg, um dieses Problem zu lösen, ist die Kind auf Undefined zu setzen.

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

Ah, dass es gelöst, danke, ich habe die Dokumentation gelesen, aber es gefunden a etwas schwer zu interpretieren tbh – Toxicable

+0

Das ist so lächerlich, macht es mit DateTimeOffsets zu einem Alptraum. Wenn jemand * explizit * den Versatz auf einem neuen DTO setzt, haben sie vielleicht bemerkt, dass wir einen Versatz haben wollten, und damit erlauben? Und haben sie vielleicht gemerkt, dass die Einstellung des originalen DateTime.Kind in den meisten Fällen nicht in unseren Händen lag? Und noch schlimmer, dass uns die ständige Annahme der Lokalzeit (Sorry, das ist schrecklich für Server) in dieser Situation überhaupt erst einfällt? Dies ist solch eine frustrierende Rahmenentscheidung, die viel Schmerz verursacht. –

1

Hier ist eine Erweiterungsmethode, die ich verwende, um diese unglaublich frustrierende Rahmenentscheidung zu umgehen. Siehe Hinweise, die beste und performanteste Möglichkeit, dies zu umgehen, besteht darin, den Konstruktor Ticks von zu verwenden, anstatt ein weiteres Zwischenprodukt DateTime zuzuordnen, nur um seine Eigenschaft Kind zu ändern.

/// <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)); 
Verwandte Themen