diff --git a/date.go b/date.go index 8c776f3..da813f7 100644 --- a/date.go +++ b/date.go @@ -19,7 +19,7 @@ type PeriodOfDays int32 // ZeroDays is the named zero value for PeriodOfDays. const ZeroDays PeriodOfDays = 0 -// A Date represents a date under the (proleptic) Gregorian calendar as +// A Date represents a date under the proleptic Gregorian calendar as // used by ISO 8601. This calendar uses astronomical year numbering, // so it includes a year 0 and represents earlier years as negative numbers // (i.e. year 0 is 1 BC; year -1 is 2 BC, and so on). @@ -30,8 +30,8 @@ const ZeroDays PeriodOfDays = 0 // // Programs using dates should typically store and pass them as values, // not pointers. That is, date variables and struct fields should be of -// type date.Date, not *date.Date. A Date value can be used by -// multiple goroutines simultaneously. +// type date.Date, not *date.Date unless the pointer indicates an optional +// value. A Date value can be used by multiple goroutines simultaneously. // // Date values can be compared using the Before, After, and Equal methods // as well as the == and != operators. @@ -40,9 +40,9 @@ const ZeroDays PeriodOfDays = 0 // them. The Add method adds a Date and a number of days, producing a Date. // // The zero value of type Date is Thursday, January 1, 1970 (called 'the -// epoch'), based on Unix convention. As this date is unlikely to come up in -// practice, the IsZero method gives a simple way of detecting a date that -// has not been initialized explicitly. +// epoch'), based on Unix convention. The IsZero method gives a simple way +// of detecting a date that has not been initialized explicitly, with the +// caveat that this is also a 'normal' date. // // The first official date of the Gregorian calendar was Friday, October 15th // 1582, quite unrelated to the epoch used here. The Date type does not @@ -188,7 +188,9 @@ func (d Date) ISOWeek() (year, week int) { return t.ISOWeek() } -// IsZero reports whether t represents the zero date. +// IsZero reports whether d represents the zero (i.e. uninitialised) date. +// Because Date follows Unix conventions, it is based on 1970-01-01. So be +// careful with this: the corresponding 1970-01-01 date is not itself a 'zero'. func (d Date) IsZero() bool { return d.day == 0 } @@ -272,12 +274,12 @@ func (d Date) DaysSinceEpoch() (days PeriodOfDays) { return d.day } -// IsLeap simply tests whether a given year is a leap year, using the Gregorian calendar algorithm. +// IsLeap simply tests whether a given year is a leap year, using the proleptic Gregorian calendar algorithm. func IsLeap(year int) bool { return gregorian.IsLeap(year) } -// DaysIn gives the number of days in a given month, according to the Gregorian calendar. +// DaysIn gives the number of days in a given month, according to the proleptic Gregorian calendar. func DaysIn(year int, month time.Month) int { return gregorian.DaysIn(year, month) } diff --git a/date_test.go b/date_test.go index 39bf6e6..085e3b2 100644 --- a/date_test.go +++ b/date_test.go @@ -52,6 +52,32 @@ func TestDate_New(t *testing.T) { } } +func Test_New_and_Add(t *testing.T) { + cases := []struct { + offset PeriodOfDays + expected Date + }{ + // For year Y, Julian date offset is + // D = [Y/100] - [Y/400] - 2 + {offset: -135140, expected: New(1600, time.January, 1)}, // 10 days Julian offset + {offset: -98615, expected: New(1700, time.January, 1)}, // 10 days Julian offset + {offset: -62091, expected: New(1800, time.January, 1)}, + {offset: -365, expected: New(1969, time.January, 1)}, + {offset: 0, expected: New(1970, time.January, 1)}, + {offset: 365, expected: New(1971, time.January, 1)}, + {offset: 36525, expected: New(2070, time.January, 1)}, + } + + zero := Date{} + + for i, c := range cases { + d2 := zero.Add(c.offset) + if !d2.Equal(c.expected) { + t.Errorf("%d: %d gives %s, wanted %s", i, c.offset, d2, c.expected) + } + } +} + func TestDate_DaysSinceEpoch(t *testing.T) { zero := Date{}.DaysSinceEpoch() if zero != 0 { @@ -178,21 +204,21 @@ func testPredicate(t *testing.T, di, dj Date, p, q bool, m string) { } func TestArithmetic(t *testing.T) { - cases := []struct { - d Date - }{ - {New(-1234, time.February, 5)}, - {New(0, time.April, 12)}, - {New(1, time.January, 1)}, - {New(1946, time.February, 4)}, - {New(1970, time.January, 1)}, - {New(1976, time.April, 1)}, - {New(1999, time.December, 1)}, - {New(1111111, time.June, 21)}, + dates := []Date{ + New(-1234, time.February, 5), + New(0, time.April, 12), + New(1, time.January, 1), + New(1946, time.February, 4), + New(1970, time.January, 1), + New(1976, time.April, 1), + New(1999, time.December, 1), + New(1111111, time.June, 21), } + offsets := []PeriodOfDays{-1000000, -9999, -555, -99, -22, -1, 0, 1, 22, 99, 555, 9999, 1000000} - for _, c := range cases { - di := c.d + + for _, d := range dates { + di := d for _, days := range offsets { dj := di.Add(days) days2 := dj.Sub(di) diff --git a/go.mod b/go.mod index 3dbf411..fab3173 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,8 @@ require ( ) require ( - github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 // indirect golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect - golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 94e9049..d40a23e 100644 --- a/go.sum +++ b/go.sum @@ -38,8 +38,6 @@ github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rickb777/plural v1.4.1 h1:5MMLcbIaapLFmvDGRT5iPk8877hpTPt8Y9cdSKRw9sU= github.com/rickb777/plural v1.4.1/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= -github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518 h1:iD+PFTQwKEmbwSdwfvP5ld2WEI/g7qbdhmHJ2ASfYGs= -github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -82,7 +80,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/parse_test.go b/parse_test.go index f846c3e..cb22d14 100644 --- a/parse_test.go +++ b/parse_test.go @@ -16,12 +16,13 @@ func TestAutoParse(t *testing.T) { month time.Month day int }{ + {"01-01-1970", 1970, time.January, 1}, + {"+1970-01-01", 1970, time.January, 1}, + {"+01970-01-02", 1970, time.January, 2}, {" 31/12/1969 ", 1969, time.December, 31}, {"1969/12/31", 1969, time.December, 31}, {"1969.12.31", 1969, time.December, 31}, {"1969-12-31", 1969, time.December, 31}, - {"+1970-01-01", 1970, time.January, 1}, - {"+01970-01-02", 1970, time.January, 2}, {"2000-02-28", 2000, time.February, 28}, {"+2000-02-29", 2000, time.February, 29}, {"+02000-03-01", 2000, time.March, 1}, diff --git a/sql.go b/sql.go index 426cc45..ec10c10 100644 --- a/sql.go +++ b/sql.go @@ -104,10 +104,5 @@ func (ds DateString) Value() (driver.Value, error) { //------------------------------------------------------------------------------------------------- -// DisableTextStorage reduces the Scan method so that only integers are handled. -// Normally, database types int64, []byte, string and time.Time are supported. -// When set true, only int64 is supported; this mode allows optimisation of SQL -// result processing and would only be used during development. -// -// Deprecated: this is no longer used. +// Deprecated: DisableTextStorage is no longer used. var DisableTextStorage = false