Разбор строки даты в Голанге

Я попытался разобрать строку даты "2014-09-12T11:45:26.371Z" в go lang.

Код

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

время разбора "2014-11-12T11:47:39.489Z": месяц вне диапазона

Я получил эту ошибку.

Как разобрать эту строку даты?

8 ответов

Используйте точные номера макетов, описанные здесь, и хороший пост в блоге здесь.

так:

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)

дает:

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

Я знаю. Сногсшибательное. Также поймал меня впервые. Go просто не использует абстрактный синтаксис для компонентов datetime (YYYY-MM-DD), но это точные цифры (я думаю, что время первого коммита go Nope, согласно этому. Кто-нибудь знает?).

Как ответили, но сохранить набрав "2006-01-02T15:04:05.000Z" для макета вы можете использовать константу пакета RFC3339.

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

Макет для использования действительно "2006-01-02T15:04:05.000Z"описано в RickyA.
Это не "время первого коммита", а скорее мнемонический способ запоминания указанного макета.
Смотрите пкг / время:

Исходное время, используемое в макетах:

Mon Jan 2 15:04:05 MST 2006

который время Unix1136239445,
Поскольку MST - GMT-0700, отсчет времени можно рассматривать как

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

(1,2,3,4,5,6,7, при условии, что вы помните, что 1 - для месяца, а 2 - для дня, что непросто для европейца, такого как я, в формате даты день-месяц)

Как показано в " time.parse: почему golang неправильно анализирует время?", Этот макет (с использованием 1,2,3,4,5,6,7) должен точно соблюдаться.

Это довольно поздно для вечеринки, и на самом деле ничего не сказано о том, что еще не было сказано в той или иной форме, в основном по ссылкам выше, но я хотел дать резюме TL;DR тем, у кого меньше внимания:

Дата и время строки формата go очень важны. Это как Го знает, какое поле какое. Они обычно 1-9 слева направо следующим образом:

  • Январь / январь / январь / январь / 01 / _1 (и т. Д.) За месяц
  • 02 / _2 за день месяца
  • 15 / 03 / _3 / PM / P / pm /p для часа и меридиана (3 часа дня)
  • 04 / _4 минуты
  • 05 / _5 за секунды
  • 2006 / 06 год
  • -0700 / 07:00 / MST для часового пояса
  • .999999999 / .000000000 и т. Д. За неполные секунды (я думаю, что различие заключается в том, что удаляются завершающие нули)
  • Понедельник / понедельник - день недели (который на самом деле был 01-02-2006),

Поэтому не пишите "01-05-15" в качестве формата даты, если вы не хотите "Месяц-Второй-Час"

(... опять же, это было в основном резюме выше.)

Я предлагаю использовать постоянную time.RFC3339 из пакета времени. Вы можете проверить другие константы из пакета времени. https://golang.org/pkg/time/

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

Это может быть слишком поздно, но это для людей, которые могут наткнуться на эту проблему и могут захотеть использовать внешний пакет для разбора строки даты.

Я попытался найти библиотеки, и я нашел это:

https://github.com/araddon/dateparse

Пример из 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())
}

Для тех из вас, кто сталкивается с этим, используйте time.RFC3339 вместо строковой константы "2006-01-02T15:04:05.000Z". И вот почему:

      regDate := "2007-10-09T22:50:01.23Z"

layout1 := "2006-01-02T15:04:05.000Z"
t1, err := time.Parse(layout1, regDate)

if err != nil {
    fmt.Println("Static format doesn't work")
} else {
    fmt.Println(t1)
}

layout2 := time.RFC3339
t2, err := time.Parse(layout2, regDate)

if err != nil {
    fmt.Println("RFC format doesn't work") // You shouldn't see this at all
} else {
    fmt.Println(t2)
}

Это даст следующий результат:

      Static format doesn't work
2007-10-09 22:50:01.23 +0000 UTC

Вот ссылка на игровую площадку

Если вы работали с форматированием / анализом времени / даты на других языках, вы могли заметить, что другие языки используют специальные заполнители для форматирования времени / даты. Например, язык рубин использует

%d for day
%Y for year

и т.д. Golang, вместо использования кодов, подобных приведенным выше, использует заполнители формата даты и времени, которые выглядят только как дата и время. В Go используется стандартное время:

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

Итак, если вы заметили, что Go использует

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

Поэтому, например, для синтаксического анализа 2020-01-29, строка макета должна быть 06-01-02 или 2006-01-02.

Вы можете обратиться к полной таблице макетов заполнителей по этой ссылке - https://golangbyexample.com/parse-time-in-golang/

Другие вопросы по тегам