Розбір рядка дати в Go


138

Я спробував проаналізувати рядок дати "2014-09-12T11:45:26.371Z"в Go.

Код

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

Я отримав цю помилку:

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

Як я можу проаналізувати цей рядок дати?


Для майбутніх читачів я написав кілька вправ для практичного розбору дат github.com/soniah/date_practice
Соня Гамільтон

Ваш макет повинен точно бути 2006-01-02T15:04:05.000Zобумовлений деяким шаленим стандартом
tharinduwijewardane

Відповіді:


164

Використовуйте точні номери макета, описані тут, і приємний поштовий пост тут .

так:

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, відповідно до цього . Хтось знає?).


118
Номери макета? Що? Чому? Арг!
Дарт Егрегійний

29
Що вони думали! ? чи куріння?
Jishnu Prathap

14
Я можу трохи запізнитися з коментарями тут, але не бійтеся макета з цифрами, просто використовуйте константи, і ваш код буде чистим :), наприклад, час.RFC3339
Давид Джахаєв,

11
Для тих, хто не отримує номери макета, я визнаю, що це на перший погляд дуже чуже, але як тільки ти звикнеш до цього, я думаю, що це має принаймні такий же сенс, як і типові пристрої компонування ("Чи я використовую" D ", "d", "dd", "DD" тощо), і, мабуть, більше сенсу. Ви просто повинні знати про це спочатку.
три вечора

5
Це з мнемонічною метою, тобто вам просто потрібно запам'ятати 1, 2, 3, 4, 5, 6, 7 цих листів. Є чудова стаття, яка обговорює це: medium.com/@simplyianm/…
amigcamel

85

Макет використання дійсно « 2006-01-02T15:04:05.000Z» описано в RickyA «s відповідь .
Це не "час першого вчинення руху", а скоріше мнемонічний спосіб запам'ятати згаданий макет.
Див. Кг / час :

Референтний час, який використовується в макетах:

Mon Jan 2 15:04:05 MST 2006

який час Unix 1136239445.
Оскільки MST є GMT-0700, опорний час можна вважати таким

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

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

Як проілюстровано у " time.parse: чому голанг неправильно розбирає час? ", Цей макет (використовуючи 1,2,3,4,5,6,7) повинен дотримуватися точно .


Так, це теж виганяє австралійців! MM / DD просто не розраховує для мене, і я повинен продовжувати дивитися на це.
Саймон Уайтхед

3
@SimonWhitehead Я згоден. Принаймні, як тільки я перегляну його, я знаю, на чому позначаються YY, MM, DD, hh, mm, ss, і я можу їх легко замовити легко. Навіть подивившись на це Go, мені потрібно запам'ятати, що означають 1, 2, 3, 4 ...
VonC

1
Наскільки я пам'ятаю це: Крок 1) «правильна» дата впорядкованість року> місяць> день> годинник> хвилини> другий> і т.д. (Оскільки змішано-молодшому просто бути не sensically довільної і непослідовною і дати big- ендіан є кращим, ніж маленький ендіан, тому що це дружньо.) Це отримає нас 1 (рік), 2 (місяць), 3 (день), [...] Крок 2) Перехід / Google є американцями, а американці ставлять свої рік наприкінці їх дат, тому замість цього 1 (місяць), 2 (день), [...], n (рік) Крок 3. Часовий пояс продовжується після всього іншого, оскільки часові пояси є додатковим шаром абстракції.
mtraceur

@mtraceur Так ... Я теж сумую за web.archive.org/web/20180501100155/http://… (від github.com/bdotdub/fuckinggodateformat ). Я маю на увазі, strftimeFTW.
VonC

58

Як відповів, але щоб зберегти набір тексту "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


1
Крім того, якщо ви подивитеся на константи пакета (пов’язані у відповіді вище), є ще ряд інших поширених форматів, які можна використовувати. Якщо вам потрібно щось трохи інше, використовуйте їх як вихідну точку.
Х'ю

Цей і кілька відповідей рекомендують 2006-01-02T15:04:05.000Zі згадують, що Go's time.RFC3339також працював. Але time.RFC3339 = "2006-01-02T15:04:05Z07:00". Є чи ці два формати точно еквівалентні , оскільки то , що time.Parseі time.ParseInLocationбуде робити?
Майлз

1
Правильно @Miles, цей тест підтверджує це play.golang.org/p/T3dW1kTeAHl
robstarbuck

24

Я запропоную використовувати time.RFC3339 константу з пакету часу. Ви можете перевірити інші константи з пакету часу. 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); 
}

Ви мали на увазі використовувати крапки з комою?
ChristoKiwi

20

Це доволі пізно до партії, і насправді не сказати нічого, про що вже не було сказано в тій чи іншій формі, в основному за посиланнями вище, але я хотів дати резюме TL; DR тим, хто має менший простір уваги:

Дата та час рядка формату go дуже важливі. Ось як Go знає, яке поле, яке. Вони, як правило, 1-9 зліва направо так:

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

Отже, не пишіть "01-05-15" як формат своєї дати, якщо ви не хочете "Місяць-другий час"

(... знову ж таки, це в основному було підсумком вище.)


5

Це може бути надто пізно, але це для людей, які можуть натрапити на цю проблему і, можливо, захочуть використовувати зовнішній пакет для розбору рядка дати.

Я спробував шукати бібліотеки, і знайшов цю:

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

2
На жаль, в порядку денного місяця існує неоднозначність. Європейський формат дати дає день перший і другий місяць, а американський часовий формат використовують зворотний. Така дата, як 5/5/2004, неоднозначна. Дата дійсна у американському та європейському форматі, але 3 та 5 можуть відповідати дню та місяцю або зворотно. dateParse припустимо формат США.
chmike

-1

Якщо ви працювали з форматуванням часу / дати / розбору іншими мовами, можливо, ви помітили, що інші мови використовують спеціальні заповнювачі для форматування часу / дати. Наприклад, використання рубінової мови

%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/

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.