diff --git a/CHANGELOG.md b/CHANGELOG.md
index e49658c..db0144f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# go-utils
+
+## [v1.27.0] - 2022-09-22
+### New Features
+- add GetCronNextAt
+
+
## [v1.26.0] - 2022-09-21
### New Features
@@ -52,11 +58,11 @@
- fix marshal issue on gorm.DeletedAt empty value ([#32](https://github.com/kumparan/kumnats/issues/32))
-
-## [v1.20.0] - 2022-03-11
-
## [v.1.20.0] - 2022-03-11
+
+
+## [v1.20.0] - 2022-03-11
### New Features
- add constraint size gql directive ([#30](https://github.com/kumparan/kumnats/issues/30))
@@ -154,11 +160,11 @@
- add money formatter for multiple currencies ([#13](https://github.com/kumparan/kumnats/issues/13))
-
-## [v1.7.1] - 2020-12-10
-
## [v1.8.0] - 2020-12-10
+
+
+## [v1.7.1] - 2020-12-10
### New Features
- add formatter for indonesian money and date
@@ -223,7 +229,8 @@
- init go-utils
-[Unreleased]: https://github.com/kumparan/kumnats/compare/v1.26.0...HEAD
+[Unreleased]: https://github.com/kumparan/kumnats/compare/v1.27.0...HEAD
+[v1.27.0]: https://github.com/kumparan/kumnats/compare/v1.26.0...v1.27.0
[v1.26.0]: https://github.com/kumparan/kumnats/compare/v1.25.1...v1.26.0
[v1.25.1]: https://github.com/kumparan/kumnats/compare/v1.25.0...v1.25.1
[v1.25.0]: https://github.com/kumparan/kumnats/compare/v1.24.0...v1.25.0
@@ -231,9 +238,9 @@
[v1.23.0]: https://github.com/kumparan/kumnats/compare/v1.22.0...v1.23.0
[v1.22.0]: https://github.com/kumparan/kumnats/compare/v1.21.0...v1.22.0
[v1.21.0]: https://github.com/kumparan/kumnats/compare/v1.20.1...v1.21.0
-[v1.20.1]: https://github.com/kumparan/kumnats/compare/v1.20.0...v1.20.1
-[v1.20.0]: https://github.com/kumparan/kumnats/compare/v.1.20.0...v1.20.0
-[v.1.20.0]: https://github.com/kumparan/kumnats/compare/v1.19.3...v.1.20.0
+[v1.20.1]: https://github.com/kumparan/kumnats/compare/v.1.20.0...v1.20.1
+[v.1.20.0]: https://github.com/kumparan/kumnats/compare/v1.20.0...v.1.20.0
+[v1.20.0]: https://github.com/kumparan/kumnats/compare/v1.19.3...v1.20.0
[v1.19.3]: https://github.com/kumparan/kumnats/compare/v1.19.2...v1.19.3
[v1.19.2]: https://github.com/kumparan/kumnats/compare/v1.19.1...v1.19.2
[v1.19.1]: https://github.com/kumparan/kumnats/compare/v1.19.0...v1.19.1
@@ -249,9 +256,9 @@
[v1.12.0]: https://github.com/kumparan/kumnats/compare/v1.11.0...v1.12.0
[v1.11.0]: https://github.com/kumparan/kumnats/compare/v1.10.0...v1.11.0
[v1.10.0]: https://github.com/kumparan/kumnats/compare/v1.9.0...v1.10.0
-[v1.9.0]: https://github.com/kumparan/kumnats/compare/v1.7.1...v1.9.0
-[v1.7.1]: https://github.com/kumparan/kumnats/compare/v1.8.0...v1.7.1
-[v1.8.0]: https://github.com/kumparan/kumnats/compare/v1.7.0...v1.8.0
+[v1.9.0]: https://github.com/kumparan/kumnats/compare/v1.8.0...v1.9.0
+[v1.8.0]: https://github.com/kumparan/kumnats/compare/v1.7.1...v1.8.0
+[v1.7.1]: https://github.com/kumparan/kumnats/compare/v1.7.0...v1.7.1
[v1.7.0]: https://github.com/kumparan/kumnats/compare/v1.6.0...v1.7.0
[v1.6.0]: https://github.com/kumparan/kumnats/compare/v1.5.0...v1.6.0
[v1.5.0]: https://github.com/kumparan/kumnats/compare/v1.4.0...v1.5.0
diff --git a/cron.go b/cron.go
new file mode 100644
index 0000000..3a325bb
--- /dev/null
+++ b/cron.go
@@ -0,0 +1,23 @@
+package utils
+
+import (
+ "time"
+
+ "github.com/robfig/cron/v3"
+)
+
+var cronNextAtTimeFormat = "2006-01-02T15:04:05"
+
+// GetCronNextAt supports
+// - Standard crontab specs, e.g. "* * * * ?"
+// - Descriptors, e.g. "@midnight", "@every 1h30m"
+// if cron parsing error then return current time
+func GetCronNextAt(cronTab string) string {
+ now := time.Now()
+ var schedule, err = cron.ParseStandard(cronTab)
+ if err != nil {
+ return now.Format(cronNextAtTimeFormat)
+ }
+
+ return schedule.Next(now).Format(cronNextAtTimeFormat)
+}
diff --git a/cron_test.go b/cron_test.go
new file mode 100644
index 0000000..41899e7
--- /dev/null
+++ b/cron_test.go
@@ -0,0 +1,22 @@
+package utils
+
+import (
+ "testing"
+ "time"
+
+ "github.com/agiledragon/gomonkey"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCron_GetCronNextAt(t *testing.T) {
+ now, _ := time.Parse(time.RFC3339, "2010-01-02T15:00:00Z")
+ patch := gomonkey.ApplyFunc(time.Now, func() time.Time { return now })
+ defer patch.Reset()
+
+ assert.Equal(t, now.Format(cronNextAtTimeFormat), GetCronNextAt("* ngaco * cron nya ")) // wrong cron tab,return current time as next at
+ assert.Equal(t, now.Add(1*time.Hour).Format(cronNextAtTimeFormat), GetCronNextAt("@hourly"))
+ assert.Equal(t, now.Add(1*time.Minute).Format(cronNextAtTimeFormat), GetCronNextAt("*/1 * * * *"))
+ assert.Equal(t, now.Add(1*time.Hour).Format(cronNextAtTimeFormat), GetCronNextAt("0 */1 * * *")) // every hour
+ assert.Equal(t, now.Add(2*time.Hour).Format(cronNextAtTimeFormat), GetCronNextAt("0 17 */1 * *")) // every 17:00
+ assert.Equal(t, now.Add(30*time.Second).Format(cronNextAtTimeFormat), GetCronNextAt("@every 30s"))
+}
diff --git a/go.mod b/go.mod
index 3f6e2dd..4bf6484 100644
--- a/go.mod
+++ b/go.mod
@@ -4,11 +4,13 @@ go 1.18
require (
github.com/99designs/gqlgen v0.14.0
+ github.com/agiledragon/gomonkey v2.0.2+incompatible
github.com/getsentry/sentry-go v0.11.0
github.com/goodsign/monday v1.0.0
github.com/graph-gophers/graphql-go v1.4.0
github.com/leekchan/accounting v0.3.1
github.com/microcosm-cc/bluemonday v1.0.19
+ github.com/robfig/cron/v3 v3.0.1
github.com/shopspring/decimal v1.2.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
diff --git a/go.sum b/go.sum
index cb710e8..289b366 100644
--- a/go.sum
+++ b/go.sum
@@ -7,6 +7,8 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
+github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
@@ -128,8 +130,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
-github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo=
-github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -159,6 +159,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -254,10 +256,8 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=