web-dev-qa-db-ja.com

Goでの日付文字列の解析

Goで日付文字列"2014-09-12T11:45:26.371Z"を解析してみました。

コード

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":範囲外の月

この日付文字列をどのように解析できますか?

103
kannanrbk

説明されている正確なレイアウト番号 こちら とNice blogpost こちら を使用してください。

そう:

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は日時コンポーネント(YYYY-MM-DD)に抽象構文を使用しませんが、これらの正確な数(Goの初回コミット時だと思います いや、 this によると。誰か知っている?)。

128
RickyA

使用するレイアウトは、 RickyAanswer で説明されている「2006-01-02T15:04:05.000Z」です。
それは「最初のコミットの時」ではなく、むしろそのレイアウトを覚えるためのニーモニックな方法です。
pkg/time :を参照してください。

レイアウトで使用される参照時間は次のとおりです。

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:golangはなぜ時間を間違って解析するのですか? "に示すように、そのレイアウト(1,2,3,4,5,6,7を使用)は尊重されなければなりません正確に

71
VonC

答えるがレイアウトのために"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

41
robstarbuck

これは当事者には間に合いません。そして、主に上記のリンクを通じて、何らかの形でまだ述べられていないことを実際には何も言っていませんが、私はTLに注意を向けたいと思いました。

Goフォーマット文字列の日時は非常に重要です。それは、Goがどのフィールドがどれであるかを知る方法です。それらは一般に次のように左から右へ1-9です。

  • 1月/ 1月/ 1月/ 1月/ 01/_1(その他)月
  • 02/_2は月の日です
  • 15/03/_3/PM/P/pm/pは時と子午線です(午後3時)
  • 04/_4は議事録です
  • 05/_5は秒です
  • 2006/06年は年です
  • -0700/07:00/MSTはタイムゾーンです
  • .999999999/.000000000などは部分的な秒です(区別は末尾のゼロが削除された場合と思います)
  • 月曜日/月曜日は曜日です(実際には2006年1月2日)

つまり、 "Month-Second-Hour"が欲しいのでなければ、 "01-05-15"をあなたの日付フォーマットとして書かないでください

(これも基本的に上記の要約です。)

12
Loren Osborn

Timeパッケージから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); 
}
10
Nishant Rawat

これは非常に遅いかもしれませんが、これはこの問題に遭遇するかもしれず、日付文字列を解析するために外部パッケージを使いたいかもしれない人々のためのものです。

私はライブラリを探してみましたが、私はこれを見つけました:

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())
}
4
Steven Ferrer