Ich habe die folgende Zeichenfolge:

let dateString = "2018-04-18T04:54:00-04:00"

Ich initialisiere ein Date über das ISO8601DateForamtter wie folgt:

let formatter = ISO8601DateFormatter()
let date = formatter.date(from: dateString)

Wenn ich das Datum drucke, erhalte ich Folgendes:

Apr 18, 2018 at 1:54am

Der Formatierer konvertiert die Zeit automatisch in meine Ortszeit. Wie kann ich verhindern, dass meine Zeitzone berücksichtigt wird? Ich möchte beispielsweise, dass das Objekt Date stattdessen Folgendes anzeigt:

Apr 18, 2018 at 4:54am 
0
Kelvin Lau 18 Apr. 2018 im 00:39

5 Antworten

Beste Antwort

Mit ISO8601 bedeutet 2018-04-18T04:54:00-04:00 2018-04-18 04:54:00 in GMT -4h. Um die Uhrzeit so zu drucken, wie sie in der ursprünglichen Zeichenfolge enthalten ist, müssen Sie einen Datumsformatierer mit der spezifischen Zeitzone -4 erstellen.

let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: -4 * 60 * 60)
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dateFormatter.string(from: date))

Sie erhalten

2018-04-17 04:54:00

Zu Ihrer Information, ich füge einen Link für ISO8601 hinzu

1
Ryan 17 Apr. 2018 im 22:38

Sie müssen die Zeitzone aus Ihrer Datumszeichenfolge analysieren und damit die Zeitzone aus Ihrem Datumsformatierer festlegen:

func secondsFromGMT(from string: String) -> Int {
    guard !string.hasSuffix("Z") else { return 0 }
    let timeZone = string.suffix(6)
    let comps = timeZone.components(separatedBy: ":")
    guard let hours = comps.first,
        let minutes = comps.last,
        let hr = Int(hours),
        let min = Int(minutes) else { return 0 }
    return hr * 3600 + min * 60
}

let dateString = "2018-04-18T04:54:00-04:00"

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
formatter.locale = Locale(identifier: "en_US_POSIX")
if let dateFromString = formatter.date(from: dateString) {
    formatter.timeZone = TimeZone(secondsFromGMT: secondsFromGMT(from: dateString))
    formatter.dateFormat = "MMM dd, yyyy 'at' h:mma"
    formatter.amSymbol = "am"
    formatter.pmSymbol = "pm"
    print(formatter.string(from: dateFromString))  // Apr 18, 2018 at 4:54am
}
1
Leo Dabus 17 Apr. 2018 im 22:31

Anstatt die Date direkt zu protokollieren, sehen Sie sich die string(from:timeZone:formatOptions:) -Methode auf ISO8601DateFormatter an. Damit sollten Sie in der Lage sein, eine Datumszeichenfolge für jede gewünschte Zeitzone zu erhalten.

0
Charles Srstka 17 Apr. 2018 im 21:44

Sie sollten Ihren Formatierer auf die entsprechende Zeitzone einstellen, z. B. (UTC-Beispiel unten):

formatter.timeZone = TimeZone(identifier: "UTC")

Oder alternativ gegen GMT angeben:

formatter.timeZone = TimeZone(secondsFromGMT: 0)
0
Shawn 17 Apr. 2018 im 21:48

Das Datum, das Sie von Ihrem aktuellen Formatierer erhalten, ist technisch korrekt. Es wird nicht empfohlen, das Datum wie in der aktuell akzeptierten Antwort beschrieben rückwärts einzustellen, da Sie eine beabsichtigte Zeitzone effektiv hart codieren. Sobald Ihr Gerät eine andere Zeitzone betritt (oder wenn ein Benutzer Ihre App außerhalb der aktuellen Zeitzone herunterlädt), sind Ihre Informationen falsch.

Wenn Sie versuchen, diese Zeit in der UTC-Zeitzone anzuzeigen , müssen Sie einen anderen Formatierer verwenden, um die Ausgabe in der Zielzeitzone korrekt zu formatieren.

let utcFormatter = DateFormatter()
utcFormatter.timeZone = TimeZone(secondsFromGMT: 0)
// Perform any other transformations you'd like
let output = utcFormatter.string(from: date)

Aber warum ist Ihr ursprüngliches Datum korrekt?

Die Date API ist unglaublich robust und erledigt viele Dinge unter der Haube, wird aber effektiv mit einem einfachen Double implementiert. Die automatischen Zeitzoneninformationen, die Ihnen angezeigt werden, sind eine Abstraktion, um das Nachdenken zu erleichtern. Ein Datum weiß technisch nicht, in welcher Zeitzone es sich befindet. Wenn Sie es jedoch in eine Zeichenfolge konvertieren, wird implizit ein abgeleiteter Datumsformatierer auf das Datum angewendet und Informationen zurückgegeben, die Ihrer Meinung nach für Sie am nützlichsten sind.

Wenn Sie an einem Datum manipulieren, verwenden Sie wahrscheinlich die Calendar API. Normalerweise erhalten Sie eine neue Instanz, wenn Sie Calendar.current verwenden, wodurch ein neuer Kalender mit Ihren aktuellen Zeitzoneninformationen erstellt wird. Sie können die dargestellte Zeitzone des Kalenders folgendermaßen ändern:

var calendar = Calendar.current
calendar.timeZone = TimeZone(secondsFromGMT: 0)

Auf diese Weise erhalten Sie relative Daten, die in jeder Zeitzone funktionieren, ohne das Basisobjekt Date zu ändern, mit dem Sie arbeiten.

0
schrismartin 17 Apr. 2018 im 23:08