-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathdate.go
209 lines (181 loc) · 7.14 KB
/
date.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package date
import (
"math"
"time"
"github.com/rickb777/date/v2/clock"
"github.com/rickb777/date/v2/gregorian"
"github.com/rickb777/period"
)
// 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).
//
// A Date is a 64-bit integer, so the total range is huge.
//
// 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 unless the pointer indicates an optional
// value. A Date value can be used by multiple goroutines simultaneously.
//
// Date values can be compared using the ==, !=, >, >=, <, and <= operators.
//
// Because a Date is a number of days since [Zero], + and - operations
// add or subtract some number of days.
//
// The zero value of Date is equivalent to the zero value of [time.Time];
// the zero value of [time.Time] is January 1, year 1, 00:00:00.000000000 UTC.
//
// Date does not distinguish between official Gregorian dates and earlier
// proleptic dates, which can also be represented when needed.
//
// Although the first official date of the Gregorian calendar was Friday,
// October 15th 1582, this is unrelated to the Unix epoch or day 0 used here.
// However, for a date before 1582 to be meaningful, it must be clarified
// separately whether it is a proleptic Gregorian date, or a Julian date, or
// some other.
type Date int64
const (
// Zero is the named zero value for Date and corresponds to
// Monday, January 1, year 1 AD in the proleptic Gregorian calendar.
// This is the same zero as used by [time.Time].
Zero Date = 0
// ZeroDay was the day of 1st January year 1 AD.
ZeroDay = time.Monday
// ZeroOffset is the number of days between 0001-01-01 and 1970-01-01, using the
// proleptic Gregorian calendar. It is based on the same Unix calculation as used
// by [time.Time].
//
// It is similar to the "Rata Die" numbering system, for which the offset would
// be 719163 instead.
ZeroOffset = 719162
)
// New returns the Date value corresponding to the given year, month, and day.
//
// The month and day may be outside their usual ranges and will be normalized
// during the conversion.
func New(year int, month time.Month, day int) Date {
t := time.Date(year, month, day, 12, 0, 0, 0, time.UTC)
return encode(t)
}
// NewAt returns the Date value corresponding to the given time.
// Note that the date is relative to the time zone specified by
// the given Time value.
func NewAt(t time.Time) Date {
return encode(t)
}
// Today returns today's date according to the current local time.
func Today() Date {
return encode(time.Now())
}
// TodayUTC returns today's date according to the current UTC time.
func TodayUTC() Date {
return encode(time.Now().UTC())
}
// TodayIn returns today's date according to the current time relative to
// the specified location.
func TodayIn(loc *time.Location) Date {
t := time.Now().In(loc)
return encode(t)
}
// Min returns the smallest representable date, which is nearly 6 million years in the past.
func Min() Date {
return Date(math.MinInt32 + 1)
}
// Max returns the largest representable date, which is nearly 6 million years in the future.
func Max() Date {
return Date(math.MaxInt32 - ZeroOffset)
}
// MidnightUTC returns a [time.Time] value corresponding to midnight on the given date d,
// UTC time. Note that midnight is the beginning of the day rather than the end.
func (d Date) MidnightUTC() time.Time {
return decode(d)
}
// Midnight returns a [time.Time] value corresponding to midnight on the given date d,
// local time. Note that midnight is the beginning of the day rather than the end.
func (d Date) Midnight() time.Time {
return d.MidnightIn(time.Local)
}
// MidnightIn returns a [time.Time] value corresponding to midnight on the given date d,
// relative to the specified time zone. Note that midnight is the beginning
// of the day rather than the end.
func (d Date) MidnightIn(loc *time.Location) time.Time {
return d.Time(0, loc)
}
// Time returns a [time.Time] value corresponding to a clock time on the given date d,
// relative to the specified time zone. A common use-case is to obtain the midnight
// time, for which the clock value is simply zero.
func (d Date) Time(clock clock.Clock, loc *time.Location) time.Time {
t := decode(d).In(loc)
_, offset := t.Zone()
return t.Add(time.Duration(-offset) * time.Second).Add(time.Duration(clock))
}
// Date returns the year, month, and day of d.
// The first day of the month is 1.
func (d Date) Date() (year int, month time.Month, day int) {
return decode(d).Date()
}
// LastDayOfMonth returns the last day of the month specified by d.
// The first day of the month is 1.
func (d Date) LastDayOfMonth() int {
y, m, _ := d.Date()
return gregorian.DaysIn(y, m)
}
// Day returns the day of the month specified by d.
// The first day of the month is 1.
func (d Date) Day() int {
return decode(d).Day()
}
// Month returns the month of the year specified by d.
func (d Date) Month() time.Month {
return decode(d).Month()
}
// Year returns the year specified by d.
func (d Date) Year() int {
return decode(d).Year()
}
// YearDay returns the day of the year specified by d, in the range [1,365] for
// non-leap years, and [1,366] in leap years.
func (d Date) YearDay() int {
return decode(d).YearDay()
}
// Weekday returns the day of the week specified by d.
func (d Date) Weekday() time.Weekday {
// Taking into account potential for overflow and negative offset
return time.Weekday((int(ZeroDay) + int(d)%7 + 7) % 7)
}
// ISOWeek returns the ISO 8601 year and week number in which d occurs.
// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to
// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1
// of year n+1.
func (d Date) ISOWeek() (year, week int) {
return decode(d).ISOWeek()
}
// AddDate returns the date corresponding to adding the given number of years,
// months, and days to d. For example, AddData(-1, 2, 3) applied to
// January 1, 2011 returns March 4, 2010.
//
// AddDate normalizes its result in the same way that Date does,
// so, for example, adding one month to October 31 yields
// December 1, the normalized form for November 31.
//
// The addition of all fields is performed before normalisation of any; this can affect
// the result. For example, adding 0y 1m 3d to September 28 gives October 31 (not
// November 1).
func (d Date) AddDate(years, months, days int) Date {
t := decode(d).AddDate(years, months, days)
return encode(t)
}
// AddPeriod returns the date corresponding to adding the given period. If the
// period's fields are be negative, this results in an earlier date.
//
// Any time component only affects the result for periods containing
// more that 24 hours in the hours/minutes/seconds fields
func (d Date) AddPeriod(delta period.Period) Date {
t1 := decode(d)
t2, _ := delta.AddTo(t1)
return encode(t2)
}