diff --git a/go.mod b/go.mod index cd09a841b66..01bfaa9b4cc 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/pkg/errors v0.9.1 - github.com/rickb777/date v1.13.0 + github.com/rickb777/date v1.21.1 github.com/robfig/cron/v3 v3.0.1 github.com/stretchr/testify v1.11.1 github.com/wavesoftware/go-ensure v1.0.0 @@ -92,7 +92,7 @@ require ( github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect - github.com/rickb777/plural v1.2.1 // indirect + github.com/rickb777/plural v1.4.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/go.sum b/go.sum index c02cd61fd10..7b5be702900 100644 --- a/go.sum +++ b/go.sum @@ -402,7 +402,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -425,16 +424,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= @@ -498,10 +493,10 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rickb777/date v1.13.0 h1:+8AmwLuY1d/rldzdqvqTEg7107bZ8clW37x4nsdG3Hs= -github.com/rickb777/date v1.13.0/go.mod h1:GZf3LoGnxPWjX+/1TXOuzHefZFDovTyNLHDMd3qH70k= -github.com/rickb777/plural v1.2.1 h1:UitRAgR70+yHFt26Tmj/F9dU9aV6UfjGXSbO1DcC9/U= -github.com/rickb777/plural v1.2.1/go.mod h1:j058+3M5QQFgcZZ2oKIOekcygoZUL8gKW5yRO14BuAw= +github.com/rickb777/date v1.21.1 h1:tUcQS8riIRoYK5kUAv5aevllFEYUEk2x8OYDyoldOn4= +github.com/rickb777/date v1.21.1/go.mod h1:gnDexsbXViZr2fCKMrY3m6IfAF5U2vSkEaiGJcNFaLQ= +github.com/rickb777/plural v1.4.2 h1:Kl/syFGLFZ5EbuV8c9SVud8s5HI2HpCCtOMw2U1kS+A= +github.com/rickb777/plural v1.4.2/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= 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/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -529,7 +524,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= -github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -688,7 +682,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -764,13 +757,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -893,7 +884,6 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/vendor/github.com/rickb777/date/period/arithmetic.go b/vendor/github.com/rickb777/date/period/arithmetic.go new file mode 100644 index 00000000000..464a4130281 --- /dev/null +++ b/vendor/github.com/rickb777/date/period/arithmetic.go @@ -0,0 +1,111 @@ +// Copyright 2015 Rick Beton. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package period + +import ( + "time" +) + +// Add adds two periods together. Use this method along with Negate in order to subtract periods. +// +// The result is not normalised and may overflow arithmetically (to make this unlikely, use Normalise on +// the inputs before adding them). +func (period Period) Add(that Period) Period { + return Period{ + period.years + that.years, + period.months + that.months, + period.days + that.days, + period.hours + that.hours, + period.minutes + that.minutes, + period.seconds + that.seconds, + } +} + +//------------------------------------------------------------------------------------------------- + +// AddTo adds the period to a time, returning the result. +// A flag is also returned that is true when the conversion was precise and false otherwise. +// +// When the period specifies hours, minutes and seconds only, the result is precise. +// Also, when the period specifies whole years, months and days (i.e. without fractions), the +// result is precise. However, when years, months or days contains fractions, the result +// is only an approximation (it assumes that all days are 24 hours and every year is 365.2425 +// days, as per Gregorian calendar rules). +func (period Period) AddTo(t time.Time) (time.Time, bool) { + wholeYears := (period.years % 10) == 0 + wholeMonths := (period.months % 10) == 0 + wholeDays := (period.days % 10) == 0 + + if wholeYears && wholeMonths && wholeDays { + // in this case, time.AddDate(...).Add(...) provides an exact solution + stE3 := totalSecondsE3(period) + if period.years == 0 && period.months == 0 && period.days == 0 { + // AddDate (below) normalises its result, so we don't call it unless needed + return t.Add(stE3 * time.Millisecond), true + } + + t1 := t.AddDate(int(period.years/10), int(period.months/10), int(period.days/10)) + return t1.Add(stE3 * time.Millisecond), true + } + + d, precise := period.Duration() + return t.Add(d), precise +} + +//------------------------------------------------------------------------------------------------- + +// Scale a period by a multiplication factor. Obviously, this can both enlarge and shrink it, +// and change the sign if negative. The result is normalised, but integer overflows are silently +// ignored. +// +// Bear in mind that the internal representation is limited by fixed-point arithmetic with two +// decimal places; each field is only int16. +// +// Known issue: scaling by a large reduction factor (i.e. much less than one) doesn't work properly. +func (period Period) Scale(factor float32) Period { + result, _ := period.ScaleWithOverflowCheck(factor) + return result +} + +// ScaleWithOverflowCheck a period by a multiplication factor. Obviously, this can both enlarge and shrink it, +// and change the sign if negative. The result is normalised. An error is returned if integer overflow +// happened. +// +// Bear in mind that the internal representation is limited by fixed-point arithmetic with one +// decimal place; each field is only int16. +// +// Known issue: scaling by a large reduction factor (i.e. much less than one) doesn't work properly. +func (period Period) ScaleWithOverflowCheck(factor float32) (Period, error) { + ap, neg := period.absNeg() + + if -0.5 < factor && factor < 0.5 { + d, pr1 := ap.Duration() + mul := float64(d) * float64(factor) + p2, pr2 := NewOf(time.Duration(mul)) + return p2.Normalise(pr1 && pr2), nil + } + + y := int64(float32(ap.years) * factor) + m := int64(float32(ap.months) * factor) + d := int64(float32(ap.days) * factor) + hh := int64(float32(ap.hours) * factor) + mm := int64(float32(ap.minutes) * factor) + ss := int64(float32(ap.seconds) * factor) + + p64 := &period64{years: y, months: m, days: d, hours: hh, minutes: mm, seconds: ss, neg: neg} + return p64.normalise64(true).toPeriod() +} + +// RationalScale scales a period by a rational multiplication factor. Obviously, this can both enlarge and shrink it, +// and change the sign if negative. The result is normalised. An error is returned if integer overflow +// happened. +// +// If the divisor is zero, a panic will arise. +// +// Bear in mind that the internal representation is limited by fixed-point arithmetic with two +// decimal places; each field is only int16. +//func (period Period) RationalScale(multiplier, divisor int) (Period, error) { +// return period.rationalScale64(int64(multiplier), int64(divisor)) +//} diff --git a/vendor/github.com/rickb777/date/period/designator.go b/vendor/github.com/rickb777/date/period/designator.go new file mode 100644 index 00000000000..6d836ec4c63 --- /dev/null +++ b/vendor/github.com/rickb777/date/period/designator.go @@ -0,0 +1,55 @@ +// Copyright 2015 Rick Beton. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package period + +type ymdDesignator byte +type hmsDesignator byte + +const ( + Year ymdDesignator = 'Y' + Month ymdDesignator = 'M' + Week ymdDesignator = 'W' + Day ymdDesignator = 'D' + + Hour hmsDesignator = 'H' + Minute hmsDesignator = 'M' + Second hmsDesignator = 'S' +) + +func (d ymdDesignator) IsOneOf(xx ...ymdDesignator) bool { + for _, x := range xx { + if x == d { + return true + } + } + return false +} + +func (d ymdDesignator) IsNotOneOf(xx ...ymdDesignator) bool { + for _, x := range xx { + if x == d { + return false + } + } + return true +} + +func (d hmsDesignator) IsOneOf(xx ...hmsDesignator) bool { + for _, x := range xx { + if x == d { + return true + } + } + return false +} + +func (d hmsDesignator) IsNotOneOf(xx ...hmsDesignator) bool { + for _, x := range xx { + if x == d { + return false + } + } + return true +} diff --git a/vendor/github.com/rickb777/date/period/doc.go b/vendor/github.com/rickb777/date/period/doc.go index c8a57b4a0d9..5abe8447b16 100644 --- a/vendor/github.com/rickb777/date/period/doc.go +++ b/vendor/github.com/rickb777/date/period/doc.go @@ -5,6 +5,9 @@ // Package period provides functionality for periods of time using ISO-8601 conventions. // This deals with years, months, weeks/days, hours, minutes and seconds. // +// *** Warning: this package is the subject of many issues, so a replacement is under +// development. Please see https://github.com/rickb777/period. +// // Because of the vagaries of calendar systems, the meaning of year lengths, month lengths // and even day lengths depends on context. So a period is not necessarily a fixed duration // of time in terms of seconds. @@ -40,5 +43,4 @@ // * "P2.5Y" is 2.5 years. // // * "PT12M7.5S" is 12 minutes and 7.5 seconds. -// package period diff --git a/vendor/github.com/rickb777/date/period/flag.go b/vendor/github.com/rickb777/date/period/flag.go new file mode 100644 index 00000000000..9488efa7ca8 --- /dev/null +++ b/vendor/github.com/rickb777/date/period/flag.go @@ -0,0 +1,16 @@ +package period + +// Set enables use of Period by the flag API. +func (period *Period) Set(p string) error { + p2, err := Parse(p) + if err != nil { + return err + } + *period = p2 + return nil +} + +// Type is for compatibility with the spf13/pflag library. +func (period Period) Type() string { + return "period" +} diff --git a/vendor/github.com/rickb777/date/period/format.go b/vendor/github.com/rickb777/date/period/format.go index 32cb6a8311f..3b095292674 100644 --- a/vendor/github.com/rickb777/date/period/format.go +++ b/vendor/github.com/rickb777/date/period/format.go @@ -5,25 +5,32 @@ package period import ( - "bytes" "fmt" + "io" "strings" "github.com/rickb777/plural" ) // Format converts the period to human-readable form using the default localisation. +// Multiples of 7 days are shown as weeks. func (period Period) Format() string { return period.FormatWithPeriodNames(PeriodYearNames, PeriodMonthNames, PeriodWeekNames, PeriodDayNames, PeriodHourNames, PeriodMinuteNames, PeriodSecondNames) } +// FormatWithoutWeeks converts the period to human-readable form using the default localisation. +// Multiples of 7 days are not shown as weeks. +func (period Period) FormatWithoutWeeks() string { + return period.FormatWithPeriodNames(PeriodYearNames, PeriodMonthNames, plural.Plurals{}, PeriodDayNames, PeriodHourNames, PeriodMinuteNames, PeriodSecondNames) +} + // FormatWithPeriodNames converts the period to human-readable form in a localisable way. func (period Period) FormatWithPeriodNames(yearNames, monthNames, weekNames, dayNames, hourNames, minNames, secNames plural.Plurals) string { period = period.Abs() parts := make([]string, 0) - parts = appendNonBlank(parts, yearNames.FormatFloat(absFloat10(period.years))) - parts = appendNonBlank(parts, monthNames.FormatFloat(absFloat10(period.months))) + parts = appendNonBlank(parts, yearNames.FormatFloat(float10(period.years))) + parts = appendNonBlank(parts, monthNames.FormatFloat(float10(period.months))) if period.days > 0 || (period.IsZero()) { if len(weekNames) > 0 { @@ -34,15 +41,15 @@ func (period Period) FormatWithPeriodNames(yearNames, monthNames, weekNames, day parts = appendNonBlank(parts, weekNames.FormatInt(int(weeks))) } if mdays > 0 || weeks == 0 { - parts = appendNonBlank(parts, dayNames.FormatFloat(absFloat10(mdays))) + parts = appendNonBlank(parts, dayNames.FormatFloat(float10(mdays))) } } else { - parts = appendNonBlank(parts, dayNames.FormatFloat(absFloat10(period.days))) + parts = appendNonBlank(parts, dayNames.FormatFloat(float10(period.days))) } } - parts = appendNonBlank(parts, hourNames.FormatFloat(absFloat10(period.hours))) - parts = appendNonBlank(parts, minNames.FormatFloat(absFloat10(period.minutes))) - parts = appendNonBlank(parts, secNames.FormatFloat(absFloat10(period.seconds))) + parts = appendNonBlank(parts, hourNames.FormatFloat(float10(period.hours))) + parts = appendNonBlank(parts, minNames.FormatFloat(float10(period.minutes))) + parts = appendNonBlank(parts, secNames.FormatFloat(float10(period.seconds))) return strings.Join(parts, ", ") } @@ -79,50 +86,54 @@ var PeriodSecondNames = plural.FromZero("", "%v second", "%v seconds") // String converts the period to ISO-8601 form. func (period Period) String() string { - if period.IsZero() { + return period.toPeriod64("").String() +} + +func (p64 period64) String() string { + if p64 == (period64{}) { return "P0D" } - buf := &bytes.Buffer{} - if period.Sign() < 0 { + buf := &strings.Builder{} + if p64.neg { buf.WriteByte('-') } buf.WriteByte('P') - if period.years != 0 { - fmt.Fprintf(buf, "%gY", absFloat10(period.years)) - } - if period.months != 0 { - fmt.Fprintf(buf, "%gM", absFloat10(period.months)) - } - if period.days != 0 { - if period.days%70 == 0 { - fmt.Fprintf(buf, "%gW", absFloat10(period.days/7)) + writeField64(buf, p64.years, byte(Year)) + writeField64(buf, p64.months, byte(Month)) + + if p64.days != 0 { + if p64.days%70 == 0 { + writeField64(buf, p64.days/7, byte(Week)) } else { - fmt.Fprintf(buf, "%gD", absFloat10(period.days)) + writeField64(buf, p64.days, byte(Day)) } } - if period.hours != 0 || period.minutes != 0 || period.seconds != 0 { + + if p64.hours != 0 || p64.minutes != 0 || p64.seconds != 0 { buf.WriteByte('T') } - if period.hours != 0 { - fmt.Fprintf(buf, "%gH", absFloat10(period.hours)) - } - if period.minutes != 0 { - fmt.Fprintf(buf, "%gM", absFloat10(period.minutes)) - } - if period.seconds != 0 { - fmt.Fprintf(buf, "%gS", absFloat10(period.seconds)) - } + + writeField64(buf, p64.hours, byte(Hour)) + writeField64(buf, p64.minutes, byte(Minute)) + writeField64(buf, p64.seconds, byte(Second)) return buf.String() } -func absFloat10(v int16) float32 { - f := float32(v) / 10 - if v < 0 { - return -f +func writeField64(w io.Writer, field int64, designator byte) { + if field != 0 { + if field%10 != 0 { + fmt.Fprintf(w, "%g", float32(field)/10) + } else { + fmt.Fprintf(w, "%d", field/10) + } + w.(io.ByteWriter).WriteByte(designator) } - return f +} + +func float10(v int16) float32 { + return float32(v) / 10 } diff --git a/vendor/github.com/rickb777/date/period/marshal.go b/vendor/github.com/rickb777/date/period/marshal.go index c87ad5f6fb9..6e1f2f1ce99 100644 --- a/vendor/github.com/rickb777/date/period/marshal.go +++ b/vendor/github.com/rickb777/date/period/marshal.go @@ -12,19 +12,21 @@ func (period Period) MarshalBinary() ([]byte, error) { } // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -// This also provides support for gob encoding. +// This also provides support for gob decoding. func (period *Period) UnmarshalBinary(data []byte) error { return period.UnmarshalText(data) } // MarshalText implements the encoding.TextMarshaler interface for Periods. +// This also provides support for JSON encoding. func (period Period) MarshalText() ([]byte, error) { return []byte(period.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for Periods. +// This also provides support for JSON decoding. func (period *Period) UnmarshalText(data []byte) (err error) { - u, err := Parse(string(data)) + u, err := Parse(string(data), false) if err == nil { *period = u } diff --git a/vendor/github.com/rickb777/date/period/parse.go b/vendor/github.com/rickb777/date/period/parse.go index 52b91f1423a..d88f1e7c8f8 100644 --- a/vendor/github.com/rickb777/date/period/parse.go +++ b/vendor/github.com/rickb777/date/period/parse.go @@ -12,8 +12,10 @@ import ( // MustParse is as per Parse except that it panics if the string cannot be parsed. // This is intended for setup code; don't use it for user inputs. -func MustParse(value string) Period { - d, err := Parse(value) +// By default, the value is normalised. +// Normalisation can be disabled using the optional flag. +func MustParse(value string, normalise ...bool) Period { + d, err := Parse(value, normalise...) if err != nil { panic(err) } @@ -24,34 +26,27 @@ func MustParse(value string) Period { // // In addition, a plus or minus sign can precede the period, e.g. "-P10D" // -// The value is normalised, e.g. multiple of 12 months become years so "P24M" -// is the same as "P2Y". However, this is done without loss of precision, so -// for example whole numbers of days do not contribute to the months tally +// By default, the value is normalised, e.g. multiple of 12 months become years +// so "P24M" is the same as "P2Y". However, this is done without loss of precision, +// so for example whole numbers of days do not contribute to the months tally // because the number of days per month is variable. // +// Normalisation can be disabled using the optional flag. +// // The zero value can be represented in several ways: all of the following // are equivalent: "P0Y", "P0M", "P0W", "P0D", "PT0H", PT0M", PT0S", and "P0". // The canonical zero is "P0D". -func Parse(period string) (Period, error) { - return ParseWithNormalise(period, true) +func Parse(period string, normalise ...bool) (Period, error) { + return ParseWithNormalise(period, len(normalise) == 0 || normalise[0]) } // ParseWithNormalise parses strings that specify periods using ISO-8601 rules // with an option to specify whether to normalise parsed period components. // -// In addition, a plus or minus sign can precede the period, e.g. "-P10D" - -// The returned value is only normalised when normalise is set to `true`, and -// normalisation will convert e.g. multiple of 12 months into years so "P24M" -// is the same as "P2Y". However, this is done without loss of precision, so -// for example whole numbers of days do not contribute to the months tally -// because the number of days per month is variable. -// -// The zero value can be represented in several ways: all of the following -// are equivalent: "P0Y", "P0M", "P0W", "P0D", "PT0H", PT0M", PT0S", and "P0". -// The canonical zero is "P0D". +// This method is deprecated and should not be used. It may be removed in a +// future version. func ParseWithNormalise(period string, normalise bool) (Period, error) { - if period == "" { + if period == "" || period == "-" || period == "+" { return Period{}, fmt.Errorf("cannot parse a blank string as a period") } @@ -59,122 +54,186 @@ func ParseWithNormalise(period string, normalise bool) (Period, error) { return Period{}, nil } - result := period64{} - pcopy := period - if pcopy[0] == '-' { - result.neg = true - pcopy = pcopy[1:] - } else if pcopy[0] == '+' { - pcopy = pcopy[1:] + p64, err := parse(period, normalise) + if err != nil { + return Period{}, err } + return p64.toPeriod() +} - if pcopy[0] != 'P' { - return Period{}, fmt.Errorf("expected 'P' period mark at the start: %s", period) +func parse(period string, normalise bool) (*period64, error) { + neg := false + remaining := period + if remaining[0] == '-' { + neg = true + remaining = remaining[1:] + } else if remaining[0] == '+' { + remaining = remaining[1:] } - pcopy = pcopy[1:] - st := parseState{period, pcopy, false, nil} - t := strings.IndexByte(pcopy, 'T') - if t >= 0 { - st.pcopy = pcopy[t+1:] + if remaining[0] != 'P' { + return nil, fmt.Errorf("%s: expected 'P' period mark at the start", period) + } + remaining = remaining[1:] - result.hours, st = parseField(st, 'H') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'H' marker: %s", period) - } + var integer, fraction, weekValue int64 + result := &period64{input: period, neg: neg} + var years, months, weeks, days, hours, minutes, seconds itemState + var designator, previousFractionDesignator byte + var err error + nComponents := 0 - result.minutes, st = parseField(st, 'M') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'M' marker: %s", period) - } + years, months, weeks, days = Armed, Armed, Armed, Armed - result.seconds, st = parseField(st, 'S') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'S' marker: %s", period) - } + isHMS := false + for len(remaining) > 0 { + if remaining[0] == 'T' { + if isHMS { + return nil, fmt.Errorf("%s: 'T' designator cannot occur more than once", period) + } + isHMS = true - if len(st.pcopy) != 0 { - return Period{}, fmt.Errorf("unexpected remaining components %s: %s", st.pcopy, period) - } + years, months, weeks, days = Unready, Unready, Unready, Unready + hours, minutes, seconds = Armed, Armed, Armed - st.pcopy = pcopy[:t] - } + remaining = remaining[1:] - result.years, st = parseField(st, 'Y') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'Y' marker: %s", period) - } - result.months, st = parseField(st, 'M') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'M' marker: %s", period) - } - weeks, st := parseField(st, 'W') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'W' marker: %s", period) + } else { + integer, fraction, designator, remaining, err = parseNextField(remaining, period) + if err != nil { + return nil, err + } + + if previousFractionDesignator != 0 && fraction != 0 { + return nil, fmt.Errorf("%s: '%c' & '%c' only the last field can have a fraction", period, previousFractionDesignator, designator) + } + + number := integer*10 + fraction + + switch designator { + case 'Y': + years, err = years.testAndSet(number, 'Y', result, &result.years) + case 'W': + weeks, err = weeks.testAndSet(number, 'W', result, &weekValue) + case 'D': + days, err = days.testAndSet(number, 'D', result, &result.days) + case 'H': + hours, err = hours.testAndSet(number, 'H', result, &result.hours) + case 'S': + seconds, err = seconds.testAndSet(number, 'S', result, &result.seconds) + case 'M': + if isHMS { + minutes, err = minutes.testAndSet(number, 'M', result, &result.minutes) + } else { + months, err = months.testAndSet(number, 'M', result, &result.months) + } + default: + return nil, fmt.Errorf("%s: expected a number not '%c'", period, designator) + } + nComponents++ + + if err != nil { + return nil, err + } + + if fraction != 0 { + previousFractionDesignator = designator + } + } } - days, st := parseField(st, 'D') - if st.err != nil { - return Period{}, fmt.Errorf("expected a number before the 'D' marker: %s", period) + if nComponents == 0 { + return nil, fmt.Errorf("%s: expected 'Y', 'M', 'W', 'D', 'H', 'M', or 'S' designator", period) } - if len(st.pcopy) != 0 { - return Period{}, fmt.Errorf("unexpected remaining components %s: %s", st.pcopy, period) + result.days += weekValue * 7 + + if normalise { + result = result.normalise64(true) } - result.days = weeks*7 + days - //fmt.Printf("%#v\n", st) + return result, nil +} - if !st.ok { - return Period{}, fmt.Errorf("expected 'Y', 'M', 'W', 'D', 'H', 'M', or 'S' marker: %s", period) - } +//------------------------------------------------------------------------------------------------- - if normalise { - return result.normalise64(true).toPeriod(), nil +type itemState int + +const ( + Unready itemState = iota + Armed + Set +) + +func (i itemState) testAndSet(number int64, designator byte, result *period64, value *int64) (itemState, error) { + switch i { + case Unready: + return i, fmt.Errorf("%s: '%c' designator cannot occur here", result.input, designator) + case Set: + return i, fmt.Errorf("%s: '%c' designator cannot occur more than once", result.input, designator) } - return result.toPeriod(), nil + *value = number + return Set, nil } -type parseState struct { - period, pcopy string - ok bool - err error -} +//------------------------------------------------------------------------------------------------- -func parseField(st parseState, mark byte) (int64, parseState) { - //fmt.Printf("%c %#v\n", mark, st) - r := int64(0) - m := strings.IndexByte(st.pcopy, mark) - if m > 0 { - r, st.err = parseDecimalFixedPoint(st.pcopy[:m], st.period) - if st.err != nil { - return 0, st - } - st.pcopy = st.pcopy[m+1:] - st.ok = true +func parseNextField(str, original string) (int64, int64, byte, string, error) { + i := scanDigits(str) + if i < 0 { + return 0, 0, 0, "", fmt.Errorf("%s: missing designator at the end", original) } - return r, st + + des := str[i] + integer, fraction, err := parseDecimalNumber(str[:i], original, des) + return integer, fraction, des, str[i+1:], err } -// Fixed-point three decimal places -func parseDecimalFixedPoint(s, original string) (int64, error) { - //was := s - dec := strings.IndexByte(s, '.') +// Fixed-point one decimal place +func parseDecimalNumber(number, original string, des byte) (int64, int64, error) { + dec := strings.IndexByte(number, '.') if dec < 0 { - dec = strings.IndexByte(s, ',') + dec = strings.IndexByte(number, ',') } + var integer, fraction int64 + var err error if dec >= 0 { - dp := len(s) - dec - if dp > 1 { - s = s[:dec] + s[dec+1:dec+2] - } else { - s = s[:dec] + s[dec+1:] + "0" + integer, err = strconv.ParseInt(number[:dec], 10, 64) + if err == nil { + number = number[dec+1:] + switch len(number) { + case 0: // skip + case 1: + fraction, err = strconv.ParseInt(number, 10, 64) + default: + fraction, err = strconv.ParseInt(number[:1], 10, 64) + } } } else { - s = s + "0" + integer, err = strconv.ParseInt(number, 10, 64) + } + + if err != nil { + return 0, 0, fmt.Errorf("%s: expected a number but found '%c'", original, des) + } + + return integer, fraction, err +} + +// scanDigits finds the first non-digit byte after a given starting point. +// Note that it does not care about runes or UTF-8 encoding; it assumes that +// a period string is always valid ASCII as well as UTF-8. +func scanDigits(s string) int { + for i, c := range s { + if !isDigit(c) { + return i + } } + return -1 +} - return strconv.ParseInt(s, 10, 64) +func isDigit(c rune) bool { + return ('0' <= c && c <= '9') || c == '.' || c == ',' } diff --git a/vendor/github.com/rickb777/date/period/period.go b/vendor/github.com/rickb777/date/period/period.go index a9b39c6a0d6..082466f21b6 100644 --- a/vendor/github.com/rickb777/date/period/period.go +++ b/vendor/github.com/rickb777/date/period/period.go @@ -9,14 +9,14 @@ import ( "time" ) -const daysPerYearE4 int64 = 3652425 // 365.2425 days by the Gregorian rule -const daysPerMonthE4 int64 = 304369 // 30.4369 days per month -const daysPerMonthE6 int64 = 30436875 // 30.436875 days per month +const daysPerYearE4 = 3652425 // 365.2425 days by the Gregorian rule +const daysPerMonthE4 = 304369 // 30.4369 days per month +const daysPerMonthE6 = 30436875 // 30.436875 days per month -const oneE4 int64 = 10000 -const oneE5 int64 = 100000 -const oneE6 int64 = 1000000 -const oneE7 int64 = 10000000 +const oneE4 = 10000 +const oneE5 = 100000 +const oneE6 = 1000000 +const oneE7 = 10000000 const hundredMs = 100 * time.Millisecond @@ -42,7 +42,6 @@ const hundredMs = 100 * time.Millisecond // // Note that although fractional weeks can be parsed, they will never be returned via String(). // This is because the number of weeks is always inferred from the number of days. -// type Period struct { years, months, days, hours, minutes, seconds int16 } @@ -52,6 +51,8 @@ type Period struct { // need to. // // All the parameters must have the same sign (otherwise a panic occurs). +// Because this implementation uses int16 internally, the paramters must +// be within the range ± 2^16 / 10. func NewYMD(years, months, days int) Period { return New(years, months, days, 0, 0, 0) } @@ -61,6 +62,8 @@ func NewYMD(years, months, days int) Period { // if you need to. // // All the parameters must have the same sign (otherwise a panic occurs). +// Because this implementation uses int16 internally, the paramters must +// be within the range ± 2^16 / 10. func NewHMS(hours, minutes, seconds int) Period { return New(0, 0, 0, hours, minutes, seconds) } @@ -82,8 +85,6 @@ func New(years, months, days, hours, minutes, seconds int) Period { years, months, days, hours, minutes, seconds)) } -// TODO NewFloat - // NewOf converts a time duration to a Period, and also indicates whether the conversion is precise. // Any time duration that spans more than ± 3276 hours will be approximated by assuming that there // are 24 hours per day, 365.2425 days per year (as per Gregorian calendar rules), and a month @@ -142,28 +143,28 @@ func NewOf(duration time.Duration) (p Period, precise bool) { // computations applied to the period can only be precise if they concern either the date (year, month, // day) part, or the clock (hour, minute, second) part, but not both. func Between(t1, t2 time.Time) (p Period) { - if t1.Location() != t2.Location() { - t2 = t2.In(t1.Location()) - } - sign := 1 if t2.Before(t1) { t1, t2, sign = t2, t1, -1 } - year, month, day, hour, min, sec, hundredth := daysDiff(t1, t2) + if t1.Location() != t2.Location() { + t2 = t2.In(t1.Location()) + } + + year, month, day, hour, min, sec, tenth := daysDiff(t1, t2) if sign < 0 { p = New(-year, -month, -day, -hour, -min, -sec) - p.seconds -= int16(hundredth) + p.seconds -= int16(tenth) } else { p = New(year, month, day, hour, min, sec) - p.seconds += int16(hundredth) + p.seconds += int16(tenth) } return } -func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, hundredth int) { +func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, tenth int) { duration := t2.Sub(t1) hh1, mm1, ss1 := t1.Clock() @@ -171,10 +172,10 @@ func daysDiff(t1, t2 time.Time) (year, month, day, hour, min, sec, hundredth int day = int(duration / (24 * time.Hour)) - hour = int(hh2 - hh1) - min = int(mm2 - mm1) - sec = int(ss2 - ss1) - hundredth = (t2.Nanosecond() - t1.Nanosecond()) / 100000000 + hour = hh2 - hh1 + min = mm2 - mm1 + sec = ss2 - ss1 + tenth = (t2.Nanosecond() - t1.Nanosecond()) / 100000000 // Normalize negative values if sec < 0 { @@ -248,15 +249,22 @@ func (period Period) OnlyHMS() Period { // Abs converts a negative period to a positive one. func (period Period) Abs() Period { - return Period{absInt16(period.years), absInt16(period.months), absInt16(period.days), - absInt16(period.hours), absInt16(period.minutes), absInt16(period.seconds)} + a, _ := period.absNeg() + return a } -func absInt16(v int16) int16 { - if v < 0 { - return -v +func (period Period) absNeg() (Period, bool) { + if period.IsNegative() { + return period.Negate(), true } - return v + return period, false +} + +func (period Period) condNegate(neg bool) Period { + if neg { + return period.Negate() + } + return period } // Negate changes the sign of the period. @@ -264,45 +272,11 @@ func (period Period) Negate() Period { return Period{-period.years, -period.months, -period.days, -period.hours, -period.minutes, -period.seconds} } -// Add adds two periods together. Use this method along with Negate in order to subtract periods. -// -// The result is not normalised and may overflow arithmetically (to make this unlikely, use Normalise on -// the inputs before adding them). -func (period Period) Add(that Period) Period { - return Period{ - period.years + that.years, - period.months + that.months, - period.days + that.days, - period.hours + that.hours, - period.minutes + that.minutes, - period.seconds + that.seconds, - } -} - -// Scale a period by a multiplication factor. Obviously, this can both enlarge and shrink it, -// and change the sign if negative. The result is normalised. -// -// Bear in mind that the internal representation is limited by fixed-point arithmetic with one -// decimal place; each field is only int16. -// -// Known issue: scaling by a large reduction factor (i.e. much less than one) doesn't work properly. -func (period Period) Scale(factor float32) Period { - - if -0.5 < factor && factor < 0.5 { - d, pr1 := period.Duration() - mul := float64(d) * float64(factor) - p2, pr2 := NewOf(time.Duration(mul)) - return p2.Normalise(pr1 && pr2) +func absInt16(v int16) int16 { + if v < 0 { + return -v } - - y := int64(float32(period.years) * factor) - m := int64(float32(period.months) * factor) - d := int64(float32(period.days) * factor) - hh := int64(float32(period.hours) * factor) - mm := int64(float32(period.minutes) * factor) - ss := int64(float32(period.seconds) * factor) - - return (&period64{y, m, d, hh, mm, ss, false}).normalise64(true).toPeriod() + return v } // Years gets the whole number of years in the period. @@ -422,29 +396,7 @@ func (period Period) SecondsFloat() float32 { return float32(period.seconds) / 10 } -// AddTo adds the period to a time, returning the result. -// A flag is also returned that is true when the conversion was precise and false otherwise. -// -// When the period specifies hours, minutes and seconds only, the result is precise. -// Also, when the period specifies whole years, months and days (i.e. without fractions), the -// result is precise. However, when years, months or days contains fractions, the result -// is only an approximation (it assumes that all days are 24 hours and every year is 365.2425 -// days, as per Gregorian calendar rules). -func (period Period) AddTo(t time.Time) (time.Time, bool) { - wholeYears := (period.years % 10) == 0 - wholeMonths := (period.months % 10) == 0 - wholeDays := (period.days % 10) == 0 - - if wholeYears && wholeMonths && wholeDays { - // in this case, time.AddDate provides an exact solution - stE3 := totalSecondsE3(period) - t1 := t.AddDate(int(period.years/10), int(period.months/10), int(period.days/10)) - return t1.Add(stE3 * time.Millisecond), true - } - - d, precise := period.Duration() - return t.Add(d), precise -} +//------------------------------------------------------------------------------------------------- // DurationApprox converts a period to the equivalent duration in nanoseconds. // When the period specifies hours, minutes and seconds only, the result is precise. @@ -514,7 +466,8 @@ func (period Period) TotalMonthsApprox() int { // // Because the number of hours per day is imprecise (due to daylight savings etc), and because // the number of days per month is variable in the Gregorian calendar, there is a reluctance -// to transfer time too or from the days element. To give control over this, there are two modes. +// to transfer time to or from the days element, or to transfer days to or from the months +// element. To give control over this, there are two modes. // // In precise mode: // Multiples of 60 seconds become minutes. @@ -527,220 +480,138 @@ func (period Period) TotalMonthsApprox() int { // // Note that leap seconds are disregarded: every minute is assumed to have 60 seconds. func (period Period) Normalise(precise bool) Period { - const limit = 32670 - (32670 / 60) - - // can we use a quicker algorithm for HHMMSS with int16 arithmetic? - if period.years == 0 && period.months == 0 && - (!precise || period.days == 0) && - period.hours > -limit && period.hours < limit { - - return period.normaliseHHMMSS(precise) - } - - // can we use a quicker algorithm for YYMM with int16 arithmetic? - if (period.years != 0 || period.months != 0) && //period.months%10 == 0 && - period.days == 0 && period.hours == 0 && period.minutes == 0 && period.seconds == 0 { - - return period.normaliseYYMM() - } - - // do things the no-nonsense way using int64 arithmetic - return period.toPeriod64().normalise64(precise).toPeriod() -} - -func (period Period) normaliseHHMMSS(precise bool) Period { - s := period.Sign() - ap := period.Abs() - - // remember that the fields are all fixed-point 1E1 - ap.minutes += (ap.seconds / 600) * 10 - ap.seconds = ap.seconds % 600 - - ap.hours += (ap.minutes / 600) * 10 - ap.minutes = ap.minutes % 600 - - // up to 36 hours stays as hours - if !precise && ap.hours > 360 { - ap.days += (ap.hours / 240) * 10 - ap.hours = ap.hours % 240 - } - - d10 := ap.days % 10 - if d10 != 0 && (ap.hours != 0 || ap.minutes != 0 || ap.seconds != 0) { - ap.hours += d10 * 24 - ap.days -= d10 - } - - hh10 := ap.hours % 10 - if hh10 != 0 { - ap.minutes += hh10 * 60 - ap.hours -= hh10 - } - - mm10 := ap.minutes % 10 - if mm10 != 0 { - ap.seconds += mm10 * 60 - ap.minutes -= mm10 - } - - if s < 0 { - return ap.Negate() - } - return ap -} - -func (period Period) normaliseYYMM() Period { - s := period.Sign() - ap := period.Abs() - - // remember that the fields are all fixed-point 1E1 - if ap.months > 129 { - ap.years += (ap.months / 120) * 10 - ap.months = ap.months % 120 - } - - y10 := ap.years % 10 - if y10 != 0 && (ap.years < 10 || ap.months != 0) { - ap.months += y10 * 12 - ap.years -= y10 - } - - if s < 0 { - return ap.Negate() - } - return ap -} - -//------------------------------------------------------------------------------------------------- - -// used for stages in arithmetic -type period64 struct { - years, months, days, hours, minutes, seconds int64 - neg bool + n, _ := period.toPeriod64("").normalise64(precise).toPeriod() + return n } -func (period Period) toPeriod64() *period64 { - return &period64{ - int64(period.years), int64(period.months), int64(period.days), - int64(period.hours), int64(period.minutes), int64(period.seconds), - false, - } -} - -func (p *period64) toPeriod() Period { - if p.neg { - return Period{ - int16(-p.years), int16(-p.months), int16(-p.days), - int16(-p.hours), int16(-p.minutes), int16(-p.seconds), +// Simplify applies some heuristic simplifications with the objective of reducing the number +// of non-zero fields and thus making the rendered form simpler. It should be applied to +// a normalised period, otherwise the results may be unpredictable. +// +// Note that months and days are never combined, due to the variability of month lengths. +// Days and hours are only combined when imprecise behaviour is selected; this is due to +// daylight savings transitions, during which there are more than or fewer than 24 hours +// per day. +// +// The following transformation rules are applied in order: +// +// * P1YnM becomes 12+n months for 0 < n <= 6 +// * P1DTnH becomes 24+n hours for 0 < n <= 6 (unless precise is true) +// * PT1HnM becomes 60+n minutes for 0 < n <= 10 +// * PT1MnS becomes 60+n seconds for 0 < n <= 10 +// +// At each step, if a fraction exists and would affect the calculation, the transformations +// stop. Also, when not precise, +// +// * for periods of at least ten years, month proper fractions are discarded +// * for periods of at least a year, day proper fractions are discarded +// * for periods of at least a month, hour proper fractions are discarded +// * for periods of at least a day, minute proper fractions are discarded +// * for periods of at least an hour, second proper fractions are discarded +// +// The thresholds can be set using the varargs th parameter. By default, the thresholds a, +// b, c, d are 6 months, 6 hours, 10 minutes, 10 seconds respectively as listed in the rules +// above. +// +// * No thresholds is equivalent to 6, 6, 10, 10. +// * A single threshold a is equivalent to a, a, a, a. +// * Two thresholds a, b are equivalent to a, a, b, b. +// * Three thresholds a, b, c are equivalent to a, b, c, c. +// * Four thresholds a, b, c, d are used as provided. +func (period Period) Simplify(precise bool, th ...int) Period { + switch len(th) { + case 0: + return period.doSimplify(precise, 60, 60, 100, 100) + case 1: + return period.doSimplify(precise, int16(th[0]*10), int16(th[0]*10), int16(th[0]*10), int16(th[0]*10)) + case 2: + return period.doSimplify(precise, int16(th[0]*10), int16(th[0]*10), int16(th[1]*10), int16(th[1]*10)) + case 3: + return period.doSimplify(precise, int16(th[0]*10), int16(th[1]*10), int16(th[2]*10), int16(th[2]*10)) + default: + return period.doSimplify(precise, int16(th[0]*10), int16(th[1]*10), int16(th[2]*10), int16(th[3]*10)) + } +} + +func (period Period) doSimplify(precise bool, a, b, c, d int16) Period { + if period.years%10 != 0 { + return period + } + + ap, neg := period.absNeg() + + // single year is dropped if there are some months + if ap.years == 10 && + 0 < ap.months && ap.months <= a && + ap.days == 0 { + ap.months += 120 + ap.years = 0 + } + + if ap.months%10 != 0 { + // month fraction is dropped for periods of at least ten years (1:120) + months := ap.months / 10 + if !precise && ap.years >= 100 && months == 0 { + ap.months = 0 } + return ap.condNegate(neg) } - return Period{ - int16(p.years), int16(p.months), int16(p.days), - int16(p.hours), int16(p.minutes), int16(p.seconds), - } -} - -func (p *period64) normalise64(precise bool) *period64 { - return p.abs().rippleUp(precise).moveFractionToRight() -} - -func (p *period64) abs() *period64 { - - if !p.neg { - if p.years < 0 { - p.years = -p.years - p.neg = true - } - - if p.months < 0 { - p.months = -p.months - p.neg = true - } - - if p.days < 0 { - p.days = -p.days - p.neg = true + if ap.days%10 != 0 { + // day fraction is dropped for periods of at least a year (1:365) + days := ap.days / 10 + if !precise && (ap.years > 0 || ap.months >= 120) && days == 0 { + ap.days = 0 } - - if p.hours < 0 { - p.hours = -p.hours - p.neg = true - } - - if p.minutes < 0 { - p.minutes = -p.minutes - p.neg = true - } - - if p.seconds < 0 { - p.seconds = -p.seconds - p.neg = true - } - } - return p -} - -func (p *period64) rippleUp(precise bool) *period64 { - // remember that the fields are all fixed-point 1E1 - - p.minutes = p.minutes + (p.seconds/600)*10 - p.seconds = p.seconds % 600 - - p.hours = p.hours + (p.minutes/600)*10 - p.minutes = p.minutes % 600 - - // 32670-(32670/60)-(32670/3600) = 32760 - 546 - 9.1 = 32204.9 - if !precise || p.hours > 32204 { - p.days += (p.hours / 240) * 10 - p.hours = p.hours % 240 + return ap.condNegate(neg) } - if !precise || p.days > 32760 { - dE6 := p.days * oneE6 - p.months += dE6 / daysPerMonthE6 - p.days = (dE6 % daysPerMonthE6) / oneE6 + if !precise && ap.days == 10 && + ap.years == 0 && + ap.months == 0 && + 0 < ap.hours && ap.hours <= b { + ap.hours += 240 + ap.days = 0 } - p.years = p.years + (p.months/120)*10 - p.months = p.months % 120 - - return p -} - -// moveFractionToRight applies the rule that only the smallest field is permitted to have a decimal fraction. -func (p *period64) moveFractionToRight() *period64 { - // remember that the fields are all fixed-point 1E1 - - y10 := p.years % 10 - if y10 != 0 && (p.months != 0 || p.days != 0 || p.hours != 0 || p.minutes != 0 || p.seconds != 0) { - p.months += y10 * 12 - p.years = (p.years / 10) * 10 + if ap.hours%10 != 0 { + // hour fraction is dropped for periods of at least a month (1:720) + hours := ap.hours / 10 + if !precise && (ap.years > 0 || ap.months > 0 || ap.days >= 300) && hours == 0 { + ap.hours = 0 + } + return ap.condNegate(neg) } - m10 := p.months % 10 - if m10 != 0 && (p.days != 0 || p.hours != 0 || p.minutes != 0 || p.seconds != 0) { - p.days += (m10 * daysPerMonthE6) / oneE6 - p.months = (p.months / 10) * 10 + if ap.hours == 10 && + 0 < ap.minutes && ap.minutes <= c { + ap.minutes += 600 + ap.hours = 0 } - d10 := p.days % 10 - if d10 != 0 && (p.hours != 0 || p.minutes != 0 || p.seconds != 0) { - p.hours += d10 * 24 - p.days = (p.days / 10) * 10 + if ap.minutes%10 != 0 { + // minute fraction is dropped for periods of at least a day (1:1440) + minutes := ap.minutes / 10 + if !precise && (ap.years > 0 || ap.months > 0 || ap.days > 0 || ap.hours >= 240) && minutes == 0 { + ap.minutes = 0 + } + return ap.condNegate(neg) } - hh10 := p.hours % 10 - if hh10 != 0 && (p.minutes != 0 || p.seconds != 0) { - p.minutes += hh10 * 60 - p.hours = (p.hours / 10) * 10 + if ap.minutes == 10 && + ap.hours == 0 && + 0 < ap.seconds && ap.seconds <= d { + ap.seconds += 600 + ap.minutes = 0 } - mm10 := p.minutes % 10 - if mm10 != 0 && p.seconds != 0 { - p.seconds += mm10 * 60 - p.minutes = (p.minutes / 10) * 10 + if ap.seconds%10 != 0 { + // second fraction is dropped for periods of at least an hour (1:3600) + seconds := ap.seconds / 10 + if !precise && (ap.years > 0 || ap.months > 0 || ap.days > 0 || ap.hours > 0 || ap.minutes >= 600) && seconds == 0 { + ap.seconds = 0 + } } - return p + return ap.condNegate(neg) } diff --git a/vendor/github.com/rickb777/date/period/period64.go b/vendor/github.com/rickb777/date/period/period64.go new file mode 100644 index 00000000000..f3e2f4b0bce --- /dev/null +++ b/vendor/github.com/rickb777/date/period/period64.go @@ -0,0 +1,142 @@ +package period + +import ( + "fmt" + "math" + "strings" +) + +// used for stages in arithmetic +type period64 struct { + // always positive values + years, months, days, hours, minutes, seconds int64 + // true if the period is negative + neg bool + input string +} + +func (period Period) toPeriod64(input string) *period64 { + if period.IsNegative() { + return &period64{ + years: int64(-period.years), months: int64(-period.months), days: int64(-period.days), + hours: int64(-period.hours), minutes: int64(-period.minutes), seconds: int64(-period.seconds), + neg: true, + input: input, + } + } + return &period64{ + years: int64(period.years), months: int64(period.months), days: int64(period.days), + hours: int64(period.hours), minutes: int64(period.minutes), seconds: int64(period.seconds), + input: input, + } +} + +func (p64 *period64) toPeriod() (Period, error) { + var f []string + if p64.years > math.MaxInt16 { + f = append(f, "years") + } + if p64.months > math.MaxInt16 { + f = append(f, "months") + } + if p64.days > math.MaxInt16 { + f = append(f, "days") + } + if p64.hours > math.MaxInt16 { + f = append(f, "hours") + } + if p64.minutes > math.MaxInt16 { + f = append(f, "minutes") + } + if p64.seconds > math.MaxInt16 { + f = append(f, "seconds") + } + + if len(f) > 0 { + if p64.input == "" { + p64.input = p64.String() + } + return Period{}, fmt.Errorf("%s: integer overflow occurred in %s", p64.input, strings.Join(f, ",")) + } + + if p64.neg { + return Period{ + int16(-p64.years), int16(-p64.months), int16(-p64.days), + int16(-p64.hours), int16(-p64.minutes), int16(-p64.seconds), + }, nil + } + + return Period{ + int16(p64.years), int16(p64.months), int16(p64.days), + int16(p64.hours), int16(p64.minutes), int16(p64.seconds), + }, nil +} + +func (p64 *period64) normalise64(precise bool) *period64 { + return p64.rippleUp(precise).moveFractionToRight() +} + +func (p64 *period64) rippleUp(precise bool) *period64 { + // remember that the fields are all fixed-point 1E1 + + p64.minutes += (p64.seconds / 600) * 10 + p64.seconds = p64.seconds % 600 + + p64.hours += (p64.minutes / 600) * 10 + p64.minutes = p64.minutes % 600 + + // 32670-(32670/60)-(32670/3600) = 32760 - 546 - 9.1 = 32204.9 + if !precise || p64.hours > 32204 { + p64.days += (p64.hours / 240) * 10 + p64.hours = p64.hours % 240 + } + + if !precise || p64.days > 32760 { + dE6 := p64.days * oneE5 + p64.months += (dE6 / daysPerMonthE6) * 10 + p64.days = (dE6 % daysPerMonthE6) / oneE5 + } + + p64.years += (p64.months / 120) * 10 + p64.months = p64.months % 120 + + return p64 +} + +// moveFractionToRight attempts to remove fractions in higher-order fields by moving their value to the +// next-lower-order field. For example, fractional years become months. +func (p64 *period64) moveFractionToRight() *period64 { + // remember that the fields are all fixed-point 1E1 + + y10 := p64.years % 10 + if y10 != 0 && (p64.months != 0 || p64.days != 0 || p64.hours != 0 || p64.minutes != 0 || p64.seconds != 0) { + p64.months += y10 * 12 + p64.years = (p64.years / 10) * 10 + } + + m10 := p64.months % 10 + if m10 != 0 && (p64.days != 0 || p64.hours != 0 || p64.minutes != 0 || p64.seconds != 0) { + p64.days += (m10 * daysPerMonthE6) / oneE6 + p64.months = (p64.months / 10) * 10 + } + + d10 := p64.days % 10 + if d10 != 0 && (p64.hours != 0 || p64.minutes != 0 || p64.seconds != 0) { + p64.hours += d10 * 24 + p64.days = (p64.days / 10) * 10 + } + + hh10 := p64.hours % 10 + if hh10 != 0 && (p64.minutes != 0 || p64.seconds != 0) { + p64.minutes += hh10 * 60 + p64.hours = (p64.hours / 10) * 10 + } + + mm10 := p64.minutes % 10 + if mm10 != 0 && p64.seconds != 0 { + p64.seconds += mm10 * 60 + p64.minutes = (p64.minutes / 10) * 10 + } + + return p64 +} diff --git a/vendor/github.com/rickb777/date/period/sql.go b/vendor/github.com/rickb777/date/period/sql.go new file mode 100644 index 00000000000..31b546429aa --- /dev/null +++ b/vendor/github.com/rickb777/date/period/sql.go @@ -0,0 +1,36 @@ +// Copyright 2015 Rick Beton. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package period + +import ( + "database/sql/driver" + "fmt" +) + +// Scan parses some value, which can be either string or []byte. +// It implements sql.Scanner, https://golang.org/pkg/database/sql/#Scanner +func (period *Period) Scan(value interface{}) (err error) { + if value == nil { + return nil + } + + err = nil + switch v := value.(type) { + case []byte: + *period, err = Parse(string(v), false) + case string: + *period, err = Parse(v, false) + default: + err = fmt.Errorf("%T %+v is not a meaningful period", value, value) + } + + return err +} + +// Value converts the period to a string. It implements driver.Valuer, +// https://golang.org/pkg/database/sql/driver/#Valuer +func (period Period) Value() (driver.Value, error) { + return period.String(), nil +} diff --git a/vendor/github.com/rickb777/plural/README.md b/vendor/github.com/rickb777/plural/README.md index b73bc256669..1085b1087ba 100644 --- a/vendor/github.com/rickb777/plural/README.md +++ b/vendor/github.com/rickb777/plural/README.md @@ -1,7 +1,7 @@ # plural - Simple Go API for Pluralisation. [![GoDoc](https://img.shields.io/badge/api-Godoc-blue.svg?style=flat-square)](https://godoc.org/github.com/rickb777/plural) -[![Build Status](https://travis-ci.org/rickb777/plural.svg?branch=master)](https://travis-ci.org/rickb777/plural) +[![Build Status](https://travis-ci.org/rickb777/plural.svg?branch=master)](https://travis-ci.org/rickb777/plural/builds) [![Coverage Status](https://coveralls.io/repos/github/rickb777/plural/badge.svg?branch=master&service=github)](https://coveralls.io/github/rickb777/plural?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/rickb777/plural)](https://goreportcard.com/report/github.com/rickb777/plural) [![Issues](https://img.shields.io/github/issues/rickb777/plural.svg)](https://github.com/rickb777/plural/issues) diff --git a/vendor/github.com/rickb777/plural/build+test.sh b/vendor/github.com/rickb777/plural/build+test.sh index dbfbd6d4f27..17b15af2566 100644 --- a/vendor/github.com/rickb777/plural/build+test.sh +++ b/vendor/github.com/rickb777/plural/build+test.sh @@ -1,13 +1,13 @@ #!/bin/bash -e -cd $(dirname $0) -PATH=$HOME/go/bin:$GOPATH/bin:$PATH +cd "$(dirname $0)" +PATH=$HOME/go/bin:$PATH if ! type -p goveralls; then - echo go get github.com/mattn/goveralls - go get github.com/mattn/goveralls + echo go install github.com/mattn/goveralls + go install github.com/mattn/goveralls fi -echo date... +echo plural... go test -v -covermode=count -coverprofile=date.out . go tool cover -func=date.out [ -z "$COVERALLS_TOKEN" ] || goveralls -coverprofile=date.out -service=travis-ci -repotoken $COVERALLS_TOKEN diff --git a/vendor/modules.txt b/vendor/modules.txt index cd99817ced3..b7b141968d4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -293,11 +293,11 @@ github.com/prometheus/procfs/internal/util github.com/prometheus/statsd_exporter/pkg/level github.com/prometheus/statsd_exporter/pkg/mapper github.com/prometheus/statsd_exporter/pkg/mapper/fsm -# github.com/rickb777/date v1.13.0 -## explicit; go 1.14 +# github.com/rickb777/date v1.21.1 +## explicit; go 1.17 github.com/rickb777/date/period -# github.com/rickb777/plural v1.2.1 -## explicit; go 1.14 +# github.com/rickb777/plural v1.4.2 +## explicit; go 1.17 github.com/rickb777/plural # github.com/robfig/cron/v3 v3.0.1 ## explicit; go 1.12