一線開發人員天天都要使用日期和時間相關的功能,各類定時器,活動時間處理等。標準庫time使用起來不太靈活,特別是日期時間的建立和運算。carbon庫是一個時間擴展庫,基於 PHP 的carbon庫編寫。提供易於使用的接口。本文就來介紹一下這個庫。git
第三方庫須要先安裝:github
$ go get github.com/uniplaces/carbon
複製代碼
後使用:golang
package main
import (
"fmt"
"time"
"github.com/uniplaces/carbon"
)
func main() {
fmt.Printf("Right now is %s\n", carbon.Now().DateTimeString())
today, _ := carbon.NowInLocation("Japan")
fmt.Printf("Right now in Japan is %s\n", today)
fmt.Printf("Tomorrow is %s\n", carbon.Now().AddDay())
fmt.Printf("Last week is %s\n", carbon.Now().SubWeek())
nextOlympics, _ := carbon.CreateFromDate(2016, time.August, 5, "Europe/London")
nextOlympics = nextOlympics.AddYears(4)
fmt.Printf("Next olympics are in %d\n", nextOlympics.Year())
if carbon.Now().IsWeekend() {
fmt.Printf("Happy time!")
}
}
複製代碼
carbon
庫的使用很便捷,首先它徹底兼容標準庫的time.Time
類型,實際上該庫的日期時間類型Carbon
直接將time.Time
內嵌到結構中,因此time.Time
的方法可直接調用:編程
// src/github.com/uniplaces/carbon/carbon.go
type Carbon struct {
time.Time
weekStartsAt time.Weekday
weekEndsAt time.Weekday
weekendDays []time.Weekday
stringFormat string
Translator *Translator
}
複製代碼
其次,簡化了建立操做。標準庫time
建立一個Time
對象,若是不是本地或 UTC 時區,須要本身先調用LoadLocation
加載對應時區。而後將該時區對象傳給time.Date
方法建立。carbon
能夠直接傳時區名字。bash
carbon
還提供了不少方法作日期運算,如例子中的AddDay
,SubWeek
等,都是見名知義的。微信
在介紹其它內容以前,咱們先說一說這個時區的問題。如下引用維基百科的描述:app
時區是地球上的區域使用同一個時間定義。之前,人們經過觀察太陽的位置(時角)決定時間,這就使得不一樣經度的地方的時間有所不一樣(地方時)。1863年,首次使用時區的概念。時區經過設立一個區域的標準時間部分地解決了這個問題。 世界各國位於地球不一樣位置上,所以不一樣國家,特別是東西跨度大的國家日出、日落時間一定有所誤差。這些誤差就是所謂的時差。less
例如,日本東京位於東九區,北京位於東八區,因此日本比中國快一個小時,日本14:00的時候中國13:00。編程語言
在 Linux 中,時區通常存放在相似/usr/share/zoneinfo
這樣的目錄。這個目錄中有不少文件,每一個時區一個文件。時區文件是二進制文件,能夠執行info tzfile
查看具體格式。學習
時區名稱的通常格式爲city
,或country/city
,或continent/city
。即要麼就是一個城市名,要麼是國家名+/+城市名,要麼是洲名+/+城市名。例如上海時區爲Asia/Shanghai
,香港時區爲Asia/Hong_Kong
。也有一些特殊的,如 UTC,Local等。
Go 語言爲了可移植性,在安裝包中提供了時區文件,在安裝目錄下(個人爲C:\Go
)的lib/time/zoneinfo.zip
文件,你們能夠執行解壓看看😀。
使用 Go 標準庫time
建立某個時區的時間,須要先加載時區:
package main
import (
"fmt"
"log"
"time"
)
func main() {
loc, err := time.LoadLocation("Japan")
if err != nil {
log.Fatal("failed to load location: ", err)
}
d := time.Date(2020, time.July, 24, 20, 0, 0, 0, loc)
fmt.Printf("The opening ceremony of next olympics will start at %s in Japan\n", d)
}
複製代碼
使用carbon
就不用這麼麻煩:
package main
import (
"fmt"
"log"
"time"
"github.com/uniplaces/carbon"
)
func main() {
c, err := carbon.Create(2020, time.July, 24, 20, 0, 0, 0, "Japan")
if err != nil {
log.Fatal(err)
}
fmt.Printf("The opening ceremony of next olympics will start at %s in Japan\n", c)
}
複製代碼
使用標準庫time
的時間運算須要先定義一個time.Duration
對象,time
庫預約義的只有納秒到小時的精度:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
複製代碼
其它的時長就須要本身使用time.ParseDuration
構造了,並且time.ParseDuration
不能構造其它精度的時間。 若是想要增長/減小年月日,就須要使用time.Time
的AddDate
方法:
package main
import (
"fmt"
"log"
"time"
)
func main() {
now := time.Now()
fmt.Println("now is:", now)
fmt.Println("one second later is:", now.Add(time.Second))
fmt.Println("one minute later is:", now.Add(time.Minute))
fmt.Println("one hour later is:", now.Add(time.Hour))
d, err := time.ParseDuration("3m20s")
if err != nil {
log.Fatal(err)
}
fmt.Println("3 minutes and 20 seconds later is:", now.Add(d))
d, err = time.ParseDuration("2h30m")
if err != nil {
log.Fatal(err)
}
fmt.Println("2 hours and 30 minutes later is:", now.Add(d))
fmt.Println("3 days and 2 hours later is:", now.AddDate(0, 0, 3).Add(time.Hour*2))
}
複製代碼
須要注意的是,時間操做都是返回一個新的對象,原對象不會修改。carbon
庫也是如此。Go 的標準庫也建議咱們不要使用time.Time
的指針。 固然carbon
庫也能使用上面的方法,它還提供了多種粒度的方法:
package main
import (
"fmt"
"github.com/uniplaces/carbon"
)
func main() {
now := carbon.Now()
fmt.Println("now is:", now)
fmt.Println("one second later is:", now.AddSecond())
fmt.Println("one minute later is:", now.AddMinute())
fmt.Println("one hour later is:", now.AddHour())
fmt.Println("3 minutes and 20 seconds later is:", now.AddMinutes(3).AddSeconds(20))
fmt.Println("2 hours and 30 minutes later is:", now.AddHours(2).AddMinutes(30))
fmt.Println("3 days and 2 hours later is:", now.AddDays(3).AddHours(2))
}
複製代碼
carbon
還提供了:
AddQuarters/AddQuarter
,複數形式介紹一個表示倍數的參數,單數形式倍數爲1;AddCenturies/AddCentury
;AddWeekdays/AddWeekday
,這個方法會跳過非工做日;AddWeeks/AddWeek
。其實給上面方法傳入負數就表示減小,另外carbon
也提供了對應的Sub*
方法。
標準庫time
可使用time.Time
對象的Before/After/Equal
判斷是否在另外一個時間對象前,後,或相等。carbon
庫也可使用上面的方法比較時間。除此以外,它還提供了多組方法,每一個方法提供一個簡短名,一個詳細名:
Eq/EqualTo
:是否相等;Ne/NotEqualTo
:是否不等;Gt/GreaterThan
:是否在以後;Lt/LessThan
:是否在以前;Lte/LessThanOrEqual
:是否相同或在以前;Between
:是否在兩個時間之間。另外carbon
提供了:
IsMonday/IsTuesday/.../IsSunday
;IsWeekday/IsWeekend/IsLeapYear/IsPast/IsFuture
。package main
import (
"fmt"
"github.com/uniplaces/carbon"
)
func main() {
t1, _ := carbon.CreateFromDate(2010, 10, 1, "Asia/Shanghai")
t2, _ := carbon.CreateFromDate(2011, 10, 20, "Asia/Shanghai")
fmt.Printf("t1 equal to t2: %t\n", t1.Eq(t2))
fmt.Printf("t1 not equal to t2: %t\n", t1.Ne(t2))
fmt.Printf("t1 greater than t2: %t\n", t1.Gt(t2))
fmt.Printf("t1 less than t2: %t\n", t1.Lt(t2))
t3, _ := carbon.CreateFromDate(2011, 1, 20, "Asia/Shanghai")
fmt.Printf("t3 between t1 and t2: %t\n", t3.Between(t1, t2, true))
now := carbon.Now()
fmt.Printf("Weekday? %t\n", now.IsWeekday())
fmt.Printf("Weekend? %t\n", now.IsWeekend())
fmt.Printf("LeapYear? %t\n", now.IsLeapYear())
fmt.Printf("Past? %t\n", now.IsPast())
fmt.Printf("Future? %t\n", now.IsFuture())
}
複製代碼
咱們還可使用carbon
計算兩個日期之間相差多少秒、分、小時、天:
package main
import (
"fmt"
"github.com/uniplaces/carbon"
)
func main() {
vancouver, _ := carbon.Today("Asia/Shanghai")
london, _ := carbon.Today("Asia/Hong_Kong")
fmt.Println(vancouver.DiffInSeconds(london, true)) // 0
ottawa, _ := carbon.CreateFromDate(2000, 1, 1, "America/Toronto")
vancouver, _ = carbon.CreateFromDate(2000, 1, 1, "America/Vancouver")
fmt.Println(ottawa.DiffInHours(vancouver, true)) // 3
fmt.Println(ottawa.DiffInHours(vancouver, false)) // 3
fmt.Println(vancouver.DiffInHours(ottawa, false)) // -3
t, _ := carbon.CreateFromDate(2012, 1, 31, "UTC")
fmt.Println(t.DiffInDays(t.AddMonth(), true)) // 31
fmt.Println(t.DiffInDays(t.SubMonth(), false)) // -31
t, _ = carbon.CreateFromDate(2012, 4, 30, "UTC")
fmt.Println(t.DiffInDays(t.AddMonth(), true)) // 30
fmt.Println(t.DiffInDays(t.AddWeek(), true)) // 7
t, _ = carbon.CreateFromTime(10, 1, 1, 0, "UTC")
fmt.Println(t.DiffInMinutes(t.AddSeconds(59), true)) // 0
fmt.Println(t.DiffInMinutes(t.AddSeconds(60), true)) // 1
fmt.Println(t.DiffInMinutes(t.AddSeconds(119), true)) // 1
fmt.Println(t.DiffInMinutes(t.AddSeconds(120), true)) // 2
}
複製代碼
咱們知道time.Time
提供了一個Format
方法,相比於其餘編程語言使用格式化符來描述格式(須要記憶%d/%m/%h
等的含義),Go 提供了一個一種更簡單、直觀的方式——使用 layout。即咱們傳入一個日期字符串,表示咱們想要格式化成什麼樣子。Go 會用當前的時間替換字符串中的對應部分:
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
fmt.Println(t.Format("2006-01-02 10:00:00"))
}
複製代碼
上面咱們只須要傳入一個2006-01-02 10:00:00
表示咱們想要的格式爲yyyy-mm-dd hh:mm:ss
,省去了咱們須要記憶的麻煩。
爲了使用方便,Go 內置了一些標準的時間格式:
// 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"
)
複製代碼
除了上面這些格式,carbon
還提供了其餘一些格式:
// src/github.com/uniplaces/carbon
const (
DefaultFormat = "2006-01-02 15:04:05"
DateFormat = "2006-01-02"
FormattedDateFormat = "Jan 2, 2006"
TimeFormat = "15:04:05"
HourMinuteFormat = "15:04"
HourFormat = "15"
DayDateTimeFormat = "Mon, Aug 2, 2006 3:04 PM"
CookieFormat = "Monday, 02-Jan-2006 15:04:05 MST"
RFC822Format = "Mon, 02 Jan 06 15:04:05 -0700"
RFC1036Format = "Mon, 02 Jan 06 15:04:05 -0700"
RFC2822Format = "Mon, 02 Jan 2006 15:04:05 -0700"
RSSFormat = "Mon, 02 Jan 2006 15:04:05 -0700"
)
複製代碼
注意一點,time
庫默認使用2006-01-02 15:04:05.999999999 -0700 MST
格式,有點複雜了,carbon
庫默認使用更簡潔的2006-01-02 15:04:05
。
所謂修飾器(modifier)就是對一些特定的時間操做,獲取開始和結束時間。如當天、月、季度、年、十年、世紀、周的開始和結束時間,還能得到上一個周2、下一個周1、下一個工做日的時間等等:
package main
import (
"fmt"
"time"
"github.com/uniplaces/carbon"
)
func main() {
t := carbon.Now()
fmt.Printf("Start of day:%s\n", t.StartOfDay())
fmt.Printf("End of day:%s\n", t.EndOfDay())
fmt.Printf("Start of month:%s\n", t.StartOfMonth())
fmt.Printf("End of month:%s\n", t.EndOfMonth())
fmt.Printf("Start of year:%s\n", t.StartOfYear())
fmt.Printf("End of year:%s\n", t.EndOfYear())
fmt.Printf("Start of decade:%s\n", t.StartOfDecade())
fmt.Printf("End of decade:%s\n", t.EndOfDecade())
fmt.Printf("Start of century:%s\n", t.StartOfCentury())
fmt.Printf("End of century:%s\n", t.EndOfCentury())
fmt.Printf("Start of week:%s\n", t.StartOfWeek())
fmt.Printf("End of week:%s\n", t.EndOfWeek())
fmt.Printf("Next:%s\n", t.Next(time.Wednesday))
fmt.Printf("Previous:%s\n", t.Previous(time.Wednesday))
}
複製代碼
有些地區每週的開始、週末和咱們的不同。例如,在美國週日是新的一週開始。不要緊,carbon
能夠自定義每週的開始和週末:
package main
import (
"fmt"
"log"
"time"
"github.com/uniplaces/carbon"
)
func main() {
t, err := carbon.Create(2020, 02, 11, 0, 0, 0, 0, "Asia/Shanghai")
if err != nil {
log.Fatal(err)
}
t.SetWeekStartsAt(time.Sunday)
t.SetWeekEndsAt(time.Saturday)
t.SetWeekendDays([]time.Weekday{time.Monday, time.Tuesday, time.Wednesday})
fmt.Printf("Today is %s, weekend? %t\n", t.Weekday(), t.IsWeekend())
}
複製代碼
carbon
提供了不少的實用方法,另外time
的方法它也能使用,使得它的功能很是強大。時間實際上是一個很是複雜的問題,考慮到時區、閏秒、各地的夏令時等,本身處理起來簡直是火葬場。幸虧有這些庫(┬_┬)
歡迎關注個人微信公衆號【GoUpUp】,共同窗習,一塊兒進步~
本文由博客一文多發平臺 OpenWrite 發佈!