乐趣区

关于golang:Go-每日一库之-dateparse

简介

不论什么时候,解决工夫总是让人头疼的一件事件。因为工夫格局太多样化了,再加上时区,夏令时,闰秒这些细枝末节解决起来更是艰难。所以在程序中,波及工夫的解决咱们个别借助于规范库或第三方提供的工夫库。明天要介绍的 dateparse 专一于一个很小的工夫解决畛域——解析日期工夫格局的字符串。

疾速应用

本文代码应用 Go Modules。

创立目录并初始化:

$ mkdir dateparse && cd dateparse
$ go mod init github.com/darjun/go-daily-lib/dateparse

装置 dateparse 库:

$ go get -u github.com/araddon/dateparse

应用:

package main

import (
  "fmt"
  "log"
  "github.com/araddon/dateparse"
)

func main() {t1, err := dateparse.ParseAny("3/1/2014")
  if err != nil {log.Fatal(err)
  }
  fmt.Println(t1.Format("2006-01-02 15:04:05"))

  t2, err := dateparse.ParseAny("mm/dd/yyyy")
  if err != nil {log.Fatal(err)
  }
  fmt.Println(t2.Format("2006-01-02 15:04:05"))
}

ParseAny()办法承受一个日期工夫字符串,解析该字符串,返回 time.Time 类型的值。如果传入的字符串 dateparse 库无奈辨认,则返回一个谬误。下面程序运行输入:

$ go run main.go
2014-03-01 00:00:00
2021/06/24 14:52:39 Could not find format for "mm/dd/yyyy"
exit status 1

须要留神,当咱们写出 ”3/1/2014″ 这个工夫的时候,能够解释为 2014 年 3 月 1 日,也能够解释为2014 年 1 月 3 日。这就存在二义性,dateparse 默认采纳 mm/dd/yyyy 这种格局,也就是 2014 年 3 月 1 日。咱们也能够应用ParseStrict() 函数让这种具备二义性的字符串解析失败:

func main() {t, err := dateparse.ParseStrict("3/1/2014")
  if err != nil {log.Fatal(err)
  }
  fmt.Println(t.Format("2006-01-02 15:04:05"))
}

运行:

$ go run main.go
2021/06/24 14:57:18 This date has ambiguous mm/dd vs dd/mm type format
exit status 1

格局

dateparse反对丰盛的日期工夫格局,根本囊括了所有罕用的格局。它反对规范库 time 中预约义的所有格局:

// src/time/format.go
const (
  ANSIC       = "Mon Jan _2 15:04:05 2006"
  UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
  RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
  RFC822      = "02 Jan 06 15:04 MST"
  RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
  RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
  RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
  RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
  RFC3339     = "2006-01-02T15:04:05Z07:00"
  RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
  Kitchen     = "3:04PM"
  // Handy time stamps.
  Stamp      = "Jan _2 15:04:05"
  StampMilli = "Jan _2 15:04:05.000"
  StampMicro = "Jan _2 15:04:05.000000"
  StampNano  = "Jan _2 15:04:05.000000000"
)

反对的残缺格局查看 dateparse README。

时区

dateparse反对在特定时区解析日期工夫字符串。咱们能够通过调用规范库的 time.LoadLocation() 办法,传入时区标识字符串来取得时区对象。时区标识字符串是相似 Asia/ShanghaiAmerica/Chicago 这样的格局,它示意一个具体的时区,前者上海,后者洛杉矶。调用 dateparse.ParseIn() 办法传入时区对象,在指定时区中解析。time包中还预约义了两个时区对象,time.Local示意本地时区,time.UTC示意 UTC 时区。时区的权威数据请看 IANA。

func main() {tz1, _ := time.LoadLocation("America/Chicago")
  t1, _ := dateparse.ParseIn("2021-06-24 15:50:30", tz1)
  fmt.Println(t1.Local().Format("2006-01-02 15:04:05"))

  t2, _ := dateparse.ParseIn("2021-06-24 15:50:30", time.Local)
  fmt.Println(t2.Local().Format("2006-01-02 15:04:05"))
}

运行:

$ go run main.go
2021-06-25 04:50:30
2021-06-24 15:50:30

美国洛杉矶时区的 ”2021 年 6 月 24 日 15 时 30 分 30 秒 ” 等于本地时区(北京工夫)的 ”2021 年 6 月 25 日 04 时 50 分 30 秒 ”。

cli

dateparse还提供了一个命令行工具,用于极快地查看日期工夫格局。装置:

$ go install github.com/araddon/dateparse/dateparse

默认会装置在 $GOPATH 门路下,我习惯上把 $GOPATH/bin 放到 $PATH 中。所以 dateparse 命令能够间接应用。

dateparse命令接管一个字符串,和一个可选的时区选项:

$ dateparse --timezone="Asia/Shanghai" "2021-06-24 06:46:08"

Your Current time.Local zone is CST

Layout String: dateparse.ParseFormat() => 2006-01-02 15:04:05

Your Using time.Local set to location=Asia/Shanghai CST

+-------------+---------------------------+-------------------------------+-------------------------------------+
| method      | Zone Source               | Parsed                        | Parsed: t.In(time.UTC)              |
+-------------+---------------------------+-------------------------------+-------------------------------------+
| ParseAny    | time.Local = nil          | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseAny    | time.Local = timezone arg | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseAny    | time.Local = time.UTC     | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseIn     | time.Local = nil          | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseIn     | time.Local = timezone arg | 2021-06-24 06:46:08 +0800 CST | 2021-06-23 22:46:08 +0000 UTC       |
| ParseIn     | time.Local = time.UTC     | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseLocal  | time.Local = nil          | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseLocal  | time.Local = timezone arg | 2021-06-24 06:46:08 +0800 CST | 2021-06-23 22:46:08 +0000 UTC       |
| ParseLocal  | time.Local = time.UTC     | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseStrict | time.Local = nil          | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseStrict | time.Local = timezone arg | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
| ParseStrict | time.Local = time.UTC     | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC       |
+-------------+---------------------------+-------------------------------+-------------------------------------+

输入以后本地时区,格局字符串(可用于生成同样格局的日期工夫字符串)和一个表格。表格外面的数据是别离对 ParseAny/ParseIn/ParseLocal/ParseStrict 在不同的时区下调用的后果。

method列示意调用的办法,Zone Source列示意将本地时区设置的值,Parsed列是以日期工夫字符串调用 ParseAny() 返回的 time.Time 对象的 Format() 办法调用后果,Parsed: t.In(time.UTC)列在返回的 time.Time 对象调用 Format() 办法前将其转为 UTC 工夫。

因为 ParseAny/ParseStrict 不会思考本地时区,都是在 UTC 下解析字符串,所以这 6 行的最初两列后果都一样。

ParseIn的第二行,将 time.Local 设置为咱们通过命令行选项设置的时区,下面我设置为 Asia/Shanghai,对应的 UTC 工夫相差 8 小时。ParseLocal 也是如此。

上面是 dateparse 命令行的局部源码,能够对照查看:

func main() {parsers := map[string]parser{
    "ParseAny":    parseAny,
    "ParseIn":     parseIn,
    "ParseLocal":  parseLocal,
    "ParseStrict": parseStrict,
  }

  for name, parser := range parsers {
    time.Local = nil
    table.AddRow(name, "time.Local = nil", parser(datestr, nil, false), parser(datestr, nil, true))
    if timezone != "" {
      time.Local = loc
      table.AddRow(name, "time.Local = timezone arg", parser(datestr, loc, false), parser(datestr, loc, true))
    }
    time.Local = time.UTC
    table.AddRow(name, "time.Local = time.UTC", parser(datestr, time.UTC, false), parser(datestr, time.UTC, true))
  }
}

func parseIn(datestr string, loc *time.Location, utc bool) string {t, err := dateparse.ParseIn(datestr, loc)
  if err != nil {return err.Error()
  }
  if utc {return t.In(time.UTC).String()}
  return t.String()}

留神输入的本地时区为 CST,它能够代表不同的时区:

Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00

CST 能够同时示意美国、澳大利亚、中国和古巴四个国家的规范工夫。

总结

应用 dateparse 能够很不便地从日期工夫字符串中解析出工夫对象和格局(layout)。同时 dateparse 命令行能够疾速的查看和转换相应时区的工夫,是一个十分不错的小工具。

大家如果发现好玩、好用的 Go 语言库,欢送到 Go 每日一库 GitHub 上提交 issue😄

参考

  1. dateparse GitHub:github.com/araddon/dateparse
  2. Go 每日一库 GitHub:https://github.com/darjun/go-daily-lib

我的博客:https://darjun.github.io

欢送关注我的微信公众号【GoUpUp】,独特学习,一起提高~

退出移动版