Analysieren der Datumszeichenfolge in Go


138

Ich habe versucht, die Datumszeichenfolge "2014-09-12T11:45:26.371Z"in Go zu analysieren .

Code

layout := "2014-09-12T11:45:26.371Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout , str)

Ich habe diesen Fehler erhalten:

Analysezeit "2014-11-12T11: 47: 39.489Z": Monat außerhalb des Bereichs

Wie kann ich diese Datumszeichenfolge analysieren?


Für zukünftige Leser schrieb ich einige Übungen zum Üben der Datumsanalyse github.com/soniah/date_practice
Sonia Hamilton

Ihr Layout sollte genau 2006-01-02T15:04:05.000Zauf einen verrückten Standard zurückzuführen sein
tharinduwijewardane

Antworten:


164

Verwenden Sie die hier beschriebenen genauen Layoutnummern und einen schönen Blogpost hier .

so:

layout := "2006-01-02T15:04:05.000Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout, str)

if err != nil {
    fmt.Println(err)
}
fmt.Println(t)

gibt:

>> 2014-11-12 11:45:26.371 +0000 UTC

Ich weiß. Verblüffend. Hat mich auch zum ersten Mal erwischt. Gehen Sie einfach nicht eine abstrakte Syntax für Datetime - Komponenten verwenden ( YYYY-MM-DD), aber diese genauen Zahlen ( ich denke , die Zeit von der ersten go begehen Nein, nach diesem . Wer weiß?).


118
Layoutnummern? Was? Warum? Argh!
Darth Egregious

29
Was dachten sie ! ? oder rauchen?
Jishnu Prathap

14
Ich bin vielleicht etwas spät dran mit Kommentaren hier, aber habe keine Angst vor dem Layout mit Zahlen, benutze einfach Konstanten und dein Code wäre sauber :) zB time.RFC3339
Davyd Dzhahaiev

11
Für diejenigen, die die Layoutnummern nicht erhalten, gebe ich zu, dass es auf den ersten Blick sehr fremd ist, aber wenn Sie sich erst einmal daran gewöhnt haben, macht es meiner Meinung nach mindestens so viel Sinn wie typische Layoutgeräte ('Benutze ich "D", "d", "dd", "DD" usw.?) und wahrscheinlich sinnvoller. Sie müssen es erst wissen.
drei

5
Es ist für mnemonische Zwecke, das heißt, Sie müssen sich nur 1, 2, 3, 4, 5, 6, 7 dieser Buchstaben merken. Es gibt einen großartigen Artikel darüber: medium.com/@simplyianm/…
amigcamel

85

Das Layout zu verwenden ist in der Tat „ 2006-01-02T15:04:05.000Z“ beschrieben in RickyA ‚s Antwort .
Es ist nicht "die Zeit des ersten Commits von go", sondern eine mnemonische Art, sich an das Layout zu erinnern.
Siehe pkg / time :

Die in den Layouts verwendete Referenzzeit ist:

Mon Jan 2 15:04:05 MST 2006

Das ist Unix-Zeit 1136239445.
Da MST GMT-0700 ist, kann die Referenzzeit als betrachtet werden

 01/02 03:04:05PM '06 -0700

(1,2,3,4,5,6,7, vorausgesetzt Sie erinnern sich, dass 1 für den Monat und 2 für den Tag ist, was für einen Europäer wie mich nicht einfach ist und an das Tag-Monat-Datumsformat gewöhnt ist)

Wie in dargestellt „ time.parse: warum tut golang falsch die Zeit analysiert? “, Das Layout (mit 1,2,3,4,5,6,7) müssen beachtet werden genau .


Ja, das bringt auch Australier raus! MM / DD berechnet einfach nicht für mich und ich muss es weiter betrachten.
Simon Whitehead

3
@ SimonWhitehead Ich stimme zu. Zumindest weiß ich nach dem Nachschlagen, wofür JJ, MM, TT, hh, mm, ss stehen, und kann sie problemlos nachbestellen. Bei Go muss ich mich auch nach dem Nachschlagen daran erinnern, wofür 1, 2, 3, 4 ... stehen.
VonC

1
Ich erinnere mich daran wie folgt: Schritt 1) Die "richtige" Datumsreihenfolge ist Jahr> Monat> Tag> Stunde> Minute> Sekunde> usw. (Weil Mixed-Endian einfach unsinnig willkürlich und inkonsistent wäre und für Daten groß- Endian ist Little Endian vorzuziehen, weil es sortierfreundlich ist.) Dies würde uns 1 (Jahr), 2 (Monat), 3 (Tag), [...] Schritt 2) Go / Google sind Amerikaner und Amerikaner setzen ihre Jahr am Ende ihrer Daten, also stattdessen 1 (Monat), 2 (Tag), [...], n (Jahr) Schritt 3) Die Zeitzone folgt allem anderen, da Zeitzonen eine zusätzliche Abstraktionsschicht sind.
mtraceur

@mtraceur Ja ... ich vermisse auch web.archive.org/web/20180501100155/http://… (von github.com/bdotdub/fuckinggodateformat ). Ich meine, strftimeFTW.
VonC

58

Wie beantwortet, aber um das Eingeben "2006-01-02T15:04:05.000Z"für das Layout zu sparen , können Sie die Konstante RFC3339 des Pakets verwenden .

str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(time.RFC3339, str)

if err != nil {
    fmt.Println(err)
}
fmt.Println(t)

https://play.golang.org/p/Dgu2ZvHwTh


1
Wenn Sie sich die Paketkonstanten ansehen (in der obigen Antwort verlinkt), stehen außerdem eine Reihe anderer gängiger Formate zur Verfügung, die verwendet werden können. Wenn Sie etwas anderes benötigen, verwenden Sie es als Ausgangspunkt.
Hugh

Diese und mehrere Antworten empfehlen 2006-01-02T15:04:05.000Zund erwähnen, dass Go's time.RFC3339auch funktionieren würde. Aber time.RFC3339 = "2006-01-02T15:04:05Z07:00". Sind diese beiden Formate insofern genau gleichwertig, als was time.Parseund was time.ParseInLocationsie tun werden?
Meilen

1
Das ist richtig @Miles, dieser Test bestätigt es play.golang.org/p/T3dW1kTeAHl
robstarbuck

24

Ich werde vorschlagen, die Konstante time.RFC3339 aus dem Zeitpaket zu verwenden. Sie können andere Konstanten aus dem Zeitpaket überprüfen. https://golang.org/pkg/time/#pkg-constants

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Time parsing");
    dateString := "2014-11-12T11:45:26.371Z"
    time1, err := time.Parse(time.RFC3339,dateString);
    if err!=nil {
    fmt.Println("Error while parsing date :", err);
    }
    fmt.Println(time1); 
}

Wollten Sie Semikolons verwenden?
ChristoKiwi

20

Dies ist ziemlich spät für die Party und sagt nicht wirklich etwas, was noch nicht in der einen oder anderen Form gesagt wurde, meistens über die obigen Links, aber ich wollte denjenigen mit weniger Aufmerksamkeitsspanne eine TL; DR-Zusammenfassung geben:

Das Datum und die Uhrzeit der Go-Format-Zeichenfolge sind sehr wichtig. So weiß Go, welches Feld welches ist. Sie sind in der Regel 1-9 von links nach rechts wie folgt:

  • Januar / Januar / Januar / Januar / 01 / _1 (usw.) sind für Monat
  • 02 / _2 sind für Tag des Monats
  • 15/03 / _3 / PM / P / pm / p sind für Stunde & Meridian (15 Uhr)
  • 04 / _4 sind für Minuten
  • 05 / _5 sind für Sekunden
  • 2006/06 sind für das Jahr
  • -0700 / 07:00 / MST sind für die Zeitzone
  • .999999999 / .000000000 usw. sind für Teilsekunden (ich denke, der Unterschied besteht darin, ob nachgestellte Nullen entfernt werden).
  • Mo / Montag sind Wochentage (was eigentlich der 01-02-2006 war),

Schreiben Sie also nicht "01-05-15" als Datumsformat, es sei denn, Sie möchten "Monat-Sekunde-Stunde".

(... wieder war dies im Grunde eine Zusammenfassung von oben.)


5

Dies kann sehr spät sein, ist jedoch für Personen gedacht, die über dieses Problem stolpern und möglicherweise ein externes Paket zum Parsen von Datumszeichenfolgen verwenden möchten.

Ich habe versucht, nach einer Bibliothek zu suchen, und ich habe diese gefunden:

https://github.com/araddon/dateparse

Beispiel aus der README:

package main

import (
    "flag"
    "fmt"
    "time"

    "github.com/apcera/termtables"
    "github.com/araddon/dateparse"
)

var examples = []string{
    "May 8, 2009 5:57:51 PM",
    "Mon Jan  2 15:04:05 2006",
    "Mon Jan  2 15:04:05 MST 2006",
    "Mon Jan 02 15:04:05 -0700 2006",
    "Monday, 02-Jan-06 15:04:05 MST",
    "Mon, 02 Jan 2006 15:04:05 MST",
    "Tue, 11 Jul 2017 16:28:13 +0200 (CEST)",
    "Mon, 02 Jan 2006 15:04:05 -0700",
    "Thu, 4 Jan 2018 17:53:36 +0000",
    "Mon Aug 10 15:44:11 UTC+0100 2015",
    "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)",
    "12 Feb 2006, 19:17",
    "12 Feb 2006 19:17",
    "03 February 2013",
    "2013-Feb-03",
    //   mm/dd/yy
    "3/31/2014",
    "03/31/2014",
    "08/21/71",
    "8/1/71",
    "4/8/2014 22:05",
    "04/08/2014 22:05",
    "4/8/14 22:05",
    "04/2/2014 03:00:51",
    "8/8/1965 12:00:00 AM",
    "8/8/1965 01:00:01 PM",
    "8/8/1965 01:00 PM",
    "8/8/1965 1:00 PM",
    "8/8/1965 12:00 AM",
    "4/02/2014 03:00:51",
    "03/19/2012 10:11:59",
    "03/19/2012 10:11:59.3186369",
    // yyyy/mm/dd
    "2014/3/31",
    "2014/03/31",
    "2014/4/8 22:05",
    "2014/04/08 22:05",
    "2014/04/2 03:00:51",
    "2014/4/02 03:00:51",
    "2012/03/19 10:11:59",
    "2012/03/19 10:11:59.3186369",
    // Chinese
    "2014年04月08日",
    //   yyyy-mm-ddThh
    "2006-01-02T15:04:05+0000",
    "2009-08-12T22:15:09-07:00",
    "2009-08-12T22:15:09",
    "2009-08-12T22:15:09Z",
    //   yyyy-mm-dd hh:mm:ss
    "2014-04-26 17:24:37.3186369",
    "2012-08-03 18:31:59.257000000",
    "2014-04-26 17:24:37.123",
    "2013-04-01 22:43",
    "2013-04-01 22:43:22",
    "2014-12-16 06:20:00 UTC",
    "2014-12-16 06:20:00 GMT",
    "2014-04-26 05:24:37 PM",
    "2014-04-26 13:13:43 +0800",
    "2014-04-26 13:13:44 +09:00",
    "2012-08-03 18:31:59.257000000 +0000 UTC",
    "2015-09-30 18:48:56.35272715 +0000 UTC",
    "2015-02-18 00:12:00 +0000 GMT",
    "2015-02-18 00:12:00 +0000 UTC",
    "2017-07-19 03:21:51+00:00",
    "2014-04-26",
    "2014-04",
    "2014",
    "2014-05-11 08:20:13,787",
    // mm.dd.yy
    "3.31.2014",
    "03.31.2014",
    "08.21.71",
    //  yyyymmdd and similar
    "20140601",
    // unix seconds, ms
    "1332151919",
    "1384216367189",
}

var (
    timezone = ""
)

func main() {
    flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone")
    flag.Parse()

    if timezone != "" {
        // NOTE:  This is very, very important to understand
        // time-parsing in go
        loc, err := time.LoadLocation(timezone)
        if err != nil {
            panic(err.Error())
        }
        time.Local = loc
    }

    table := termtables.CreateTable()

    table.AddHeaders("Input", "Parsed, and Output as %v")
    for _, dateExample := range examples {
        t, err := dateparse.ParseLocal(dateExample)
        if err != nil {
            panic(err.Error())
        }
        table.AddRow(dateExample, fmt.Sprintf("%v", t))
    }
    fmt.Println(table.Render())
}

2
Leider gibt es eine Unklarheit in der Tages- und Monatsreihenfolge. Das europäische Datumsformat gibt den ersten Tag und den zweiten Monat an, und das US-Zeitformat verwendet das Gegenteil. Ein Datum wie der 05.03.2004 ist nicht eindeutig. Das Datum ist im US- und europäischen Format gültig, aber 3 und 5 können Tag und Monat oder umgekehrt entsprechen. dateParse nimmt das US-Format an.
Chmike

-1

Wenn Sie mit der Formatierung / Analyse von Uhrzeit / Datum in anderen Sprachen gearbeitet haben, haben Sie möglicherweise bemerkt, dass die anderen Sprachen spezielle Platzhalter für die Formatierung von Uhrzeit / Datum verwenden. Zum Beispiel für die Verwendung von Rubin

%d for day
%Y for year

usw. Golang verwendet anstelle von Codes wie oben Platzhalter für das Datums- und Uhrzeitformat, die nur wie Datum und Uhrzeit aussehen. Go verwendet die Standardzeit:

Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
or 
01/02 03:04:05PM '06 -0700

Also, wenn Sie bemerken, dass Go verwendet

01 for the day of the month,
02 for the month
03 for hours,
04 for minutes
05 for second
and so on

Daher sollte zum Beispiel für das Parsen des 29.01.2018 die Layoutzeichenfolge 06-01-02 oder 2006-01-02 sein.

Sie können auf die vollständige Platzhalter-Layout-Tabelle unter diesem Link verweisen - https://golangbyexample.com/parse-time-in-golang/

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.