Go: 一些關於時間和定時任務的庫
避免重複發明輪子。如果有一些好用的庫,我們就直接使用就好了,沒必要做一些重複的工作,如果這些庫不能滿足需求,不妨提交 pull request 或者 clone 它們,提升它們,優化它們,當前前提是你得知道它們。
這篇文章給大家介紹一些關於時間和類似 linux cron 功能的定時任務庫。
jinzhu/now
張金柱大佬除了給大家貢獻了 gorm 外,還寫了一些好用的 Go 庫, jinzhu/now[1] 就是之一。
當前,Go 標準庫提供了關於時間的庫 time[2],可以滿足我們 80% 的場景,但是對於一些特殊的場景,使用標準庫卻很麻煩,其它一些編程語言也是這樣,標準庫中的時間相關的函數在一些特殊場景下不方便使用,金柱提供的 now 庫滿足了一些特殊場景的需求,使用起來特別的方便。
這個庫最重要的函數我把它分成兩類:
-
計算第一天和最後一天的函數
-
解析
當然它還包含求四季,以及明確求週日週一的函數 (有的國家和地區星期天算一週的開始、有的週一算一週的開始),這更少用了,我們就不介紹了。
計算開始和最後時刻的函數
給定一個時間,你可以得到這個時刻的此分鐘開始的時刻、此小時開始的時刻、此天的開始的時刻、此周開始的時刻、此月開始的時刻、此季節開始的時刻、此半年開始的時刻,此年開始的時刻:
import "github.com/jinzhu/now"
time.Now() // 2013-11-18 17:51:49.123456789 Mon
now.BeginningOfMinute() // 2013-11-18 17:51:00 Mon
now.BeginningOfHour() // 2013-11-18 17:00:00 Mon
now.BeginningOfDay() // 2013-11-18 00:00:00 Mon
now.BeginningOfWeek() // 2013-11-17 00:00:00 Sun
now.BeginningOfMonth() // 2013-11-01 00:00:00 Fri
now.BeginningOfQuarter() // 2013-10-01 00:00:00 Tue
now.BeginningOfYear() // 2013-01-01 00:00:00 Tue
或者這個時刻的此分鐘最後的時刻、此小時最後的時刻、此天的最後的時刻、此周最後的時刻、此月最後的時刻、此季節最後的時刻、此半年最後的時刻,此年最後的時刻:
now.EndOfMinute() // 2013-11-18 17:51:59.999999999 Mon
now.EndOfHour() // 2013-11-18 17:59:59.999999999 Mon
now.EndOfDay() // 2013-11-18 23:59:59.999999999 Mon
now.EndOfWeek() // 2013-11-23 23:59:59.999999999 Sat
now.EndOfMonth() // 2013-11-30 23:59:59.999999999 Sat
now.EndOfQuarter() // 2013-12-31 23:59:59.999999999 Tue
now.EndOfYear() // 2013-12-31 23:59:59.999999999 Tue
now.WeekStartDay = time.Monday // 設置 Monday 作爲每週的第一天, 默認星期天是一週的第一天
now.EndOfWeek() // 2013-11-24 23:59:59.999999999 Sun
如果你是求當前時刻的開始時刻和結束時刻,你可以使用包的函數,它提供了便利的函數,比如當前小時的開始時刻:
_ = time.BeginningOfHour()
它實際的實現是:
func BeginningOfHour() time.Time {
return With(time.Now()).BeginningOfHour()
}
你還可以設置特定的時區、日期格式和每週的開始的第一天是星期一還是星期天:
myConfig := &now.Config{
WeekStartDay: time.Monday,
TimeLocation: location,
TimeFormats: []string{"2006-01-02 15:04:05"},
}
t := time.Date(2013, 11, 18, 17, 51, 49, 123456789, time.Now().Location()) // // 2013-11-18 17:51:49.123456789 Mon
myConfig.With(t).BeginningOfWeek() // 2013-11-18 00:00:00 Mon
日期解析
標註庫的日期解析方式是以樣本的方式提供的,比如2006-01-02 15:04:05
, 這種解析方法比較特殊,經常我們需要查看幫助文檔才能正確設置想起的格式,而且解析的時候容錯能力不是太好。
jizhu/now
庫提供了一種容錯式的解析方式,它會遍歷標準庫的時間格式 [3],嘗試使用其中的一種格式進行解析。它的處理方式有遍歷和正則表達式,所以如果是在追求性能和日期格式比較明確的情況下,用標準庫的解析就好,但是如果不追求極致的性能,這個解析能很好的容錯,你不需要記住格式模板,輸入一個日期字符串它就能解析。(哦覺得它還可以做一個優化,除了標準庫提供的日期格式外,允許用戶提供特定的日期格式模板,並且設定優先級)
// Parse(string) (time.Time, error)
t, err := now.Parse("2017") // 2017-01-01 00:00:00, nil
t, err := now.Parse("2017-10") // 2017-10-01 00:00:00, nil
t, err := now.Parse("2017-10-13") // 2017-10-13 00:00:00, nil
t, err := now.Parse("1999-12-12 12") // 1999-12-12 12:00:00, nil
t, err := now.Parse("1999-12-12 12:20") // 1999-12-12 12:20:00, nil
t, err := now.Parse("1999-12-12 12:20:21") // 1999-12-12 12:20:21, nil
t, err := now.Parse("10-13") // 2013-10-13 00:00:00, nil
t, err := now.Parse("12:20") // 2013-11-18 12:20:00, nil
t, err := now.Parse("12:20:13") // 2013-11-18 12:20:13, nil
t, err := now.Parse("14") // 2013-11-18 14:00:00, nil
t, err := now.Parse("99:99") // 2013-11-18 12:20:00, Can't parse string as time: 99:99
// MustParse must parse string to time or it will panic
now.MustParse("2013-01-13") // 2013-01-13 00:00:00
now.MustParse("02-17") // 2013-02-17 00:00:00
now.MustParse("2-17") // 2013-02-17 00:00:00
now.MustParse("8") // 2013-11-18 08:00:00
now.MustParse("2002-10-12 22:14") // 2002-10-12 22:14:00
now.MustParse("99:99") // panic: Can't parse string as time: 99:99
carbon
carbon 是另外一個日期 / 時間擴展庫。很多語言都有一個兼做 carbon 的日期擴展庫,比如 javascript、php、python、rust 等等。Go 語言這也不止一個,這裏我介紹的是 golang-module/carbon[4]golang-module/carbon 是一個輕量級、語義化、對開發者友好的 golang 時間處理庫,支持鏈式調用,由夠過癮 [5] 開發。
它提供了非常豐富的函數,看的我老眼昏花。它提供的函數大致分爲幾類。
創建 carbon 實例
根據參數的不同,創建的方式很多,下面只是列出了幾種創建的方法:
carbon.CreateFromTimestamp(0).ToString() // 1970-01-01 08:00:00 +0800 CST
carbon.CreateFromTimestampMilli(1649735755981).ToString() // 2022-04-12 11:55:55.981 +0800 CST
carbon.CreateFromDate(2020, 8, 5).ToString() // // 2020-08-05 13:14:15 +0800 CST
carbon.CreateFromTime(13, 14, 15).ToString() // 2020-08-05 13:14:15 +0800 CST
和標準庫互轉:
// 將 time.Time 轉換成 Carbon
carbon.Time2Carbon(time.Now())
// 將 Carbon 轉換成 time.Time
carbon.Now().Carbon2Time()
昨天、今天和明天, 以及轉換成字符串,下面是一部分例子:
// 今天此刻
fmt.Sprintf("%s", carbon.Now()) // 2020-08-05 13:14:15
carbon.Now().ToString() // 2020-08-05 13:14:15 +0800 CST
carbon.Now().ToDateTimeString() // 2020-08-05 13:14:15
// 今天日期
carbon.Now().ToDateString() // 2020-08-05
// 今天時間
carbon.Now().ToTimeString() // 13:14:15
// 昨天此刻
fmt.Sprintf("%s", carbon.Yesterday()) // 2020-08-04 13:14:15
carbon.Yesterday().ToString() // 2020-08-04 13:14:15 +0800 CST
// 明天此刻
fmt.Sprintf("%s", carbon.Tomorrow()) // 2020-08-06 13:14:15
carbon.Tomorrow().ToString() // 2020-08-06 13:14:15 +0800 CST
carbon.Tomorrow().ToDateTimeString() // 2020-08-06 13:14:15
一些字符串格式例子:
// 輸出日期時間字符串
carbon.Parse("2020-08-05T13:14:15.999999999+08:00").ToDateTimeString() // 2020-08-05 13:14:15
// 輸出日期時間字符串,包含毫秒
carbon.Parse("2020-08-05T13:14:15.999999999+08:00").ToDateTimeMilliString() // 2020-08-05 13:14:15.999
// 輸出日期時間字符串,包含微秒
carbon.Parse("2020-08-05T13:14:15.999999999+08:00").ToDateTimeMicroString() // 2020-08-05 13:14:15.999999
// 輸出日期時間字符串,包含納秒
carbon.Parse("2020-08-05T13:14:15.999999999+08:00").ToDateTimeNanoString() // 2020-08-05 13:14:15.999999999
解析
carbon 解析採用標準格式或者模板格式,標準格式如下:
carbon.Parse("now").ToString() // 2020-08-05 13:14:15 +0800 CST
carbon.Parse("yesterday").ToString() // 2020-08-04 13:14:15 +0800 CST
carbon.Parse("tomorrow").ToString() // 2020-08-06 13:14:15 +0800 CST
carbon.Parse("2020").ToString() // 2020-01-01 00:00:00 +0800 CST
carbon.Parse("2020-8").ToString() // 2020-08-01 00:00:00 +0800 CST
carbon.Parse("2020-08").ToString() // 2020-08-01 00:00:00 +0800 CST
carbon.Parse("2020-8-5").ToString() // 2020-08-05 00:00:00 +0800 CST
carbon.Parse("2020-8-05").ToString() // 2020-08-05 00:00:00 +0800 CST
carbon.Parse("2020-08-05").ToString() // 2020-08-05 00:00:00 +0800 CST
carbon.Parse("2020-08-05.999").ToString() // 2020-08-05 00:00:00.999 +0800 CST
carbon.Parse("2020-08-05.999999").ToString() // 2020-08-05 00:00:00.999999 +0800 CST
carbon.Parse("2020-08-05.999999999").ToString() // 2020-08-05 00:00:00.999999999 +0800 CST
carbon.Parse("2020-8-5 13:14:15").ToString() // 2020-08-05 13:14:15 +0800 CST
carbon.Parse("2020-8-05 13:14:15").ToString() // 2020-08-05 13:14:15 +0800 CST
carbon.Parse("2020-08-05T13:14:15.999999999+08:00").ToString() // 2020-08-05 13:14:15.999999999 +0800 CST
carbon.Parse("20200805").ToString() // 2020-08-05 00:00:00 +0800 CST
carbon.Parse("20200805131415.999999999+08:00").ToString() // 2020-08-05 13:14:15.999999999 +0800 CST
模板格式:
carbon.ParseByFormat("2020|08|05 13|14|15", "Y|m|d H|i|s").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByFormat("It is 2020-08-05 13:14:15", "\\I\\t \\i\\s Y-m-d H:i:s").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByFormat("今天是 2020年08月05日13時14分15秒", "今天是 Y年m月d日H時i分s秒").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByFormat("2020-08-05 13:14:15", "Y-m-d H:i:s", carbon.Tokyo).ToDateTimeString() // 2020-08-05 14:14:15
或者 Go 標準庫佈局模式:
carbon.ParseByLayout("2020|08|05 13|14|15", "2006|01|02 15|04|05").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByLayout("It is 2020-08-05 13:14:15", "It is 2006-01-02 15:04:05").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByLayout("今天是 2020年08月05日13時14分15秒", "今天是 2006年01月02日15時04分05秒").ToDateTimeString() // 2020-08-05 13:14:15
carbon.ParseByLayout("2020-08-05 13:14:15", "2006-01-02 15:04:05", carbon.Tokyo).ToDateTimeString() // 2020-08-05 14:14:15
開始時刻和結束時刻
和 jizhu/now 的功能類似,求一個時刻開始點和結束點:
// 本世紀開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfCentury().ToDateTimeString() // 2000-01-01 00:00:00
// 本世紀結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfCentury().ToDateTimeString() // 2999-12-31 23:59:59
// 本年代開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfDecade().ToDateTimeString() // 2020-01-01 00:00:00
carbon.Parse("2021-08-05 13:14:15").StartOfDecade().ToDateTimeString() // 2020-01-01 00:00:00
carbon.Parse("2029-08-05 13:14:15").StartOfDecade().ToDateTimeString() // 2020-01-01 00:00:00
// 本年代結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfDecade().ToDateTimeString() // 2029-12-31 23:59:59
carbon.Parse("2021-08-05 13:14:15").EndOfDecade().ToDateTimeString() // 2029-12-31 23:59:59
carbon.Parse("2029-08-05 13:14:15").EndOfDecade().ToDateTimeString() // 2029-12-31 23:59:59
// 本年開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfYear().ToDateTimeString() // 2020-01-01 00:00:00
// 本年結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfYear().ToDateTimeString() // 2020-12-31 23:59:59
// 本季度開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfQuarter().ToDateTimeString() // 2020-07-01 00:00:00
// 本季度結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfQuarter().ToDateTimeString() // 2020-09-30 23:59:59
......
// 本分鐘開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfMinute().ToDateTimeString() // 2020-08-05 13:14:00
// 本分鐘結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfMinute().ToDateTimeString() // 2020-08-05 13:14:59
// 本秒開始時間
carbon.Parse("2020-08-05 13:14:15").StartOfSecond().ToString() // 2020-08-05 13:14:15 +0800 CST
// 本秒結束時間
carbon.Parse("2020-08-05 13:14:15").EndOfSecond().ToString() // 2020-08-05 13:14:15.999999999 +0800 CST
好吧,向上它已經提供勞務世紀初和世紀末的時間點、已經秒級別的開始時間點和結束時間點。
時間旅行
提供了時間時移的功能,增加時間或者減少時間到另外一個時間點。
依然很大氣哦,可以提供世紀級別的方法納秒級別的方法。
// 三個世紀後
carbon.Parse("2020-02-29 13:14:15").AddCenturies(3).ToDateTimeString() // 2320-02-29 13:14:15
// 三個世紀後(月份不溢出)
carbon.Parse("2020-02-29 13:14:15").AddCenturiesNoOverflow(3).ToDateTimeString() // 2320-02-29 13:14:15
......
// 三個世紀後
carbon.Parse("2020-02-29 13:14:15").AddCenturies(3).ToDateTimeString() // 2320-02-29 13:14:15
// 三個世紀後(月份不溢出)
carbon.Parse("2020-02-29 13:14:15").AddCenturiesNoOverflow(3).ToDateTimeString() // 2320-02-29 13:14:15
......
// 三納秒後
carbon.Parse("2020-08-05 13:14:15.222222222").AddNanoseconds(3).ToString() // 2020-08-05 13:14:15.222222225 +0800 CST
// 一納秒後
carbon.Parse("2020-08-05 13:14:15.222222222").AddNanossecond().ToString() // 2020-08-05 13:14:15.222222223 +0800 CST
// 三納秒前
carbon.Parse("2020-08-05 13:14:15.222222222").SubNanosseconds(3).ToString() // 2020-08-05 13:14:15.222222219 +0800 CST
// 一納秒前
carbon.Parse("2020-08-05 13:14:15.222222222").SubNanossecond().ToString() // 2020-08-05 13:14:15.222222221 +0800 CST
仁者見仁智者見智,有些人喜歡這種細粒度的方法,挺好。不過看到這麼多的方法,提供類似的功能,我會提供一個方法,然後第二個單位用枚舉類型來指定,這樣一個時移通過一個方法就搞定了,這樣學習起來和維護起來比較方便,比如我會設計成這樣:
carbon.Parse("2020-02-29 13:14:15").Add(3, carbon.Century)
carbon.Parse("2020-02-29 13:14:15").Add(3, carbon.Nano)
你喜歡哪種方法,歡迎評論區寫出你的想法。
時間差
求兩個時間的差值, 比如:
// 相差多少年
carbon.Parse("2021-08-05 13:14:15").DiffInYears(carbon.Parse("2020-08-05 13:14:15")) // -1
// 相差多少年(絕對值)
carbon.Parse("2021-08-05 13:14:15").DiffAbsInYears(carbon.Parse("2020-08-05 13:14:15")) // 1
...
/ 相差多少秒
carbon.Parse("2020-08-05 13:14:15").DiffInSeconds(carbon.Parse("2020-08-05 13:14:14")) // -1
// 相差多少秒(絕對值)
carbon.Parse("2020-08-05 13:14:15").DiffAbsInSeconds(carbon.Parse("2020-08-05 13:14:14")) // 1
// 相差字符串
carbon.Now().DiffInString() // just now
carbon.Now().AddYearsNoOverflow(1).DiffInString() // -1 year
carbon.Now().SubYearsNoOverflow(1).DiffInString() // 1 year
// 相差字符串(絕對值)
carbon.Now().DiffAbsInString(carbon.Now()) // just now
carbon.Now().AddYearsNoOverflow(1).DiffAbsInString(carbon.Now()) // 1 year
carbon.Now().SubYearsNoOverflow(1).DiffAbsInString(carbon.Now()) // 1 year
一些時間判斷
比如
carbon.Parse("0").IsZero() // true
carbon.Parse("0000-00-00 00:00:00").IsZero() // true
carbon.Parse("0").IsZero() // true
carbon.Parse("0000-00-00 00:00:00").IsZero() // true
// 是否是閏年
carbon.Parse("2020-08-05 13:14:15").IsLeapYear() // true
// 是否是長年
carbon.Parse("2020-08-05 13:14:15").IsLongYear() // true
// 是否是一月
carbon.Parse("2020-08-05 13:14:15").IsJanuary() // false
// 是否是閏年
carbon.Parse("2020-08-05 13:14:15").IsLeapYear() // true
// 是否是長年
carbon.Parse("2020-08-05 13:14:15").IsLongYear() // true
// 是否是一月
carbon.Parse("2020-08-05 13:14:15").IsJanuary() // false
設置時間的某個單位
/ 設置區域
carbon.Parse("2020-07-05 13:14:15").SetLocale("en").DiffForHumans() // 1 month ago
carbon.Parse("2020-07-05 13:14:15").SetLocale("zh-CN").DiffForHumans() // 1 月前
// 設置年月日時分秒
carbon.Parse("2020-01-01").SetDateTime(2019, 2, 2, 13, 14, 15).ToString() // 2019-02-02 13:14:15 +0800 CST
carbon.Parse("2020-01-01").SetDateTime(2019, 2, 31, 13, 14, 15).ToString() // 2019-03-03 13:14:15 +0800 CST
// 設置年月日時分秒毫秒
carbon.Parse("2020-01-01").SetDateTimeMilli(2019, 2, 2, 13, 14, 15, 999).ToString() // 2019-02-02 13:14:15.999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeMilli(2019, 2, 31, 13, 14, 15, 999).ToString() // 2019-03-03 13:14:15.999 +0800 CST
// 設置年月日時分秒微秒
carbon.Parse("2020-01-01").SetDateTimeMicro(2019, 2, 2, 13, 14, 15, 999999).ToString() // 2019-02-02 13:14:15.999999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeMicro(2019, 2, 31, 13, 14, 15, 999999).ToString() // 2019-03-03 13:14:15.999999 +0800 CST
// 設置年月日時分秒納秒
carbon.Parse("2020-01-01").SetDateTimeNano(2019, 2, 2, 13, 14, 15, 999999999).ToString() // 2019-02-02 13:14:15.999999999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeNano(2019, 2, 31, 13, 14, 15, 999999999).ToString() // 2019-03-03 13:14:15.999999999 +0800 CST
獲取時間的某個單位
/ 設置區域
carbon.Parse("2020-07-05 13:14:15").SetLocale("en").DiffForHumans() // 1 month ago
carbon.Parse("2020-07-05 13:14:15").SetLocale("zh-CN").DiffForHumans() // 1 月前
// 設置年月日時分秒
carbon.Parse("2020-01-01").SetDateTime(2019, 2, 2, 13, 14, 15).ToString() // 2019-02-02 13:14:15 +0800 CST
carbon.Parse("2020-01-01").SetDateTime(2019, 2, 31, 13, 14, 15).ToString() // 2019-03-03 13:14:15 +0800 CST
// 設置年月日時分秒毫秒
carbon.Parse("2020-01-01").SetDateTimeMilli(2019, 2, 2, 13, 14, 15, 999).ToString() // 2019-02-02 13:14:15.999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeMilli(2019, 2, 31, 13, 14, 15, 999).ToString() // 2019-03-03 13:14:15.999 +0800 CST
// 設置年月日時分秒微秒
carbon.Parse("2020-01-01").SetDateTimeMicro(2019, 2, 2, 13, 14, 15, 999999).ToString() // 2019-02-02 13:14:15.999999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeMicro(2019, 2, 31, 13, 14, 15, 999999).ToString() // 2019-03-03 13:14:15.999999 +0800 CST
// 設置年月日時分秒納秒
carbon.Parse("2020-01-01").SetDateTimeNano(2019, 2, 2, 13, 14, 15, 999999999).ToString() // 2019-02-02 13:14:15.999999999 +0800 CST
carbon.Parse("2020-01-01").SetDateTimeNano(2019, 2, 31, 13, 14, 15, 999999999).ToString() // 2019-03-03 13:14:15.999999999 +0800 CST
// 獲取當前區域
carbon.Now().Locale() // en
carbon.Now().SetLocale("zh-CN").Locale() // zh-CN
// 獲取當前星座
carbon.Now().Constellation() // Leo
carbon.Now().SetLocale("en").Constellation() // Leo
carbon.Now().SetLocale("zh-CN").Constellation() // 獅子座
// 獲取當前季節
carbon.Now().Season() // Summer
carbon.Now().SetLocale("en").Season() // Summer
carbon.Now().SetLocale("zh-CN").Season() // 夏季
carbon 還提供了獲取星座、季節、農曆的方法, 以及設計 json 編解碼的數據格式,數據庫日期格式的支持。
總體來說, carbon 提供了非常豐富,可以說是保姆級的方法,讓你處理日期時間的時候不用再做格外的處理。
robfig/cron
在做業務開發的時候,我們經常會設置一些定時器,有些情況下我們使用 Ticker[6] 就好了,但是我們想做更細緻的定時任務的控制,就得另想辦法了,大家第一個想到的就是 Linux 的 cron 功能,非常的靈活,所以 Go 生態圈中也有相應的庫,這裏給大家介紹兩個。
robfig/cron[7] 是一款兼容 Linux cron 格式的定時任務庫,同時它還提供了擴展的格式,支持秒粒度的設定,這是一種兼容知名的 Java Tigger 庫 quartz[8] 的格式。我們以 Linux cron 格式介紹。
雖然 cron 提供AddFunc
、AddJob
、Schedule
, 但是大同小異,我們一般用AddFunc
去增加定時任務。AddFunc
的第一個參數是 cron 表達式,第二個參數是無參函數,用來在 cron 定義的表達式包額誒觸發時要執行的函數。 cron 使用的例子如下:
c := cron.New()
c.AddFunc("30 * * * *", func() { fmt.Println("在每個小時的30分鐘的時候實行") })
c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println("在每天早上3-6點, 晚上8-11點的30分鐘執行") })
c.AddFunc("CRON_TZ=Asia/Shanghai 30 04 * * *", func() { fmt.Println("在每天的北京時間04:30執行") }) // 如果不指定,默認使用機器的時區
c.AddFunc("@hourly", func() { fmt.Println("每一小時執行。從1小時後開始") })
c.AddFunc("@every 1h30m", func() { fmt.Println("每一小時30分執行,1小時30分開始") })
c.Start()
...
// 函數在它們的goroutine中異步的執行
...
// 期間可以安全的增加任務
c.AddFunc("@daily", func() { fmt.Println("每天執行") })
...
// 可以檢查任務的狀態
inspect(c.Entries())
...
c.Remove(entryID) // 移除某個任務
...
c.Stop() // 不再執行後續的任務
cron 的格式
字段名 | 強制設置? | 允許值 | 允許的特殊字符
---------- | ---------- | -------------- | --------------------------
Minutes | Yes | 0-59 | * / , -
Hours | Yes | 0-23 | * / , -
Day of month | Yes | 1-31 | * / , - ?
Month | Yes | 1-12 or JAN-DEC | * / , -
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?
維基百科 [9] 也介紹了 cron 的格式:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │ 7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * <command to execute>
特殊字符代表的意義:
-
*
: 代表滿足這個字段的每一個值。 -
/
: 代表對於時間範圍的步數,比如第一個字段*/5
代表每 5 分鐘, 也就是5,10,15,20,25,30,35,40,45,50,55,00
分鐘。 -
,
: 代表一組列表,比如第五個字段MON,WED,FRI
代表每星期一、星期三、星期五會觸發。 -
-
: 代表一個範圍,比如第二個字段10-15
代表會在每天 10 點、11 點、12 點、13 點、14 點、15 點被觸發。 -
?
: 有時候可以在第三個和第五個字段代替*
同時這個庫還提供預定義的幾種形式:
預定義類型 | 描述 | 等價格式
----- | ----------- | -------------
@yearly (or @annually) | 在每年的一月一日零點 | 0 0 1 1 *
@monthly | 在每月的第一天零點 | 0 0 1 * *
@weekly | 在每週的第一天零點,也就是週日零點 | 0 0 * * 0
@daily (or @midnight) | 每天零點運行 | 0 0 * * *
@hourly | 每小時開始的時候運行 | 0 * * * *
go-co-op/gocron
go-co-op/gocron[10] 是另外一個優秀的定時任務庫。
它提供了豐富的例子,所以很容易上手,你很容易把它應用到項目中。它的 cron 解析使用的就是上面的 robfig/cron 庫, 你可以使用 cron 格式實現定時任務:
package main
import (
"time"
"github.com/go-co-op/gocron"
)
var task = func() {}
func main() {
s := gocron.NewScheduler(time.UTC)
_, _ = s.Cron("*/1 * * * *").Do(task) // 每分鐘執行一次
_, _ = s.Cron("0 1 * * *").Do(task) // 每天一點執行
_, _ = s.Cron("0 0 * * 6,0").Do(task) // 週末的零點執行
}
但是它還提供了其它人性化的設置,不一定使用 cron 配置:
s := gocron.NewScheduler(time.UTC)
s.Every(5).Seconds().Do(func(){ ... })
// 每5分鐘
s.Every("5m").Do(func(){ ... })
// 每5天
s.Every(5).Days().Do(func(){ ... })
s.Every(1).Month(1, 2, 3).Do(func(){ ... })
// set time
s.Every(1).Day().At("10:30").Do(func(){ ... })
// set multiple times
s.Every(1).Day().At("10:30;08:00").Do(func(){ ... })
s.Every(1).Day().At("10:30").At("08:00").Do(func(){ ... })
// Schedule each last day of the month
s.Every(1).MonthLastDay().Do(func(){ ... })
// Or each last day of every other month
s.Every(2).MonthLastDay().Do(func(){ ... })
// cron expressions supported
s.Cron("*/1 * * * *").Do(task) // every minute
// 異步執行,避免任務會阻塞scheduler
s.StartAsync()
參考資料
[1]
jinzhu/now: https://github.com/jinzhu/now
[2]
time: https://pkg.go.dev/time
[3]
時間格式: https://pkg.go.dev/time#pkg-constants
[4]
golang-module/carbon: https://github.com/golang-module/carbon
[5]
夠過癮: https://www.gouguoyin.com/
[6]
Ticker: https://pkg.go.dev/time#Ticker
[7]
robfig/cron: https://pkg.go.dev/github.com/robfig/cron/v3
[8]
quartz: http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html
[9]
維基百科: https://en.wikipedia.org/wiki/Cron
[10]
go-co-op/gocron: https://github.com/go-co-op/gocron
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/EAk_LdlfYGwaiDDj9CgqHA