Wie man elegant mit Zeitzonen umgeht


140

Ich habe eine Website, die in einer anderen Zeitzone gehostet wird als die Benutzer, die die Anwendung verwenden. Darüber hinaus können Benutzer eine bestimmte Zeitzone haben. Ich habe mich gefragt, wie andere SO-Benutzer und -Anwendungen dies angehen. Der offensichtlichste Teil ist, dass in der Datenbank Datum und Uhrzeit in UTC gespeichert sind. Auf dem Server sollten alle Datums- und Uhrzeitangaben in UTC behandelt werden. Ich sehe jedoch drei Probleme, die ich zu überwinden versuche:

  1. Abrufen der aktuellen Uhrzeit in UTC (einfach zu lösen mit DateTime.UtcNow).

  2. Datum und Uhrzeit aus der Datenbank abrufen und dem Benutzer anzeigen. Es gibt möglicherweise viele Anrufe, um Daten in verschiedenen Ansichten zu drucken. Ich dachte an eine Ebene zwischen der Ansicht und den Controllern, die dieses Problem lösen könnte. Oder mit einer benutzerdefinierten Erweiterungsmethode DateTime(siehe unten). Der Hauptnachteil ist, dass an jedem Ort, an dem eine Datums- / Uhrzeitangabe in einer Ansicht verwendet wird, die Erweiterungsmethode aufgerufen werden muss!

    Dies würde auch die Verwendung von etwas wie dem erschweren JsonResult. Man konnte nicht mehr einfach anrufen Json(myEnumerable), es müsste sein Json(myEnumerable.Select(transformAllDates)). Vielleicht könnte AutoMapper in dieser Situation helfen?

  3. Eingaben vom Benutzer erhalten (Lokal zu UTC). Wenn Sie beispielsweise ein Formular mit einem Datum veröffentlichen möchten, müssen Sie das Datum zuvor in UTC konvertieren. Das erste, was mir in den Sinn kommt, ist das Erstellen eines Brauchs ModelBinder.

Hier sind die Erweiterungen, die ich in den Ansichten verwenden wollte:

public static class DateTimeExtensions
{
    public static DateTime UtcToLocal(this DateTime source, 
        TimeZoneInfo localTimeZone)
    {
        return TimeZoneInfo.ConvertTimeFromUtc(source, localTimeZone);
    }

    public static DateTime LocalToUtc(this DateTime source, 
        TimeZoneInfo localTimeZone)
    {
        source = DateTime.SpecifyKind(source, DateTimeKind.Unspecified);
        return TimeZoneInfo.ConvertTimeToUtc(source, localTimeZone);
    }
}

Ich würde denken, dass der Umgang mit Zeitzonen so häufig vorkommt, wenn man bedenkt, dass viele Anwendungen jetzt Cloud-basiert sind und die Ortszeit des Servers stark von der erwarteten Zeitzone abweichen kann.

Wurde dies schon einmal elegant gelöst? Fehlt mir etwas? Ideen und Gedanken werden sehr geschätzt.

EDIT: Um einige Verwirrung zu beseitigen, dachte ich, einige weitere Details hinzuzufügen. Im Moment geht es nicht darum, wie UTC-Zeiten in der Datenbank gespeichert werden, sondern vielmehr darum, von UTC-> Lokal und Lokal-> UTC zu wechseln. Wie @Max Zerbini betont, ist es natürlich klug, den UTC-> Lokalen Code in die Ansicht aufzunehmen, aber ist die DateTimeExtensionswirklich die Antwort? Ist es sinnvoll, beim Abrufen von Eingaben vom Benutzer Datumsangaben als Ortszeit des Benutzers zu akzeptieren (da dies von JS verwendet wird) und dann eine ModelBinderzu UTC-Transformation zu verwenden? Die Zeitzone des Benutzers wird in der Datenbank gespeichert und kann leicht abgerufen werden.


3
Vielleicht lesen Sie zuerst diesen ausgezeichneten Beitrag durch ... Sommerzeit und Best Practices für die Zeitzone
dodgy_coder

@dodgy_coder - Das war schon immer ein großartiger Ressourcenlink für Zeitzonen. Es löst jedoch keines meiner Probleme (speziell in Bezug auf MVC). Trotzdem danke.
TheCloudlessSky


Neugierig, für welche Lösung Sie sich entschieden haben. Ich stehe vor einer ähnlichen Entscheidung. Gute Frage.
Sean

@ Sean - Die Lösung war bisher nicht elegant (weshalb ich noch keine Antwort akzeptiert habe). Es war ein großer manueller Aufwand, Daten / Zeiten zu drucken und sie manuell mit einem zurück zu konvertieren ModelBinder.
TheCloudlessSky

Antworten:


106

Nicht, dass dies eine Empfehlung wäre, sondern vielmehr ein Paradigma, aber die aggressivste Art und Weise, wie ich mit Zeitzoneninformationen in einer Web-App (die nicht nur für ASP.NET MVC verfügbar ist) umgegangen bin, war die folgende:

  • Alle Datums- und Uhrzeitangaben auf dem Server sind UTC. Das bedeutet, wie Sie sagten , DateTime.UtcNow.

  • Versuchen Sie, dem Client zu vertrauen, der so wenig wie möglich Daten an den Server übergibt. Wenn Sie beispielsweise "jetzt" benötigen, erstellen Sie kein Datum auf dem Client und übergeben Sie es dann an den Server. Erstellen Sie entweder ein Datum in Ihrem GET und übergeben Sie es an das ViewModel oder auf POST DateTime.UtcNow.

Bisher ziemlich normaler Tarif, aber hier wird es „interessant“.

  • Wenn Sie ein Datum vom Client akzeptieren müssen, verwenden Sie Javascript, um sicherzustellen, dass die Daten, die Sie auf dem Server veröffentlichen, in UTC vorliegen. Der Kunde weiß, in welcher Zeitzone er sich befindet, sodass er die Zeiten mit angemessener Genauigkeit in UTC umrechnen kann.

  • Beim Rendern von Ansichten verwendeten sie das HTML5- <time>Element. Sie renderten niemals Datumsangaben direkt im ViewModel. Es wurde als HtmlHelperErweiterung implementiert , so etwas wie Html.Time(Model.when). Es würde rendern <time datetime='[utctime]' data-date-format='[datetimeformat]'></time>.

    Dann würden sie Javascript verwenden, um die UTC-Zeit in die Ortszeit des Clients zu übersetzen. Das Skript würde alle <time>Elemente finden und die date-formatdata-Eigenschaft verwenden, um das Datum zu formatieren und den Inhalt des Elements zu füllen.

Auf diese Weise mussten sie nie die Zeitzone eines Kunden verfolgen, speichern oder verwalten. Dem Server war es egal, in welcher Zeitzone sich der Client befand, und er musste auch keine Zeitzonenübersetzungen durchführen. Es spuckte einfach UTC aus und ließ den Kunden das in etwas Vernünftiges umwandeln. Dies ist vom Browser aus einfach, da er weiß, in welcher Zeitzone er sich befindet. Wenn der Client seine Zeitzone ändert, aktualisiert sich die Webanwendung automatisch. Das einzige, was sie gespeichert haben, war die Datums- / Uhrzeitformatzeichenfolge für das Gebietsschema des Benutzers.

Ich sage nicht, dass es der beste Ansatz war, aber es war ein anderer, den ich vorher nicht gesehen hatte. Vielleicht finden Sie daraus einige interessante Ideen.


Vielen Dank für Ihre Antwort. Wird beim Eingeben von Datumseingaben vom Benutzer (z. B. Planen eines Termins) nicht angenommen , dass sich diese Eingabe in der aktuellen Zeitzone befindet? Was halten Sie davon, dass der ModelBinder diese Transformation vor dem Eingeben der Aktion ausführt (siehe meine Kommentare zu @casperOne? Außerdem ist die <time>Idee ziemlich cool. Der einzige Nachteil ist, dass ich das gesamte DOM nach diesen Elementen abfragen muss ist nicht gerade schön, nur um Daten zu transformieren (was ist mit JS deaktiviert?).
Nochmals vielen

Normalerweise wird davon ausgegangen, dass es sich um eine lokale Zeitzone handelt. Sie haben jedoch darauf geachtet, dass jedes Mal, wenn sie eine Zeit von einem Benutzer gesammelt haben, diese mithilfe von Javascript in UTC umgewandelt wurde, bevor sie an den Server gesendet wurde. Ihre Lösung war sehr JS-schwer und verschlechterte sich nicht sehr gut, wenn JS ausgeschaltet war. Ich habe nicht genug darüber nachgedacht, um zu sehen, ob das klug ist. Aber wie gesagt, vielleicht gibt es dir ein paar Ideen.
J. Holmes

2
Ich habe seitdem an einem anderen Projekt gearbeitet, das lokale Daten benötigte, und dies war die Methode, die ich verwendet habe. Ich benutze moment.js , um die Datums- / Uhrzeitformatierung durchzuführen ... es ist süß. Vielen Dank!
TheCloudlessSky

Gibt es nicht eine einfache Möglichkeit, in der app.config / web.cofig der Anwendung eine Zeitzone für den Anwendungsbereich zu definieren und alle DateTime.Now-Werte in DateTime.UtcNow umzuwandeln? (Ich möchte Situationen vermeiden, in denen Programmierer in der Firma noch versehentlich DateTime.Now verwenden würden)
Uri Abramson

3
Ein Nachteil dieses Ansatzes, den ich sehen kann, ist, wenn Sie die Zeit für andere Dinge nutzen, PDFs, E-Mails usw. erstellen. Es gibt kein Zeitelement für diese, sodass Sie diese weiterhin manuell konvertieren müssen. Ansonsten sehr ordentliche Lösung
Shenku

15

Nach mehreren Rückmeldungen ist hier meine endgültige Lösung, die meiner Meinung nach sauber und einfach ist und Probleme mit der Sommerzeit abdeckt.

1 - Wir übernehmen die Konvertierung auf Modellebene. In der Model-Klasse schreiben wir also:

    public class Quote
    {
        ...
        public DateTime DateCreated
        {
            get { return CRM.Global.ToLocalTime(_DateCreated); }
            set { _DateCreated = value.ToUniversalTime(); }
        }
        private DateTime _DateCreated { get; set; }
        ...
    }

2 - In einem globalen Helfer erstellen wir unsere benutzerdefinierte Funktion "ToLocalTime":

    public static DateTime ToLocalTime(DateTime utcDate)
    {
        var localTimeZoneId = "China Standard Time";
        var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(localTimeZoneId);
        var localTime = TimeZoneInfo.ConvertTimeFromUtc(utcDate, localTimeZone);
        return localTime;
    }

3 - Wir können dies weiter verbessern, indem wir die Zeitzonen-ID in jedem Benutzerprofil speichern, damit wir sie aus der Benutzerklasse abrufen können, anstatt die konstante "China Standard Time" zu verwenden:

public class Contact
{
    ...
    public string TimeZone { get; set; }
    ...
}

4 - Hier können wir die Liste der Zeitzonen abrufen, die dem Benutzer zur Auswahl aus einer Dropdown-Box angezeigt werden sollen:

public class ListHelper
{
    public IEnumerable<SelectListItem> GetTimeZoneList()
    {
        var list = from tz in TimeZoneInfo.GetSystemTimeZones()
                   select new SelectListItem { Value = tz.Id, Text = tz.DisplayName };

        return list;
    }
}

Jetzt, um 9:25 Uhr in China, Website in den USA gehostet, Datum in UTC in der Datenbank gespeichert, hier ist das Endergebnis:

5/9/2013 6:25:58 PM (Server - in USA) 
5/10/2013 1:25:58 AM (Database - Converted UTC)
5/10/2013 9:25:58 AM (Local - in China)

BEARBEITEN

Vielen Dank an Matt Johnson für den Hinweis auf die Schwachstellen der ursprünglichen Lösung und für das Löschen des ursprünglichen Beitrags, aber Probleme beim Erhalten des richtigen Code-Anzeigeformats. Es stellte sich heraus, dass der Editor Probleme beim Mischen von "Aufzählungszeichen" mit "Vorcode" hat, also ich entfernte die Bulles und es war in Ordnung.


Es scheint praktikabel zu sein, wenn jemand keine n-Tier-Architektur hat oder Webbibliotheken gemeinsam genutzt werden. Wie wir die Zeitzonen-ID für die Datenschicht freigeben können.
Vikash Kumar

9

Im Abschnitt "Ereignisse" auf sf4answers geben Benutzer eine Adresse für ein Ereignis sowie ein Startdatum und ein optionales Enddatum ein. Diese Zeiten werden in einen datetimeoffsetIn-SQL-Server übersetzt, der den Versatz von UTC berücksichtigt.

Dies ist das gleiche Problem, mit dem Sie konfrontiert sind (obwohl Sie einen anderen Ansatz wählen, indem Sie es verwenden DateTime.UtcNow). Sie haben einen Ort und müssen eine Zeit von einer Zeitzone in eine andere übersetzen.

Es gibt zwei wichtige Dinge, die ich getan habe und die für mich funktioniert haben. Verwenden Sie zunächst immer die DateTimeOffsetStruktur . Es berücksichtigt den Offset von UTC und wenn Sie diese Informationen von Ihrem Kunden erhalten können, erleichtert es Ihnen das Leben ein wenig.

Zweitens können Sie bei der Durchführung der Übersetzungen unter der Annahme, dass Sie den Ort / die Zeitzone kennen, in der sich der Client befindet, die Zeitzonendatenbank für öffentliche Informationen verwenden , um eine Zeit von UTC in eine andere Zeitzone zu übersetzen (oder, wenn Sie so wollen, zwischen zwei zu triangulieren Zeitzonen). Das Tolle an der tz-Datenbank (manchmal auch als Olson-Datenbank bezeichnet ) ist, dass sie die Änderungen der Zeitzonen im Laufe der Geschichte berücksichtigt. Das Erhalten eines Versatzes ist eine Funktion des Datums, an dem Sie den Versatz erhalten möchten (siehe den Energy Policy Act von 2005, der die Daten geändert hat, an denen die Sommerzeit in den USA in Kraft tritt ).

Mit der vorliegenden Datenbank können Sie die .NET-API von ZoneInfo (tz-Datenbank / Olson-Datenbank) verwenden . Beachten Sie, dass es keine Binärdistribution gibt. Sie müssen die neueste Version herunterladen und selbst kompilieren.

Zum Zeitpunkt dieses Schreibens werden derzeit alle Dateien in der neuesten Datenverteilung analysiert (ich habe sie am 25. September gegen die Datei ftp://elsie.nci.nih.gov/pub/tzdata2011k.tar.gz ausgeführt) . 2011; im März 2017 erhalten Sie es über https://iana.org/time-zones oder über ftp://fpt.iana.org/tz/releases/tzdata2017a.tar.gz ).

Bei sf4answers wird die Adresse nach Erhalt der Adresse in eine Längen- / Breitengradkombination geokodiert und dann an einen Webdienst eines Drittanbieters gesendet, um eine Zeitzone abzurufen, die einem Eintrag in der tz-Datenbank entspricht. Von dort werden die Start- und Endzeiten in DateTimeOffsetInstanzen mit dem richtigen UTC-Offset konvertiert und dann in der Datenbank gespeichert.

Der Umgang damit auf SO und Websites hängt von der Zielgruppe und dem ab, was Sie anzeigen möchten. Wenn Sie bemerken, dass auf den meisten sozialen Websites (und SO sowie im Abschnitt "Ereignisse" auf sf4answers) Ereignisse in relativer Zeit angezeigt werden oder wenn ein absoluter Wert verwendet wird, ist dies normalerweise UTC.

Wenn Ihr Publikum jedoch Ortszeiten erwartet, ist die Verwendung DateTimeOffsetzusammen mit einer Erweiterungsmethode, bei der die Zeitzone für die Konvertierung benötigt wird, in Ordnung. Der SQL-Datentyp wird datetimeoffsetin .NET übersetzt, sodass DateTimeOffsetSie die universelle Zeit für die Verwendung der GetUniversalTimeMethode erhalten . Von dort aus verwenden Sie einfach die Methoden der ZoneInfoKlasse, um von UTC in die Ortszeit zu konvertieren (Sie müssen ein wenig arbeiten, um sie in eine zu verwandeln DateTimeOffset, aber es ist einfach genug, dies zu tun).

Wo soll die Transformation durchgeführt werden? Das sind Kosten, die Sie irgendwo bezahlen müssen , und es gibt keinen "besten" Weg. Ich würde mich jedoch für die Ansicht entscheiden, wobei der Zeitzonenversatz Teil des Ansichtsmodells ist, das der Ansicht präsentiert wird. Auf diese Weise müssen Sie Ihr Ansichtsmodell nicht ändern, wenn sich die Anforderungen für die Ansicht ändern, um die Änderung zu berücksichtigen. Sie JsonResultwürden einfach ein Modell mit dem und dem Versatz enthalten.IEnumerable<T>

Auf der Eingabeseite mit einem Modellbinder? Ich würde absolut keinen Weg sagen. Sie können nicht garantieren, dass alle Daten (jetzt oder in Zukunft) auf diese Weise transformiert werden müssen. Es sollte eine explizite Funktion Ihres Controllers sein, diese Aktion auszuführen. Wenn sich die Anforderungen ändern, müssen Sie nicht eine oder mehrere ModelBinderInstanzen optimieren , um Ihre Geschäftslogik anzupassen. und es ist Geschäftslogik, was bedeutet, dass es in der Steuerung sein sollte.


Vielen Dank für Ihre ausführliche Antwort. Ich hoffe, dass ich nicht unhöflich rüberkomme, aber dies hat meine Bedenken in Bezug auf ASP.NET MVC nicht wirklich beantwortet: Was ist mit Benutzereingaben (würde die Verwendung eines benutzerdefinierten Modellbinders ausreichen)? Und was ist am wichtigsten mit der Anzeige dieser Daten (in der lokalen Zeitzone des Benutzers)? Ich habe das Gefühl, dass die Erweiterungsmethode meinen Ansichten viel Gewicht verleihen wird, was unnötig erscheint.
TheCloudlessSky

1
@TheCloudlessSky: Siehe die letzten beiden Absätze meiner bearbeiteten Antwort. Persönlich denke ich, dass die Details, wo die Transformationen durchgeführt werden sollen, gering sind; Das Hauptproblem ist die tatsächliche Konvertierung und Speicherung der Datums- / Uhrzeitdaten (übrigens kann ich die Verwendung datetimeoffsetin SQL Server und DateTimeOffsetin .NET hier nicht genug betonen , sie vereinfachen die Dinge wirklich enorm), die .NET meiner Meinung nach nicht angemessen handhabt überhaupt aus den oben genannten Gründen. Wenn Sie ein Datum in NYC haben, das 2003 eingegeben wurde, und dann möchten, dass es 2011 in ein Datum in LA übersetzt wird, schlägt .NET in diesem Fall schwer fehl.
CasperOne

Das Problem , wenn kein Modellordner (oder keine Ebene vor der Aktion) verwendet wird, besteht darin, dass jeder Controller beim Arbeiten mit Datumsangaben nur sehr schwer zu testen ist (alle würden von der Datumskonvertierung abhängig sein). Dies würde es ermöglichen, Unit-Testdaten in UTC zu schreiben. Meine Anwendung hat Benutzer, die einem Profil zugeordnet sind (denken Sie an Ärzte / Sekretäre, die mit ihrer Praxis verbunden sind). Das Profil enthält die Zeitzoneninformationen. Daher ist es ziemlich einfach, die Zeitzone des aktuellen Benutzerprofils abzurufen und während der Bindung zu transformieren. Haben Sie andere Argumente dagegen? Danke für deinen Beitrag!
TheCloudlessSky

Der Fall dagegen ist, dass Ihre Tests die Testfälle nicht genau widerspiegeln würden. Ihre Eingabe erfolgt nicht in UTC, daher sollten Ihre Testfälle nicht für die Verwendung erstellt werden. Es sollten reale Daten mit Orten und allem verwendet werden (obwohl, wenn Sie die verwenden, DateTimeOffsetSie dies sehr mildern werden, IMO).
CasperOne

Ja - aber das bedeutet, dass jeder Test, der sich mit Daten befasst, dies berücksichtigen muss. Jede Aktion, die sich mit Datumsangaben befasst, wird immer in UTC konvertiert . Für mich ist dies ein Hauptkandidat für den Modellbinder und testen Sie dann den Modellbinder .
TheCloudlessSky

5

Dies ist nur meine Meinung. Ich denke, dass die MVC-Anwendung das Problem der Datenpräsentation vom Datenmodellmanagement trennen sollte. Eine Datenbank kann Daten in lokaler Serverzeit speichern, es ist jedoch eine Aufgabe der Präsentationsschicht, die Datenzeit mithilfe der Zeitzone des lokalen Benutzers zu rendern. Dies scheint mir das gleiche Problem wie I18N und Zahlenformat für verschiedene Länder zu sein. In Ihrem Fall sollte Ihre Anwendung die CultureZeitzone des Benutzers erkennen und die Ansicht ändern, in der unterschiedliche Text-, Zahlen- und Datumsdarstellungen angezeigt werden. Die gespeicherten Daten können jedoch dasselbe Format haben.


Vielen Dank für Ihre Antwort. Ja, das habe ich im Grunde beschrieben. Ich frage mich nur, wie dies mit MVC elegant erreicht werden kann. Die App speichert die Zeitzone des Benutzers als Teil seiner Kontoerstellung (sie wählen ihre Zeitzone aus). Das Problem besteht wiederum darin, wie die Daten in jeder Ansicht gerendert werden können, ohne sie (hoffentlich) mit den von mir erstellten Methoden verunreinigen zu müssen DateTimeExtensions.
TheCloudlessSky

Es gibt viele Möglichkeiten, dies zu tun. Eine besteht darin, die von Ihnen vorgeschlagenen Hilfsmethoden zu verwenden. Eine andere, möglicherweise komplexere, aber elegantere Methode ist die Verwendung eines Filters, der die Anforderungen und Antworten verarbeitet und die Datums- und Uhrzeitangabe konvertiert. Eine andere Möglichkeit besteht darin, ein benutzerdefiniertes Anzeigeattribut zu entwickeln, um die Felder vom Typ DateTime Ihres Ansichtsmodells mit Anmerkungen zu versehen.
Massimo Zerbini

Das sind die Dinge, nach denen ich gesucht habe. Wenn Sie sich mein OP ansehen, habe ich auch erwähnt, dass AutoMapper verwendet wird, um einige Verarbeitungsschritte durchzuführen, bevor Sie zum view / json-Ergebnis gehen, aber nachdem die Aktion ausgeführt wurde.
TheCloudlessSky

1

Erstellen Sie für die Ausgabe eine Anzeige- / Editorvorlage wie diese

@inherits System.Web.Mvc.WebViewPage<System.DateTime>
@Html.Label(Model.ToLocalTime().ToLongTimeString()))

Sie können sie basierend auf Attributen in Ihrem Modell binden, wenn nur bestimmte Modelle diese Vorlagen verwenden sollen.

Weitere Informationen zum Erstellen benutzerdefinierter Editorvorlagen finden Sie hier und hier .

Da Sie möchten, dass es sowohl für die Eingabe als auch für die Ausgabe funktioniert, würde ich alternativ empfehlen, ein Steuerelement zu erweitern oder sogar ein eigenes zu erstellen. Auf diese Weise können Sie sowohl die Ein- als auch die Ausgaben abfangen und den Text / Wert nach Bedarf konvertieren.

Dieser Link wird Sie hoffentlich in die richtige Richtung bringen, wenn Sie diesen Weg gehen möchten.

In jedem Fall ist es ein bisschen Arbeit, wenn Sie eine elegante Lösung suchen. Auf der positiven Seite, wenn Sie es einmal getan haben, können Sie es für die zukünftige Verwendung in Ihrer Codebibliothek aufbewahren!


Ich denke, benutzerdefinierte Anzeige- / Editor-Vorlagen und Ordner sind die eleganteste Lösung, da sie nach der Implementierung "nur funktionieren". Kein Entwickler muß etwas Besonderes wissen , um die Daten zu erhalten , richtig funktionieren nur benutzen DisplayForund EditorForund es wird jedes Mal arbeiten. +1
Kevin Stricker

17
Würde dies nicht die Zeit des Anwendungsservers und nicht die Zeit des Browsers wiedergeben?
Alex

0

Dies ist wahrscheinlich ein Vorschlaghammer, um eine Nuss zu knacken, aber Sie könnten eine Ebene zwischen der Benutzeroberfläche und der Business-Ebene einfügen, die Datumszeiten in zurückgegebenen Objektdiagrammen transparent in die Ortszeit und in eingegebenen Datums- / Uhrzeitparametern in UTC konvertiert.

Ich stelle mir vor, dass dies mit PostSharp oder einer Inversion des Kontrollcontainers erreicht werden könnte.

Persönlich würde ich einfach Ihre Datenzeiten explizit in der Benutzeroberfläche konvertieren ...

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.