diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-11-24 13:14:34 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2022-11-24 14:46:00 +0300 |
commit | 87f7fceed34bcafb8aaff351dd493a35c916986f (patch) | |
tree | 26809ec8f550aba8eb019e59adc3d48e51913eb2 /contrib/go/_std_1.18/src/time | |
parent | 11bc4015b8010ae201bf3eb33db7dba425aca35e (diff) | |
download | ydb-87f7fceed34bcafb8aaff351dd493a35c916986f.tar.gz |
Ydb stable 22-4-4322.4.43
x-stable-origin-commit: 8d49d46cc834835bf3e50870516acd7376a63bcf
Diffstat (limited to 'contrib/go/_std_1.18/src/time')
-rw-r--r-- | contrib/go/_std_1.18/src/time/format.go | 1608 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/sleep.go | 177 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/sys_unix.go | 54 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/tick.go | 73 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/time.go | 1581 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/zoneinfo.go | 687 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/zoneinfo_read.go | 586 | ||||
-rw-r--r-- | contrib/go/_std_1.18/src/time/zoneinfo_unix.go | 69 |
8 files changed, 4835 insertions, 0 deletions
diff --git a/contrib/go/_std_1.18/src/time/format.go b/contrib/go/_std_1.18/src/time/format.go new file mode 100644 index 0000000000..33e6543289 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/format.go @@ -0,0 +1,1608 @@ +// Copyright 2010 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 time + +import "errors" + +// These are predefined layouts for use in Time.Format and time.Parse. +// The reference time used in these layouts is the specific time stamp: +// 01/02 03:04:05PM '06 -0700 +// (January 2, 15:04:05, 2006, in time zone seven hours west of GMT). +// That value is recorded as the constant named Layout, listed below. As a Unix +// time, this is 1136239445. Since MST is GMT-0700, the reference would be +// printed by the Unix date command as: +// Mon Jan 2 15:04:05 MST 2006 +// It is a regrettable historic error that the date uses the American convention +// of putting the numerical month before the day. +// +// The example for Time.Format demonstrates the working of the layout string +// in detail and is a good reference. +// +// Note that the RFC822, RFC850, and RFC1123 formats should be applied +// only to local times. Applying them to UTC times will use "UTC" as the +// time zone abbreviation, while strictly speaking those RFCs require the +// use of "GMT" in that case. +// In general RFC1123Z should be used instead of RFC1123 for servers +// that insist on that format, and RFC3339 should be preferred for new protocols. +// RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; +// when used with time.Parse they do not accept all the time formats +// permitted by the RFCs and they do accept time formats not formally defined. +// The RFC3339Nano format removes trailing zeros from the seconds field +// and thus may not sort correctly once formatted. +// +// Most programs can use one of the defined constants as the layout passed to +// Format or Parse. The rest of this comment can be ignored unless you are +// creating a custom layout string. +// +// To define your own format, write down what the reference time would look like +// formatted your way; see the values of constants like ANSIC, StampMicro or +// Kitchen for examples. The model is to demonstrate what the reference time +// looks like so that the Format and Parse methods can apply the same +// transformation to a general time value. +// +// Here is a summary of the components of a layout string. Each element shows by +// example the formatting of an element of the reference time. Only these values +// are recognized. Text in the layout string that is not recognized as part of +// the reference time is echoed verbatim during Format and expected to appear +// verbatim in the input to Parse. +// +// Year: "2006" "06" +// Month: "Jan" "January" +// Textual day of the week: "Mon" "Monday" +// Numeric day of the month: "2" "_2" "02" +// Numeric day of the year: "__2" "002" +// Hour: "15" "3" "03" (PM or AM) +// Minute: "4" "04" +// Second: "5" "05" +// AM/PM mark: "PM" +// +// Numeric time zone offsets format as follows: +// "-0700" ±hhmm +// "-07:00" ±hh:mm +// "-07" ±hh +// Replacing the sign in the format with a Z triggers +// the ISO 8601 behavior of printing Z instead of an +// offset for the UTC zone. Thus: +// "Z0700" Z or ±hhmm +// "Z07:00" Z or ±hh:mm +// "Z07" Z or ±hh +// +// Within the format string, the underscores in "_2" and "__2" represent spaces +// that may be replaced by digits if the following number has multiple digits, +// for compatibility with fixed-width Unix time formats. A leading zero represents +// a zero-padded value. +// +// The formats __2 and 002 are space-padded and zero-padded +// three-character day of year; there is no unpadded day of year format. +// +// A comma or decimal point followed by one or more zeros represents +// a fractional second, printed to the given number of decimal places. +// A comma or decimal point followed by one or more nines represents +// a fractional second, printed to the given number of decimal places, with +// trailing zeros removed. +// For example "15:04:05,000" or "15:04:05.000" formats or parses with +// millisecond precision. +// +// Some valid layouts are invalid time values for time.Parse, due to formats +// such as _ for space padding and Z for zone information. +// +const ( + Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. + ANSIC = "Mon Jan _2 15:04:05 2006" + UnixDate = "Mon Jan _2 15:04:05 MST 2006" + RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + RFC822 = "02 Jan 06 15:04 MST" + RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone + RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" + RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone + RFC3339 = "2006-01-02T15:04:05Z07:00" + RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" + Kitchen = "3:04PM" + // Handy time stamps. + Stamp = "Jan _2 15:04:05" + StampMilli = "Jan _2 15:04:05.000" + StampMicro = "Jan _2 15:04:05.000000" + StampNano = "Jan _2 15:04:05.000000000" +) + +const ( + _ = iota + stdLongMonth = iota + stdNeedDate // "January" + stdMonth // "Jan" + stdNumMonth // "1" + stdZeroMonth // "01" + stdLongWeekDay // "Monday" + stdWeekDay // "Mon" + stdDay // "2" + stdUnderDay // "_2" + stdZeroDay // "02" + stdUnderYearDay // "__2" + stdZeroYearDay // "002" + stdHour = iota + stdNeedClock // "15" + stdHour12 // "3" + stdZeroHour12 // "03" + stdMinute // "4" + stdZeroMinute // "04" + stdSecond // "5" + stdZeroSecond // "05" + stdLongYear = iota + stdNeedDate // "2006" + stdYear // "06" + stdPM = iota + stdNeedClock // "PM" + stdpm // "pm" + stdTZ = iota // "MST" + stdISO8601TZ // "Z0700" // prints Z for UTC + stdISO8601SecondsTZ // "Z070000" + stdISO8601ShortTZ // "Z07" + stdISO8601ColonTZ // "Z07:00" // prints Z for UTC + stdISO8601ColonSecondsTZ // "Z07:00:00" + stdNumTZ // "-0700" // always numeric + stdNumSecondsTz // "-070000" + stdNumShortTZ // "-07" // always numeric + stdNumColonTZ // "-07:00" // always numeric + stdNumColonSecondsTZ // "-07:00:00" + stdFracSecond0 // ".0", ".00", ... , trailing zeros included + stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted + + stdNeedDate = 1 << 8 // need month, day, year + stdNeedClock = 2 << 8 // need hour, minute, second + stdArgShift = 16 // extra argument in high bits, above low stdArgShift + stdSeparatorShift = 28 // extra argument in high 4 bits for fractional second separators + stdMask = 1<<stdArgShift - 1 // mask out argument +) + +// std0x records the std values for "01", "02", ..., "06". +var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear} + +// startsWithLowerCase reports whether the string has a lower-case letter at the beginning. +// Its purpose is to prevent matching strings like "Month" when looking for "Mon". +func startsWithLowerCase(str string) bool { + if len(str) == 0 { + return false + } + c := str[0] + return 'a' <= c && c <= 'z' +} + +// nextStdChunk finds the first occurrence of a std string in +// layout and returns the text before, the std string, and the text after. +func nextStdChunk(layout string) (prefix string, std int, suffix string) { + for i := 0; i < len(layout); i++ { + switch c := int(layout[i]); c { + case 'J': // January, Jan + if len(layout) >= i+3 && layout[i:i+3] == "Jan" { + if len(layout) >= i+7 && layout[i:i+7] == "January" { + return layout[0:i], stdLongMonth, layout[i+7:] + } + if !startsWithLowerCase(layout[i+3:]) { + return layout[0:i], stdMonth, layout[i+3:] + } + } + + case 'M': // Monday, Mon, MST + if len(layout) >= i+3 { + if layout[i:i+3] == "Mon" { + if len(layout) >= i+6 && layout[i:i+6] == "Monday" { + return layout[0:i], stdLongWeekDay, layout[i+6:] + } + if !startsWithLowerCase(layout[i+3:]) { + return layout[0:i], stdWeekDay, layout[i+3:] + } + } + if layout[i:i+3] == "MST" { + return layout[0:i], stdTZ, layout[i+3:] + } + } + + case '0': // 01, 02, 03, 04, 05, 06, 002 + if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { + return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:] + } + if len(layout) >= i+3 && layout[i+1] == '0' && layout[i+2] == '2' { + return layout[0:i], stdZeroYearDay, layout[i+3:] + } + + case '1': // 15, 1 + if len(layout) >= i+2 && layout[i+1] == '5' { + return layout[0:i], stdHour, layout[i+2:] + } + return layout[0:i], stdNumMonth, layout[i+1:] + + case '2': // 2006, 2 + if len(layout) >= i+4 && layout[i:i+4] == "2006" { + return layout[0:i], stdLongYear, layout[i+4:] + } + return layout[0:i], stdDay, layout[i+1:] + + case '_': // _2, _2006, __2 + if len(layout) >= i+2 && layout[i+1] == '2' { + //_2006 is really a literal _, followed by stdLongYear + if len(layout) >= i+5 && layout[i+1:i+5] == "2006" { + return layout[0 : i+1], stdLongYear, layout[i+5:] + } + return layout[0:i], stdUnderDay, layout[i+2:] + } + if len(layout) >= i+3 && layout[i+1] == '_' && layout[i+2] == '2' { + return layout[0:i], stdUnderYearDay, layout[i+3:] + } + + case '3': + return layout[0:i], stdHour12, layout[i+1:] + + case '4': + return layout[0:i], stdMinute, layout[i+1:] + + case '5': + return layout[0:i], stdSecond, layout[i+1:] + + case 'P': // PM + if len(layout) >= i+2 && layout[i+1] == 'M' { + return layout[0:i], stdPM, layout[i+2:] + } + + case 'p': // pm + if len(layout) >= i+2 && layout[i+1] == 'm' { + return layout[0:i], stdpm, layout[i+2:] + } + + case '-': // -070000, -07:00:00, -0700, -07:00, -07 + if len(layout) >= i+7 && layout[i:i+7] == "-070000" { + return layout[0:i], stdNumSecondsTz, layout[i+7:] + } + if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" { + return layout[0:i], stdNumColonSecondsTZ, layout[i+9:] + } + if len(layout) >= i+5 && layout[i:i+5] == "-0700" { + return layout[0:i], stdNumTZ, layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == "-07:00" { + return layout[0:i], stdNumColonTZ, layout[i+6:] + } + if len(layout) >= i+3 && layout[i:i+3] == "-07" { + return layout[0:i], stdNumShortTZ, layout[i+3:] + } + + case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00, + if len(layout) >= i+7 && layout[i:i+7] == "Z070000" { + return layout[0:i], stdISO8601SecondsTZ, layout[i+7:] + } + if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" { + return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:] + } + if len(layout) >= i+5 && layout[i:i+5] == "Z0700" { + return layout[0:i], stdISO8601TZ, layout[i+5:] + } + if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" { + return layout[0:i], stdISO8601ColonTZ, layout[i+6:] + } + if len(layout) >= i+3 && layout[i:i+3] == "Z07" { + return layout[0:i], stdISO8601ShortTZ, layout[i+3:] + } + + case '.', ',': // ,000, or .000, or ,999, or .999 - repeated digits for fractional seconds. + if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { + ch := layout[i+1] + j := i + 1 + for j < len(layout) && layout[j] == ch { + j++ + } + // String of digits must end here - only fractional second is all digits. + if !isDigit(layout, j) { + code := stdFracSecond0 + if layout[i+1] == '9' { + code = stdFracSecond9 + } + std := stdFracSecond(code, j-(i+1), c) + return layout[0:i], std, layout[j:] + } + } + } + } + return layout, 0, "" +} + +var longDayNames = []string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +} + +var shortDayNames = []string{ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +} + +var shortMonthNames = []string{ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +} + +var longMonthNames = []string{ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +} + +// match reports whether s1 and s2 match ignoring case. +// It is assumed s1 and s2 are the same length. +func match(s1, s2 string) bool { + for i := 0; i < len(s1); i++ { + c1 := s1[i] + c2 := s2[i] + if c1 != c2 { + // Switch to lower-case; 'a'-'A' is known to be a single bit. + c1 |= 'a' - 'A' + c2 |= 'a' - 'A' + if c1 != c2 || c1 < 'a' || c1 > 'z' { + return false + } + } + } + return true +} + +func lookup(tab []string, val string) (int, string, error) { + for i, v := range tab { + if len(val) >= len(v) && match(val[0:len(v)], v) { + return i, val[len(v):], nil + } + } + return -1, val, errBad +} + +// appendInt appends the decimal form of x to b and returns the result. +// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. +// Duplicates functionality in strconv, but avoids dependency. +func appendInt(b []byte, x int, width int) []byte { + u := uint(x) + if x < 0 { + b = append(b, '-') + u = uint(-x) + } + + // Assemble decimal in reverse order. + var buf [20]byte + i := len(buf) + for u >= 10 { + i-- + q := u / 10 + buf[i] = byte('0' + u - q*10) + u = q + } + i-- + buf[i] = byte('0' + u) + + // Add 0-padding. + for w := len(buf) - i; w < width; w++ { + b = append(b, '0') + } + + return append(b, buf[i:]...) +} + +// Never printed, just needs to be non-nil for return by atoi. +var atoiError = errors.New("time: invalid number") + +// Duplicates functionality in strconv, but avoids dependency. +func atoi(s string) (x int, err error) { + neg := false + if s != "" && (s[0] == '-' || s[0] == '+') { + neg = s[0] == '-' + s = s[1:] + } + q, rem, err := leadingInt(s) + x = int(q) + if err != nil || rem != "" { + return 0, atoiError + } + if neg { + x = -x + } + return x, nil +} + +// The "std" value passed to formatNano contains two packed fields: the number of +// digits after the decimal and the separator character (period or comma). +// These functions pack and unpack that variable. +func stdFracSecond(code, n, c int) int { + // Use 0xfff to make the failure case even more absurd. + if c == '.' { + return code | ((n & 0xfff) << stdArgShift) + } + return code | ((n & 0xfff) << stdArgShift) | 1<<stdSeparatorShift +} + +func digitsLen(std int) int { + return (std >> stdArgShift) & 0xfff +} + +func separator(std int) byte { + if (std >> stdSeparatorShift) == 0 { + return '.' + } + return ',' +} + +// formatNano appends a fractional second, as nanoseconds, to b +// and returns the result. +func formatNano(b []byte, nanosec uint, std int) []byte { + var ( + n = digitsLen(std) + separator = separator(std) + trim = std&stdMask == stdFracSecond9 + ) + u := nanosec + var buf [9]byte + for start := len(buf); start > 0; { + start-- + buf[start] = byte(u%10 + '0') + u /= 10 + } + + if n > 9 { + n = 9 + } + if trim { + for n > 0 && buf[n-1] == '0' { + n-- + } + if n == 0 { + return b + } + } + b = append(b, separator) + return append(b, buf[:n]...) +} + +// String returns the time formatted using the format string +// "2006-01-02 15:04:05.999999999 -0700 MST" +// +// If the time has a monotonic clock reading, the returned string +// includes a final field "m=±<value>", where value is the monotonic +// clock reading formatted as a decimal number of seconds. +// +// The returned string is meant for debugging; for a stable serialized +// representation, use t.MarshalText, t.MarshalBinary, or t.Format +// with an explicit format string. +func (t Time) String() string { + s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") + + // Format monotonic clock reading as m=±ddd.nnnnnnnnn. + if t.wall&hasMonotonic != 0 { + m2 := uint64(t.ext) + sign := byte('+') + if t.ext < 0 { + sign = '-' + m2 = -m2 + } + m1, m2 := m2/1e9, m2%1e9 + m0, m1 := m1/1e9, m1%1e9 + buf := make([]byte, 0, 24) + buf = append(buf, " m="...) + buf = append(buf, sign) + wid := 0 + if m0 != 0 { + buf = appendInt(buf, int(m0), 0) + wid = 9 + } + buf = appendInt(buf, int(m1), wid) + buf = append(buf, '.') + buf = appendInt(buf, int(m2), 9) + s += string(buf) + } + return s +} + +// GoString implements fmt.GoStringer and formats t to be printed in Go source +// code. +func (t Time) GoString() string { + buf := make([]byte, 0, 70) + buf = append(buf, "time.Date("...) + buf = appendInt(buf, t.Year(), 0) + month := t.Month() + if January <= month && month <= December { + buf = append(buf, ", time."...) + buf = append(buf, t.Month().String()...) + } else { + // It's difficult to construct a time.Time with a date outside the + // standard range but we might as well try to handle the case. + buf = appendInt(buf, int(month), 0) + } + buf = append(buf, ", "...) + buf = appendInt(buf, t.Day(), 0) + buf = append(buf, ", "...) + buf = appendInt(buf, t.Hour(), 0) + buf = append(buf, ", "...) + buf = appendInt(buf, t.Minute(), 0) + buf = append(buf, ", "...) + buf = appendInt(buf, t.Second(), 0) + buf = append(buf, ", "...) + buf = appendInt(buf, t.Nanosecond(), 0) + buf = append(buf, ", "...) + switch loc := t.Location(); loc { + case UTC, nil: + buf = append(buf, "time.UTC"...) + case Local: + buf = append(buf, "time.Local"...) + default: + // there are several options for how we could display this, none of + // which are great: + // + // - use Location(loc.name), which is not technically valid syntax + // - use LoadLocation(loc.name), which will cause a syntax error when + // embedded and also would require us to escape the string without + // importing fmt or strconv + // - try to use FixedZone, which would also require escaping the name + // and would represent e.g. "America/Los_Angeles" daylight saving time + // shifts inaccurately + // - use the pointer format, which is no worse than you'd get with the + // old fmt.Sprintf("%#v", t) format. + // + // Of these, Location(loc.name) is the least disruptive. This is an edge + // case we hope not to hit too often. + buf = append(buf, `time.Location(`...) + buf = append(buf, []byte(quote(loc.name))...) + buf = append(buf, `)`...) + } + buf = append(buf, ')') + return string(buf) +} + +// Format returns a textual representation of the time value formatted according +// to the layout defined by the argument. See the documentation for the +// constant called Layout to see how to represent the layout format. +// +// The executable example for Time.Format demonstrates the working +// of the layout string in detail and is a good reference. +func (t Time) Format(layout string) string { + const bufSize = 64 + var b []byte + max := len(layout) + 10 + if max < bufSize { + var buf [bufSize]byte + b = buf[:0] + } else { + b = make([]byte, 0, max) + } + b = t.AppendFormat(b, layout) + return string(b) +} + +// AppendFormat is like Format but appends the textual +// representation to b and returns the extended buffer. +func (t Time) AppendFormat(b []byte, layout string) []byte { + var ( + name, offset, abs = t.locabs() + + year int = -1 + month Month + day int + yday int + hour int = -1 + min int + sec int + ) + // Each iteration generates one std value. + for layout != "" { + prefix, std, suffix := nextStdChunk(layout) + if prefix != "" { + b = append(b, prefix...) + } + if std == 0 { + break + } + layout = suffix + + // Compute year, month, day if needed. + if year < 0 && std&stdNeedDate != 0 { + year, month, day, yday = absDate(abs, true) + yday++ + } + + // Compute hour, minute, second if needed. + if hour < 0 && std&stdNeedClock != 0 { + hour, min, sec = absClock(abs) + } + + switch std & stdMask { + case stdYear: + y := year + if y < 0 { + y = -y + } + b = appendInt(b, y%100, 2) + case stdLongYear: + b = appendInt(b, year, 4) + case stdMonth: + b = append(b, month.String()[:3]...) + case stdLongMonth: + m := month.String() + b = append(b, m...) + case stdNumMonth: + b = appendInt(b, int(month), 0) + case stdZeroMonth: + b = appendInt(b, int(month), 2) + case stdWeekDay: + b = append(b, absWeekday(abs).String()[:3]...) + case stdLongWeekDay: + s := absWeekday(abs).String() + b = append(b, s...) + case stdDay: + b = appendInt(b, day, 0) + case stdUnderDay: + if day < 10 { + b = append(b, ' ') + } + b = appendInt(b, day, 0) + case stdZeroDay: + b = appendInt(b, day, 2) + case stdUnderYearDay: + if yday < 100 { + b = append(b, ' ') + if yday < 10 { + b = append(b, ' ') + } + } + b = appendInt(b, yday, 0) + case stdZeroYearDay: + b = appendInt(b, yday, 3) + case stdHour: + b = appendInt(b, hour, 2) + case stdHour12: + // Noon is 12PM, midnight is 12AM. + hr := hour % 12 + if hr == 0 { + hr = 12 + } + b = appendInt(b, hr, 0) + case stdZeroHour12: + // Noon is 12PM, midnight is 12AM. + hr := hour % 12 + if hr == 0 { + hr = 12 + } + b = appendInt(b, hr, 2) + case stdMinute: + b = appendInt(b, min, 0) + case stdZeroMinute: + b = appendInt(b, min, 2) + case stdSecond: + b = appendInt(b, sec, 0) + case stdZeroSecond: + b = appendInt(b, sec, 2) + case stdPM: + if hour >= 12 { + b = append(b, "PM"...) + } else { + b = append(b, "AM"...) + } + case stdpm: + if hour >= 12 { + b = append(b, "pm"...) + } else { + b = append(b, "am"...) + } + case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ: + // Ugly special case. We cheat and take the "Z" variants + // to mean "the time zone as formatted for ISO 8601". + if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) { + b = append(b, 'Z') + break + } + zone := offset / 60 // convert to minutes + absoffset := offset + if zone < 0 { + b = append(b, '-') + zone = -zone + absoffset = -absoffset + } else { + b = append(b, '+') + } + b = appendInt(b, zone/60, 2) + if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { + b = append(b, ':') + } + if std != stdNumShortTZ && std != stdISO8601ShortTZ { + b = appendInt(b, zone%60, 2) + } + + // append seconds if appropriate + if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { + if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { + b = append(b, ':') + } + b = appendInt(b, absoffset%60, 2) + } + + case stdTZ: + if name != "" { + b = append(b, name...) + break + } + // No time zone known for this time, but we must print one. + // Use the -0700 format. + zone := offset / 60 // convert to minutes + if zone < 0 { + b = append(b, '-') + zone = -zone + } else { + b = append(b, '+') + } + b = appendInt(b, zone/60, 2) + b = appendInt(b, zone%60, 2) + case stdFracSecond0, stdFracSecond9: + b = formatNano(b, uint(t.Nanosecond()), std) + } + } + return b +} + +var errBad = errors.New("bad value for field") // placeholder not passed to user + +// ParseError describes a problem parsing a time string. +type ParseError struct { + Layout string + Value string + LayoutElem string + ValueElem string + Message string +} + +// These are borrowed from unicode/utf8 and strconv and replicate behavior in +// that package, since we can't take a dependency on either. +const ( + lowerhex = "0123456789abcdef" + runeSelf = 0x80 + runeError = '\uFFFD' +) + +func quote(s string) string { + buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes + buf[0] = '"' + for i, c := range s { + if c >= runeSelf || c < ' ' { + // This means you are asking us to parse a time.Duration or + // time.Location with unprintable or non-ASCII characters in it. + // We don't expect to hit this case very often. We could try to + // reproduce strconv.Quote's behavior with full fidelity but + // given how rarely we expect to hit these edge cases, speed and + // conciseness are better. + var width int + if c == runeError { + width = 1 + if i+2 < len(s) && s[i:i+3] == string(runeError) { + width = 3 + } + } else { + width = len(string(c)) + } + for j := 0; j < width; j++ { + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[i+j]>>4]) + buf = append(buf, lowerhex[s[i+j]&0xF]) + } + } else { + if c == '"' || c == '\\' { + buf = append(buf, '\\') + } + buf = append(buf, string(c)...) + } + } + buf = append(buf, '"') + return string(buf) +} + +// Error returns the string representation of a ParseError. +func (e *ParseError) Error() string { + if e.Message == "" { + return "parsing time " + + quote(e.Value) + " as " + + quote(e.Layout) + ": cannot parse " + + quote(e.ValueElem) + " as " + + quote(e.LayoutElem) + } + return "parsing time " + + quote(e.Value) + e.Message +} + +// isDigit reports whether s[i] is in range and is a decimal digit. +func isDigit(s string, i int) bool { + if len(s) <= i { + return false + } + c := s[i] + return '0' <= c && c <= '9' +} + +// getnum parses s[0:1] or s[0:2] (fixed forces s[0:2]) +// as a decimal integer and returns the integer and the +// remainder of the string. +func getnum(s string, fixed bool) (int, string, error) { + if !isDigit(s, 0) { + return 0, s, errBad + } + if !isDigit(s, 1) { + if fixed { + return 0, s, errBad + } + return int(s[0] - '0'), s[1:], nil + } + return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil +} + +// getnum3 parses s[0:1], s[0:2], or s[0:3] (fixed forces s[0:3]) +// as a decimal integer and returns the integer and the remainder +// of the string. +func getnum3(s string, fixed bool) (int, string, error) { + var n, i int + for i = 0; i < 3 && isDigit(s, i); i++ { + n = n*10 + int(s[i]-'0') + } + if i == 0 || fixed && i != 3 { + return 0, s, errBad + } + return n, s[i:], nil +} + +func cutspace(s string) string { + for len(s) > 0 && s[0] == ' ' { + s = s[1:] + } + return s +} + +// skip removes the given prefix from value, +// treating runs of space characters as equivalent. +func skip(value, prefix string) (string, error) { + for len(prefix) > 0 { + if prefix[0] == ' ' { + if len(value) > 0 && value[0] != ' ' { + return value, errBad + } + prefix = cutspace(prefix) + value = cutspace(value) + continue + } + if len(value) == 0 || value[0] != prefix[0] { + return value, errBad + } + prefix = prefix[1:] + value = value[1:] + } + return value, nil +} + +// Parse parses a formatted string and returns the time value it represents. +// See the documentation for the constant called Layout to see how to +// represent the format. The second argument must be parseable using +// the format string (layout) provided as the first argument. +// +// The example for Time.Format demonstrates the working of the layout string +// in detail and is a good reference. +// +// When parsing (only), the input may contain a fractional second +// field immediately after the seconds field, even if the layout does not +// signify its presence. In that case either a comma or a decimal point +// followed by a maximal series of digits is parsed as a fractional second. +// Fractional seconds are truncated to nanosecond precision. +// +// Elements omitted from the layout are assumed to be zero or, when +// zero is impossible, one, so parsing "3:04pm" returns the time +// corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is +// 0, this time is before the zero Time). +// Years must be in the range 0000..9999. The day of the week is checked +// for syntax but it is otherwise ignored. +// +// For layouts specifying the two-digit year 06, a value NN >= 69 will be treated +// as 19NN and a value NN < 69 will be treated as 20NN. +// +// The remainder of this comment describes the handling of time zones. +// +// In the absence of a time zone indicator, Parse returns a time in UTC. +// +// When parsing a time with a zone offset like -0700, if the offset corresponds +// to a time zone used by the current location (Local), then Parse uses that +// location and zone in the returned time. Otherwise it records the time as +// being in a fabricated location with time fixed at the given zone offset. +// +// When parsing a time with a zone abbreviation like MST, if the zone abbreviation +// has a defined offset in the current location, then that offset is used. +// The zone abbreviation "UTC" is recognized as UTC regardless of location. +// If the zone abbreviation is unknown, Parse records the time as being +// in a fabricated location with the given zone abbreviation and a zero offset. +// This choice means that such a time can be parsed and reformatted with the +// same layout losslessly, but the exact instant used in the representation will +// differ by the actual zone offset. To avoid such problems, prefer time layouts +// that use a numeric zone offset, or use ParseInLocation. +func Parse(layout, value string) (Time, error) { + return parse(layout, value, UTC, Local) +} + +// ParseInLocation is like Parse but differs in two important ways. +// First, in the absence of time zone information, Parse interprets a time as UTC; +// ParseInLocation interprets the time as in the given location. +// Second, when given a zone offset or abbreviation, Parse tries to match it +// against the Local location; ParseInLocation uses the given location. +func ParseInLocation(layout, value string, loc *Location) (Time, error) { + return parse(layout, value, loc, loc) +} + +func parse(layout, value string, defaultLocation, local *Location) (Time, error) { + alayout, avalue := layout, value + rangeErrString := "" // set if a value is out of range + amSet := false // do we need to subtract 12 from the hour for midnight? + pmSet := false // do we need to add 12 to the hour? + + // Time being constructed. + var ( + year int + month int = -1 + day int = -1 + yday int = -1 + hour int + min int + sec int + nsec int + z *Location + zoneOffset int = -1 + zoneName string + ) + + // Each iteration processes one std value. + for { + var err error + prefix, std, suffix := nextStdChunk(layout) + stdstr := layout[len(prefix) : len(layout)-len(suffix)] + value, err = skip(value, prefix) + if err != nil { + return Time{}, &ParseError{alayout, avalue, prefix, value, ""} + } + if std == 0 { + if len(value) != 0 { + return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + quote(value)} + } + break + } + layout = suffix + var p string + switch std & stdMask { + case stdYear: + if len(value) < 2 { + err = errBad + break + } + hold := value + p, value = value[0:2], value[2:] + year, err = atoi(p) + if err != nil { + value = hold + } else if year >= 69 { // Unix time starts Dec 31 1969 in some time zones + year += 1900 + } else { + year += 2000 + } + case stdLongYear: + if len(value) < 4 || !isDigit(value, 0) { + err = errBad + break + } + p, value = value[0:4], value[4:] + year, err = atoi(p) + case stdMonth: + month, value, err = lookup(shortMonthNames, value) + month++ + case stdLongMonth: + month, value, err = lookup(longMonthNames, value) + month++ + case stdNumMonth, stdZeroMonth: + month, value, err = getnum(value, std == stdZeroMonth) + if err == nil && (month <= 0 || 12 < month) { + rangeErrString = "month" + } + case stdWeekDay: + // Ignore weekday except for error checking. + _, value, err = lookup(shortDayNames, value) + case stdLongWeekDay: + _, value, err = lookup(longDayNames, value) + case stdDay, stdUnderDay, stdZeroDay: + if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + day, value, err = getnum(value, std == stdZeroDay) + // Note that we allow any one- or two-digit day here. + // The month, day, year combination is validated after we've completed parsing. + case stdUnderYearDay, stdZeroYearDay: + for i := 0; i < 2; i++ { + if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + } + yday, value, err = getnum3(value, std == stdZeroYearDay) + // Note that we allow any one-, two-, or three-digit year-day here. + // The year-day, year combination is validated after we've completed parsing. + case stdHour: + hour, value, err = getnum(value, false) + if hour < 0 || 24 <= hour { + rangeErrString = "hour" + } + case stdHour12, stdZeroHour12: + hour, value, err = getnum(value, std == stdZeroHour12) + if hour < 0 || 12 < hour { + rangeErrString = "hour" + } + case stdMinute, stdZeroMinute: + min, value, err = getnum(value, std == stdZeroMinute) + if min < 0 || 60 <= min { + rangeErrString = "minute" + } + case stdSecond, stdZeroSecond: + sec, value, err = getnum(value, std == stdZeroSecond) + if sec < 0 || 60 <= sec { + rangeErrString = "second" + break + } + // Special case: do we have a fractional second but no + // fractional second in the format? + if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) { + _, std, _ = nextStdChunk(layout) + std &= stdMask + if std == stdFracSecond0 || std == stdFracSecond9 { + // Fractional second in the layout; proceed normally + break + } + // No fractional second in the layout but we have one in the input. + n := 2 + for ; n < len(value) && isDigit(value, n); n++ { + } + nsec, rangeErrString, err = parseNanoseconds(value, n) + value = value[n:] + } + case stdPM: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + switch p { + case "PM": + pmSet = true + case "AM": + amSet = true + default: + err = errBad + } + case stdpm: + if len(value) < 2 { + err = errBad + break + } + p, value = value[0:2], value[2:] + switch p { + case "pm": + pmSet = true + case "am": + amSet = true + default: + err = errBad + } + case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: + if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' { + value = value[1:] + z = UTC + break + } + var sign, hour, min, seconds string + if std == stdISO8601ColonTZ || std == stdNumColonTZ { + if len(value) < 6 { + err = errBad + break + } + if value[3] != ':' { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:] + } else if std == stdNumShortTZ || std == stdISO8601ShortTZ { + if len(value) < 3 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:] + } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { + if len(value) < 9 { + err = errBad + break + } + if value[3] != ':' || value[6] != ':' { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:] + } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz { + if len(value) < 7 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:] + } else { + if len(value) < 5 { + err = errBad + break + } + sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:] + } + var hr, mm, ss int + hr, err = atoi(hour) + if err == nil { + mm, err = atoi(min) + } + if err == nil { + ss, err = atoi(seconds) + } + zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds + switch sign[0] { + case '+': + case '-': + zoneOffset = -zoneOffset + default: + err = errBad + } + case stdTZ: + // Does it look like a time zone? + if len(value) >= 3 && value[0:3] == "UTC" { + z = UTC + value = value[3:] + break + } + n, ok := parseTimeZone(value) + if !ok { + err = errBad + break + } + zoneName, value = value[:n], value[n:] + + case stdFracSecond0: + // stdFracSecond0 requires the exact number of digits as specified in + // the layout. + ndigit := 1 + digitsLen(std) + if len(value) < ndigit { + err = errBad + break + } + nsec, rangeErrString, err = parseNanoseconds(value, ndigit) + value = value[ndigit:] + + case stdFracSecond9: + if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] { + // Fractional second omitted. + break + } + // Take any number of digits, even more than asked for, + // because it is what the stdSecond case would do. + i := 0 + for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' { + i++ + } + nsec, rangeErrString, err = parseNanoseconds(value, 1+i) + value = value[1+i:] + } + if rangeErrString != "" { + return Time{}, &ParseError{alayout, avalue, stdstr, value, ": " + rangeErrString + " out of range"} + } + if err != nil { + return Time{}, &ParseError{alayout, avalue, stdstr, value, ""} + } + } + if pmSet && hour < 12 { + hour += 12 + } else if amSet && hour == 12 { + hour = 0 + } + + // Convert yday to day, month. + if yday >= 0 { + var d int + var m int + if isLeap(year) { + if yday == 31+29 { + m = int(February) + d = 29 + } else if yday > 31+29 { + yday-- + } + } + if yday < 1 || yday > 365 { + return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year out of range"} + } + if m == 0 { + m = (yday-1)/31 + 1 + if int(daysBefore[m]) < yday { + m++ + } + d = yday - int(daysBefore[m-1]) + } + // If month, day already seen, yday's m, d must match. + // Otherwise, set them from m, d. + if month >= 0 && month != m { + return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match month"} + } + month = m + if day >= 0 && day != d { + return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match day"} + } + day = d + } else { + if month < 0 { + month = int(January) + } + if day < 0 { + day = 1 + } + } + + // Validate the day of the month. + if day < 1 || day > daysIn(Month(month), year) { + return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"} + } + + if z != nil { + return Date(year, Month(month), day, hour, min, sec, nsec, z), nil + } + + if zoneOffset != -1 { + t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) + t.addSec(-int64(zoneOffset)) + + // Look for local zone with the given offset. + // If that zone was in effect at the given time, use it. + name, offset, _, _, _ := local.lookup(t.unixSec()) + if offset == zoneOffset && (zoneName == "" || name == zoneName) { + t.setLoc(local) + return t, nil + } + + // Otherwise create fake zone to record offset. + t.setLoc(FixedZone(zoneName, zoneOffset)) + return t, nil + } + + if zoneName != "" { + t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) + // Look for local zone with the given offset. + // If that zone was in effect at the given time, use it. + offset, ok := local.lookupName(zoneName, t.unixSec()) + if ok { + t.addSec(-int64(offset)) + t.setLoc(local) + return t, nil + } + + // Otherwise, create fake zone with unknown offset. + if len(zoneName) > 3 && zoneName[:3] == "GMT" { + offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. + offset *= 3600 + } + t.setLoc(FixedZone(zoneName, offset)) + return t, nil + } + + // Otherwise, fall back to default. + return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil +} + +// parseTimeZone parses a time zone string and returns its length. Time zones +// are human-generated and unpredictable. We can't do precise error checking. +// On the other hand, for a correct parse there must be a time zone at the +// beginning of the string, so it's almost always true that there's one +// there. We look at the beginning of the string for a run of upper-case letters. +// If there are more than 5, it's an error. +// If there are 4 or 5 and the last is a T, it's a time zone. +// If there are 3, it's a time zone. +// Otherwise, other than special cases, it's not a time zone. +// GMT is special because it can have an hour offset. +func parseTimeZone(value string) (length int, ok bool) { + if len(value) < 3 { + return 0, false + } + // Special case 1: ChST and MeST are the only zones with a lower-case letter. + if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { + return 4, true + } + // Special case 2: GMT may have an hour offset; treat it specially. + if value[:3] == "GMT" { + length = parseGMT(value) + return length, true + } + // Special Case 3: Some time zones are not named, but have +/-00 format + if value[0] == '+' || value[0] == '-' { + length = parseSignedOffset(value) + ok := length > 0 // parseSignedOffset returns 0 in case of bad input + return length, ok + } + // How many upper-case letters are there? Need at least three, at most five. + var nUpper int + for nUpper = 0; nUpper < 6; nUpper++ { + if nUpper >= len(value) { + break + } + if c := value[nUpper]; c < 'A' || 'Z' < c { + break + } + } + switch nUpper { + case 0, 1, 2, 6: + return 0, false + case 5: // Must end in T to match. + if value[4] == 'T' { + return 5, true + } + case 4: + // Must end in T, except one special case. + if value[3] == 'T' || value[:4] == "WITA" { + return 4, true + } + case 3: + return 3, true + } + return 0, false +} + +// parseGMT parses a GMT time zone. The input string is known to start "GMT". +// The function checks whether that is followed by a sign and a number in the +// range -23 through +23 excluding zero. +func parseGMT(value string) int { + value = value[3:] + if len(value) == 0 { + return 3 + } + + return 3 + parseSignedOffset(value) +} + +// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04"). +// The function checks for a signed number in the range -23 through +23 excluding zero. +// Returns length of the found offset string or 0 otherwise +func parseSignedOffset(value string) int { + sign := value[0] + if sign != '-' && sign != '+' { + return 0 + } + x, rem, err := leadingInt(value[1:]) + + // fail if nothing consumed by leadingInt + if err != nil || value[1:] == rem { + return 0 + } + if x > 23 { + return 0 + } + return len(value) - len(rem) +} + +func commaOrPeriod(b byte) bool { + return b == '.' || b == ',' +} + +func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) { + if !commaOrPeriod(value[0]) { + err = errBad + return + } + if nbytes > 10 { + value = value[:10] + nbytes = 10 + } + if ns, err = atoi(value[1:nbytes]); err != nil { + return + } + if ns < 0 { + rangeErrString = "fractional second" + return + } + // We need nanoseconds, which means scaling by the number + // of missing digits in the format, maximum length 10. + scaleDigits := 10 - nbytes + for i := 0; i < scaleDigits; i++ { + ns *= 10 + } + return +} + +var errLeadingInt = errors.New("time: bad [0-9]*") // never printed + +// leadingInt consumes the leading [0-9]* from s. +func leadingInt(s string) (x uint64, rem string, err error) { + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if x > 1<<63/10 { + // overflow + return 0, "", errLeadingInt + } + x = x*10 + uint64(c) - '0' + if x > 1<<63 { + // overflow + return 0, "", errLeadingInt + } + } + return x, s[i:], nil +} + +// leadingFraction consumes the leading [0-9]* from s. +// It is used only for fractions, so does not return an error on overflow, +// it just stops accumulating precision. +func leadingFraction(s string) (x uint64, scale float64, rem string) { + i := 0 + scale = 1 + overflow := false + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + if overflow { + continue + } + if x > (1<<63-1)/10 { + // It's possible for overflow to give a positive number, so take care. + overflow = true + continue + } + y := x*10 + uint64(c) - '0' + if y > 1<<63 { + overflow = true + continue + } + x = y + scale *= 10 + } + return x, scale, s[i:] +} + +var unitMap = map[string]uint64{ + "ns": uint64(Nanosecond), + "us": uint64(Microsecond), + "µs": uint64(Microsecond), // U+00B5 = micro symbol + "μs": uint64(Microsecond), // U+03BC = Greek letter mu + "ms": uint64(Millisecond), + "s": uint64(Second), + "m": uint64(Minute), + "h": uint64(Hour), +} + +// ParseDuration parses a duration string. +// A duration string is a possibly signed sequence of +// decimal numbers, each with optional fraction and a unit suffix, +// such as "300ms", "-1.5h" or "2h45m". +// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". +func ParseDuration(s string) (Duration, error) { + // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ + orig := s + var d uint64 + neg := false + + // Consume [-+]? + if s != "" { + c := s[0] + if c == '-' || c == '+' { + neg = c == '-' + s = s[1:] + } + } + // Special case: if all that is left is "0", this is zero. + if s == "0" { + return 0, nil + } + if s == "" { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + for s != "" { + var ( + v, f uint64 // integers before, after decimal point + scale float64 = 1 // value = v + f/scale + ) + + var err error + + // The next character must be [0-9.] + if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + // Consume [0-9]* + pl := len(s) + v, s, err = leadingInt(s) + if err != nil { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + pre := pl != len(s) // whether we consumed anything before a period + + // Consume (\.[0-9]*)? + post := false + if s != "" && s[0] == '.' { + s = s[1:] + pl := len(s) + f, scale, s = leadingFraction(s) + post = pl != len(s) + } + if !pre && !post { + // no digits (e.g. ".s" or "-.s") + return 0, errors.New("time: invalid duration " + quote(orig)) + } + + // Consume unit. + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c == '.' || '0' <= c && c <= '9' { + break + } + } + if i == 0 { + return 0, errors.New("time: missing unit in duration " + quote(orig)) + } + u := s[:i] + s = s[i:] + unit, ok := unitMap[u] + if !ok { + return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig)) + } + if v > 1<<63/unit { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + v *= unit + if f > 0 { + // float64 is needed to be nanosecond accurate for fractions of hours. + // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) + v += uint64(float64(f) * (float64(unit) / scale)) + if v > 1<<63 { + // overflow + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + d += v + if d > 1<<63 { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + } + if neg { + return -Duration(d), nil + } + if d > 1<<63-1 { + return 0, errors.New("time: invalid duration " + quote(orig)) + } + return Duration(d), nil +} diff --git a/contrib/go/_std_1.18/src/time/sleep.go b/contrib/go/_std_1.18/src/time/sleep.go new file mode 100644 index 0000000000..1ffaabec67 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/sleep.go @@ -0,0 +1,177 @@ +// Copyright 2009 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 time + +// Sleep pauses the current goroutine for at least the duration d. +// A negative or zero duration causes Sleep to return immediately. +func Sleep(d Duration) + +// Interface to timers implemented in package runtime. +// Must be in sync with ../runtime/time.go:/^type timer +type runtimeTimer struct { + pp uintptr + when int64 + period int64 + f func(any, uintptr) // NOTE: must not be closure + arg any + seq uintptr + nextwhen int64 + status uint32 +} + +// when is a helper function for setting the 'when' field of a runtimeTimer. +// It returns what the time will be, in nanoseconds, Duration d in the future. +// If d is negative, it is ignored. If the returned value would be less than +// zero because of an overflow, MaxInt64 is returned. +func when(d Duration) int64 { + if d <= 0 { + return runtimeNano() + } + t := runtimeNano() + int64(d) + if t < 0 { + // N.B. runtimeNano() and d are always positive, so addition + // (including overflow) will never result in t == 0. + t = 1<<63 - 1 // math.MaxInt64 + } + return t +} + +func startTimer(*runtimeTimer) +func stopTimer(*runtimeTimer) bool +func resetTimer(*runtimeTimer, int64) bool +func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) + +// The Timer type represents a single event. +// When the Timer expires, the current time will be sent on C, +// unless the Timer was created by AfterFunc. +// A Timer must be created with NewTimer or AfterFunc. +type Timer struct { + C <-chan Time + r runtimeTimer +} + +// Stop prevents the Timer from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or been stopped. +// Stop does not close the channel, to prevent a read from the channel succeeding +// incorrectly. +// +// To ensure the channel is empty after a call to Stop, check the +// return value and drain the channel. +// For example, assuming the program has not received from t.C already: +// +// if !t.Stop() { +// <-t.C +// } +// +// This cannot be done concurrent to other receives from the Timer's +// channel or other calls to the Timer's Stop method. +// +// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer +// has already expired and the function f has been started in its own goroutine; +// Stop does not wait for f to complete before returning. +// If the caller needs to know whether f is completed, it must coordinate +// with f explicitly. +func (t *Timer) Stop() bool { + if t.r.f == nil { + panic("time: Stop called on uninitialized Timer") + } + return stopTimer(&t.r) +} + +// NewTimer creates a new Timer that will send +// the current time on its channel after at least duration d. +func NewTimer(d Duration) *Timer { + c := make(chan Time, 1) + t := &Timer{ + C: c, + r: runtimeTimer{ + when: when(d), + f: sendTime, + arg: c, + }, + } + startTimer(&t.r) + return t +} + +// Reset changes the timer to expire after duration d. +// It returns true if the timer had been active, false if the timer had +// expired or been stopped. +// +// For a Timer created with NewTimer, Reset should be invoked only on +// stopped or expired timers with drained channels. +// +// If a program has already received a value from t.C, the timer is known +// to have expired and the channel drained, so t.Reset can be used directly. +// If a program has not yet received a value from t.C, however, +// the timer must be stopped and—if Stop reports that the timer expired +// before being stopped—the channel explicitly drained: +// +// if !t.Stop() { +// <-t.C +// } +// t.Reset(d) +// +// This should not be done concurrent to other receives from the Timer's +// channel. +// +// Note that it is not possible to use Reset's return value correctly, as there +// is a race condition between draining the channel and the new timer expiring. +// Reset should always be invoked on stopped or expired channels, as described above. +// The return value exists to preserve compatibility with existing programs. +// +// For a Timer created with AfterFunc(d, f), Reset either reschedules +// when f will run, in which case Reset returns true, or schedules f +// to run again, in which case it returns false. +// When Reset returns false, Reset neither waits for the prior f to +// complete before returning nor does it guarantee that the subsequent +// goroutine running f does not run concurrently with the prior +// one. If the caller needs to know whether the prior execution of +// f is completed, it must coordinate with f explicitly. +func (t *Timer) Reset(d Duration) bool { + if t.r.f == nil { + panic("time: Reset called on uninitialized Timer") + } + w := when(d) + return resetTimer(&t.r, w) +} + +// sendTime does a non-blocking send of the current time on c. +func sendTime(c any, seq uintptr) { + select { + case c.(chan Time) <- Now(): + default: + } +} + +// After waits for the duration to elapse and then sends the current time +// on the returned channel. +// It is equivalent to NewTimer(d).C. +// The underlying Timer is not recovered by the garbage collector +// until the timer fires. If efficiency is a concern, use NewTimer +// instead and call Timer.Stop if the timer is no longer needed. +func After(d Duration) <-chan Time { + return NewTimer(d).C +} + +// AfterFunc waits for the duration to elapse and then calls f +// in its own goroutine. It returns a Timer that can +// be used to cancel the call using its Stop method. +func AfterFunc(d Duration, f func()) *Timer { + t := &Timer{ + r: runtimeTimer{ + when: when(d), + f: goFunc, + arg: f, + }, + } + startTimer(&t.r) + return t +} + +func goFunc(arg any, seq uintptr) { + go arg.(func())() +} diff --git a/contrib/go/_std_1.18/src/time/sys_unix.go b/contrib/go/_std_1.18/src/time/sys_unix.go new file mode 100644 index 0000000000..a949a6af22 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/sys_unix.go @@ -0,0 +1,54 @@ +// Copyright 2011 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. + +//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris + +package time + +import ( + "errors" + "syscall" +) + +// for testing: whatever interrupts a sleep +func interrupt() { + syscall.Kill(syscall.Getpid(), syscall.SIGCHLD) +} + +func open(name string) (uintptr, error) { + fd, err := syscall.Open(name, syscall.O_RDONLY, 0) + if err != nil { + return 0, err + } + return uintptr(fd), nil +} + +func read(fd uintptr, buf []byte) (int, error) { + return syscall.Read(int(fd), buf) +} + +func closefd(fd uintptr) { + syscall.Close(int(fd)) +} + +func preadn(fd uintptr, buf []byte, off int) error { + whence := seekStart + if off < 0 { + whence = seekEnd + } + if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil { + return err + } + for len(buf) > 0 { + m, err := syscall.Read(int(fd), buf) + if m <= 0 { + if err == nil { + return errors.New("short read") + } + return err + } + buf = buf[m:] + } + return nil +} diff --git a/contrib/go/_std_1.18/src/time/tick.go b/contrib/go/_std_1.18/src/time/tick.go new file mode 100644 index 0000000000..babf865aeb --- /dev/null +++ b/contrib/go/_std_1.18/src/time/tick.go @@ -0,0 +1,73 @@ +// Copyright 2009 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 time + +import "errors" + +// A Ticker holds a channel that delivers ``ticks'' of a clock +// at intervals. +type Ticker struct { + C <-chan Time // The channel on which the ticks are delivered. + r runtimeTimer +} + +// NewTicker returns a new Ticker containing a channel that will send +// the current time on the channel after each tick. The period of the +// ticks is specified by the duration argument. The ticker will adjust +// the time interval or drop ticks to make up for slow receivers. +// The duration d must be greater than zero; if not, NewTicker will +// panic. Stop the ticker to release associated resources. +func NewTicker(d Duration) *Ticker { + if d <= 0 { + panic(errors.New("non-positive interval for NewTicker")) + } + // Give the channel a 1-element time buffer. + // If the client falls behind while reading, we drop ticks + // on the floor until the client catches up. + c := make(chan Time, 1) + t := &Ticker{ + C: c, + r: runtimeTimer{ + when: when(d), + period: int64(d), + f: sendTime, + arg: c, + }, + } + startTimer(&t.r) + return t +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +// Stop does not close the channel, to prevent a concurrent goroutine +// reading from the channel from seeing an erroneous "tick". +func (t *Ticker) Stop() { + stopTimer(&t.r) +} + +// Reset stops a ticker and resets its period to the specified duration. +// The next tick will arrive after the new period elapses. The duration d +// must be greater than zero; if not, Reset will panic. +func (t *Ticker) Reset(d Duration) { + if d <= 0 { + panic("non-positive interval for Ticker.Reset") + } + if t.r.f == nil { + panic("time: Reset called on uninitialized Ticker") + } + modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq) +} + +// Tick is a convenience wrapper for NewTicker providing access to the ticking +// channel only. While Tick is useful for clients that have no need to shut down +// the Ticker, be aware that without a way to shut it down the underlying +// Ticker cannot be recovered by the garbage collector; it "leaks". +// Unlike NewTicker, Tick will return nil if d <= 0. +func Tick(d Duration) <-chan Time { + if d <= 0 { + return nil + } + return NewTicker(d).C +} diff --git a/contrib/go/_std_1.18/src/time/time.go b/contrib/go/_std_1.18/src/time/time.go new file mode 100644 index 0000000000..8046ff508b --- /dev/null +++ b/contrib/go/_std_1.18/src/time/time.go @@ -0,0 +1,1581 @@ +// Copyright 2009 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 time provides functionality for measuring and displaying time. +// +// The calendrical calculations always assume a Gregorian calendar, with +// no leap seconds. +// +// Monotonic Clocks +// +// Operating systems provide both a “wall clock,” which is subject to +// changes for clock synchronization, and a “monotonic clock,” which is +// not. The general rule is that the wall clock is for telling time and +// the monotonic clock is for measuring time. Rather than split the API, +// in this package the Time returned by time.Now contains both a wall +// clock reading and a monotonic clock reading; later time-telling +// operations use the wall clock reading, but later time-measuring +// operations, specifically comparisons and subtractions, use the +// monotonic clock reading. +// +// For example, this code always computes a positive elapsed time of +// approximately 20 milliseconds, even if the wall clock is changed during +// the operation being timed: +// +// start := time.Now() +// ... operation that takes 20 milliseconds ... +// t := time.Now() +// elapsed := t.Sub(start) +// +// Other idioms, such as time.Since(start), time.Until(deadline), and +// time.Now().Before(deadline), are similarly robust against wall clock +// resets. +// +// The rest of this section gives the precise details of how operations +// use monotonic clocks, but understanding those details is not required +// to use this package. +// +// The Time returned by time.Now contains a monotonic clock reading. +// If Time t has a monotonic clock reading, t.Add adds the same duration to +// both the wall clock and monotonic clock readings to compute the result. +// Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time +// computations, they always strip any monotonic clock reading from their results. +// Because t.In, t.Local, and t.UTC are used for their effect on the interpretation +// of the wall time, they also strip any monotonic clock reading from their results. +// The canonical way to strip a monotonic clock reading is to use t = t.Round(0). +// +// If Times t and u both contain monotonic clock readings, the operations +// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out +// using the monotonic clock readings alone, ignoring the wall clock +// readings. If either t or u contains no monotonic clock reading, these +// operations fall back to using the wall clock readings. +// +// On some systems the monotonic clock will stop if the computer goes to sleep. +// On such a system, t.Sub(u) may not accurately reflect the actual +// time that passed between t and u. +// +// Because the monotonic clock reading has no meaning outside +// the current process, the serialized forms generated by t.GobEncode, +// t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic +// clock reading, and t.Format provides no format for it. Similarly, the +// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix, +// as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. +// t.UnmarshalJSON, and t.UnmarshalText always create times with +// no monotonic clock reading. +// +// Note that the Go == operator compares not just the time instant but +// also the Location and the monotonic clock reading. See the +// documentation for the Time type for a discussion of equality +// testing for Time values. +// +// For debugging, the result of t.String does include the monotonic +// clock reading if present. If t != u because of different monotonic clock readings, +// that difference will be visible when printing t.String() and u.String(). +// +package time + +import ( + "errors" + _ "unsafe" // for go:linkname +) + +// A Time represents an instant in time with nanosecond precision. +// +// Programs using times should typically store and pass them as values, +// not pointers. That is, time variables and struct fields should be of +// type time.Time, not *time.Time. +// +// A Time value can be used by multiple goroutines simultaneously except +// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and +// UnmarshalText are not concurrency-safe. +// +// Time instants can be compared using the Before, After, and Equal methods. +// The Sub method subtracts two instants, producing a Duration. +// The Add method adds a Time and a Duration, producing a Time. +// +// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. +// As this time is unlikely to come up in practice, the IsZero method gives +// a simple way of detecting a time that has not been initialized explicitly. +// +// Each Time has associated with it a Location, consulted when computing the +// presentation form of the time, such as in the Format, Hour, and Year methods. +// The methods Local, UTC, and In return a Time with a specific location. +// Changing the location in this way changes only the presentation; it does not +// change the instant in time being denoted and therefore does not affect the +// computations described in earlier paragraphs. +// +// Representations of a Time value saved by the GobEncode, MarshalBinary, +// MarshalJSON, and MarshalText methods store the Time.Location's offset, but not +// the location name. They therefore lose information about Daylight Saving Time. +// +// In addition to the required “wall clock” reading, a Time may contain an optional +// reading of the current process's monotonic clock, to provide additional precision +// for comparison or subtraction. +// See the “Monotonic Clocks” section in the package documentation for details. +// +// Note that the Go == operator compares not just the time instant but also the +// Location and the monotonic clock reading. Therefore, Time values should not +// be used as map or database keys without first guaranteeing that the +// identical Location has been set for all values, which can be achieved +// through use of the UTC or Local method, and that the monotonic clock reading +// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) +// to t == u, since t.Equal uses the most accurate comparison available and +// correctly handles the case when only one of its arguments has a monotonic +// clock reading. +// +type Time struct { + // wall and ext encode the wall time seconds, wall time nanoseconds, + // and optional monotonic clock reading in nanoseconds. + // + // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), + // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. + // The nanoseconds field is in the range [0, 999999999]. + // If the hasMonotonic bit is 0, then the 33-bit field must be zero + // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. + // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit + // unsigned wall seconds since Jan 1 year 1885, and ext holds a + // signed 64-bit monotonic clock reading, nanoseconds since process start. + wall uint64 + ext int64 + + // loc specifies the Location that should be used to + // determine the minute, hour, month, day, and year + // that correspond to this Time. + // The nil location means UTC. + // All UTC times are represented with loc==nil, never loc==&utcLoc. + loc *Location +} + +const ( + hasMonotonic = 1 << 63 + maxWall = wallToInternal + (1<<33 - 1) // year 2157 + minWall = wallToInternal // year 1885 + nsecMask = 1<<30 - 1 + nsecShift = 30 +) + +// These helpers for manipulating the wall and monotonic clock readings +// take pointer receivers, even when they don't modify the time, +// to make them cheaper to call. + +// nsec returns the time's nanoseconds. +func (t *Time) nsec() int32 { + return int32(t.wall & nsecMask) +} + +// sec returns the time's seconds since Jan 1 year 1. +func (t *Time) sec() int64 { + if t.wall&hasMonotonic != 0 { + return wallToInternal + int64(t.wall<<1>>(nsecShift+1)) + } + return t.ext +} + +// unixSec returns the time's seconds since Jan 1 1970 (Unix time). +func (t *Time) unixSec() int64 { return t.sec() + internalToUnix } + +// addSec adds d seconds to the time. +func (t *Time) addSec(d int64) { + if t.wall&hasMonotonic != 0 { + sec := int64(t.wall << 1 >> (nsecShift + 1)) + dsec := sec + d + if 0 <= dsec && dsec <= 1<<33-1 { + t.wall = t.wall&nsecMask | uint64(dsec)<<nsecShift | hasMonotonic + return + } + // Wall second now out of range for packed field. + // Move to ext. + t.stripMono() + } + + // Check if the sum of t.ext and d overflows and handle it properly. + sum := t.ext + d + if (sum > t.ext) == (d > 0) { + t.ext = sum + } else if d > 0 { + t.ext = 1<<63 - 1 + } else { + t.ext = -(1<<63 - 1) + } +} + +// setLoc sets the location associated with the time. +func (t *Time) setLoc(loc *Location) { + if loc == &utcLoc { + loc = nil + } + t.stripMono() + t.loc = loc +} + +// stripMono strips the monotonic clock reading in t. +func (t *Time) stripMono() { + if t.wall&hasMonotonic != 0 { + t.ext = t.sec() + t.wall &= nsecMask + } +} + +// setMono sets the monotonic clock reading in t. +// If t cannot hold a monotonic clock reading, +// because its wall time is too large, +// setMono is a no-op. +func (t *Time) setMono(m int64) { + if t.wall&hasMonotonic == 0 { + sec := t.ext + if sec < minWall || maxWall < sec { + return + } + t.wall |= hasMonotonic | uint64(sec-minWall)<<nsecShift + } + t.ext = m +} + +// mono returns t's monotonic clock reading. +// It returns 0 for a missing reading. +// This function is used only for testing, +// so it's OK that technically 0 is a valid +// monotonic clock reading as well. +func (t *Time) mono() int64 { + if t.wall&hasMonotonic == 0 { + return 0 + } + return t.ext +} + +// After reports whether the time instant t is after u. +func (t Time) After(u Time) bool { + if t.wall&u.wall&hasMonotonic != 0 { + return t.ext > u.ext + } + ts := t.sec() + us := u.sec() + return ts > us || ts == us && t.nsec() > u.nsec() +} + +// Before reports whether the time instant t is before u. +func (t Time) Before(u Time) bool { + if t.wall&u.wall&hasMonotonic != 0 { + return t.ext < u.ext + } + ts := t.sec() + us := u.sec() + return ts < us || ts == us && t.nsec() < u.nsec() +} + +// Equal reports whether t and u represent the same time instant. +// Two times can be equal even if they are in different locations. +// For example, 6:00 +0200 and 4:00 UTC are Equal. +// See the documentation on the Time type for the pitfalls of using == with +// Time values; most code should use Equal instead. +func (t Time) Equal(u Time) bool { + if t.wall&u.wall&hasMonotonic != 0 { + return t.ext == u.ext + } + return t.sec() == u.sec() && t.nsec() == u.nsec() +} + +// A Month specifies a month of the year (January = 1, ...). +type Month int + +const ( + January Month = 1 + iota + February + March + April + May + June + July + August + September + October + November + December +) + +// String returns the English name of the month ("January", "February", ...). +func (m Month) String() string { + if January <= m && m <= December { + return longMonthNames[m-1] + } + buf := make([]byte, 20) + n := fmtInt(buf, uint64(m)) + return "%!Month(" + string(buf[n:]) + ")" +} + +// A Weekday specifies a day of the week (Sunday = 0, ...). +type Weekday int + +const ( + Sunday Weekday = iota + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday +) + +// String returns the English name of the day ("Sunday", "Monday", ...). +func (d Weekday) String() string { + if Sunday <= d && d <= Saturday { + return longDayNames[d] + } + buf := make([]byte, 20) + n := fmtInt(buf, uint64(d)) + return "%!Weekday(" + string(buf[n:]) + ")" +} + +// Computations on time. +// +// The zero value for a Time is defined to be +// January 1, year 1, 00:00:00.000000000 UTC +// which (1) looks like a zero, or as close as you can get in a date +// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to +// be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a +// non-negative year even in time zones west of UTC, unlike 1-1-0 +// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York. +// +// The zero Time value does not force a specific epoch for the time +// representation. For example, to use the Unix epoch internally, we +// could define that to distinguish a zero value from Jan 1 1970, that +// time would be represented by sec=-1, nsec=1e9. However, it does +// suggest a representation, namely using 1-1-1 00:00:00 UTC as the +// epoch, and that's what we do. +// +// The Add and Sub computations are oblivious to the choice of epoch. +// +// The presentation computations - year, month, minute, and so on - all +// rely heavily on division and modulus by positive constants. For +// calendrical calculations we want these divisions to round down, even +// for negative values, so that the remainder is always positive, but +// Go's division (like most hardware division instructions) rounds to +// zero. We can still do those computations and then adjust the result +// for a negative numerator, but it's annoying to write the adjustment +// over and over. Instead, we can change to a different epoch so long +// ago that all the times we care about will be positive, and then round +// to zero and round down coincide. These presentation routines already +// have to add the zone offset, so adding the translation to the +// alternate epoch is cheap. For example, having a non-negative time t +// means that we can write +// +// sec = t % 60 +// +// instead of +// +// sec = t % 60 +// if sec < 0 { +// sec += 60 +// } +// +// everywhere. +// +// The calendar runs on an exact 400 year cycle: a 400-year calendar +// printed for 1970-2369 will apply as well to 2370-2769. Even the days +// of the week match up. It simplifies the computations to choose the +// cycle boundaries so that the exceptional years are always delayed as +// long as possible. That means choosing a year equal to 1 mod 400, so +// that the first leap year is the 4th year, the first missed leap year +// is the 100th year, and the missed missed leap year is the 400th year. +// So we'd prefer instead to print a calendar for 2001-2400 and reuse it +// for 2401-2800. +// +// Finally, it's convenient if the delta between the Unix epoch and +// long-ago epoch is representable by an int64 constant. +// +// These three considerations—choose an epoch as early as possible, that +// uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds +// earlier than 1970—bring us to the year -292277022399. We refer to +// this year as the absolute zero year, and to times measured as a uint64 +// seconds since this year as absolute times. +// +// Times measured as an int64 seconds since the year 1—the representation +// used for Time's sec field—are called internal times. +// +// Times measured as an int64 seconds since the year 1970 are called Unix +// times. +// +// It is tempting to just use the year 1 as the absolute epoch, defining +// that the routines are only valid for years >= 1. However, the +// routines would then be invalid when displaying the epoch in time zones +// west of UTC, since it is year 0. It doesn't seem tenable to say that +// printing the zero time correctly isn't supported in half the time +// zones. By comparison, it's reasonable to mishandle some times in +// the year -292277022399. +// +// All this is opaque to clients of the API and can be changed if a +// better implementation presents itself. + +const ( + // The unsigned zero year for internal calculations. + // Must be 1 mod 400, and times before it will not compute correctly, + // but otherwise can be changed at will. + absoluteZeroYear = -292277022399 + + // The year of the zero Time. + // Assumed by the unixToInternal computation below. + internalYear = 1 + + // Offsets to convert between internal and absolute or Unix times. + absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay + internalToAbsolute = -absoluteToInternal + + unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay + internalToUnix int64 = -unixToInternal + + wallToInternal int64 = (1884*365 + 1884/4 - 1884/100 + 1884/400) * secondsPerDay +) + +// IsZero reports whether t represents the zero time instant, +// January 1, year 1, 00:00:00 UTC. +func (t Time) IsZero() bool { + return t.sec() == 0 && t.nsec() == 0 +} + +// abs returns the time t as an absolute time, adjusted by the zone offset. +// It is called when computing a presentation property like Month or Hour. +func (t Time) abs() uint64 { + l := t.loc + // Avoid function calls when possible. + if l == nil || l == &localLoc { + l = l.get() + } + sec := t.unixSec() + if l != &utcLoc { + if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { + sec += int64(l.cacheZone.offset) + } else { + _, offset, _, _, _ := l.lookup(sec) + sec += int64(offset) + } + } + return uint64(sec + (unixToInternal + internalToAbsolute)) +} + +// locabs is a combination of the Zone and abs methods, +// extracting both return values from a single zone lookup. +func (t Time) locabs() (name string, offset int, abs uint64) { + l := t.loc + if l == nil || l == &localLoc { + l = l.get() + } + // Avoid function call if we hit the local time cache. + sec := t.unixSec() + if l != &utcLoc { + if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd { + name = l.cacheZone.name + offset = l.cacheZone.offset + } else { + name, offset, _, _, _ = l.lookup(sec) + } + sec += int64(offset) + } else { + name = "UTC" + } + abs = uint64(sec + (unixToInternal + internalToAbsolute)) + return +} + +// Date returns the year, month, and day in which t occurs. +func (t Time) Date() (year int, month Month, day int) { + year, month, day, _ = t.date(true) + return +} + +// Year returns the year in which t occurs. +func (t Time) Year() int { + year, _, _, _ := t.date(false) + return year +} + +// Month returns the month of the year specified by t. +func (t Time) Month() Month { + _, month, _, _ := t.date(true) + return month +} + +// Day returns the day of the month specified by t. +func (t Time) Day() int { + _, _, day, _ := t.date(true) + return day +} + +// Weekday returns the day of the week specified by t. +func (t Time) Weekday() Weekday { + return absWeekday(t.abs()) +} + +// absWeekday is like Weekday but operates on an absolute time. +func absWeekday(abs uint64) Weekday { + // January 1 of the absolute year, like January 1 of 2001, was a Monday. + sec := (abs + uint64(Monday)*secondsPerDay) % secondsPerWeek + return Weekday(int(sec) / secondsPerDay) +} + +// ISOWeek returns the ISO 8601 year and week number in which t 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 (t Time) ISOWeek() (year, week int) { + // According to the rule that the first calendar week of a calendar year is + // the week including the first Thursday of that year, and that the last one is + // the week immediately preceding the first calendar week of the next calendar year. + // See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details. + + // weeks start with Monday + // Monday Tuesday Wednesday Thursday Friday Saturday Sunday + // 1 2 3 4 5 6 7 + // +3 +2 +1 0 -1 -2 -3 + // the offset to Thursday + abs := t.abs() + d := Thursday - absWeekday(abs) + // handle Sunday + if d == 4 { + d = -3 + } + // find the Thursday of the calendar week + abs += uint64(d) * secondsPerDay + year, _, _, yday := absDate(abs, false) + return year, yday/7 + 1 +} + +// Clock returns the hour, minute, and second within the day specified by t. +func (t Time) Clock() (hour, min, sec int) { + return absClock(t.abs()) +} + +// absClock is like clock but operates on an absolute time. +func absClock(abs uint64) (hour, min, sec int) { + sec = int(abs % secondsPerDay) + hour = sec / secondsPerHour + sec -= hour * secondsPerHour + min = sec / secondsPerMinute + sec -= min * secondsPerMinute + return +} + +// Hour returns the hour within the day specified by t, in the range [0, 23]. +func (t Time) Hour() int { + return int(t.abs()%secondsPerDay) / secondsPerHour +} + +// Minute returns the minute offset within the hour specified by t, in the range [0, 59]. +func (t Time) Minute() int { + return int(t.abs()%secondsPerHour) / secondsPerMinute +} + +// Second returns the second offset within the minute specified by t, in the range [0, 59]. +func (t Time) Second() int { + return int(t.abs() % secondsPerMinute) +} + +// Nanosecond returns the nanosecond offset within the second specified by t, +// in the range [0, 999999999]. +func (t Time) Nanosecond() int { + return int(t.nsec()) +} + +// YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, +// and [1,366] in leap years. +func (t Time) YearDay() int { + _, _, _, yday := t.date(false) + return yday + 1 +} + +// A Duration represents the elapsed time between two instants +// as an int64 nanosecond count. The representation limits the +// largest representable duration to approximately 290 years. +type Duration int64 + +const ( + minDuration Duration = -1 << 63 + maxDuration Duration = 1<<63 - 1 +) + +// Common durations. There is no definition for units of Day or larger +// to avoid confusion across daylight savings time zone transitions. +// +// To count the number of units in a Duration, divide: +// second := time.Second +// fmt.Print(int64(second/time.Millisecond)) // prints 1000 +// +// To convert an integer number of units to a Duration, multiply: +// seconds := 10 +// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s +// +const ( + Nanosecond Duration = 1 + Microsecond = 1000 * Nanosecond + Millisecond = 1000 * Microsecond + Second = 1000 * Millisecond + Minute = 60 * Second + Hour = 60 * Minute +) + +// String returns a string representing the duration in the form "72h3m0.5s". +// Leading zero units are omitted. As a special case, durations less than one +// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure +// that the leading digit is non-zero. The zero duration formats as 0s. +func (d Duration) String() string { + // Largest time is 2540400h10m10.000000000s + var buf [32]byte + w := len(buf) + + u := uint64(d) + neg := d < 0 + if neg { + u = -u + } + + if u < uint64(Second) { + // Special case: if duration is smaller than a second, + // use smaller units, like 1.2ms + var prec int + w-- + buf[w] = 's' + w-- + switch { + case u == 0: + return "0s" + case u < uint64(Microsecond): + // print nanoseconds + prec = 0 + buf[w] = 'n' + case u < uint64(Millisecond): + // print microseconds + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w-- // Need room for two bytes. + copy(buf[w:], "µ") + default: + // print milliseconds + prec = 6 + buf[w] = 'm' + } + w, u = fmtFrac(buf[:w], u, prec) + w = fmtInt(buf[:w], u) + } else { + w-- + buf[w] = 's' + + w, u = fmtFrac(buf[:w], u, 9) + + // u is now integer seconds + w = fmtInt(buf[:w], u%60) + u /= 60 + + // u is now integer minutes + if u > 0 { + w-- + buf[w] = 'm' + w = fmtInt(buf[:w], u%60) + u /= 60 + + // u is now integer hours + // Stop at hours because days can be different lengths. + if u > 0 { + w-- + buf[w] = 'h' + w = fmtInt(buf[:w], u) + } + } + } + + if neg { + w-- + buf[w] = '-' + } + + return string(buf[w:]) +} + +// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the +// tail of buf, omitting trailing zeros. It omits the decimal +// point too when the fraction is 0. It returns the index where the +// output bytes begin and the value v/10**prec. +func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) { + // Omit trailing zeros up to and including decimal point. + w := len(buf) + print := false + for i := 0; i < prec; i++ { + digit := v % 10 + print = print || digit != 0 + if print { + w-- + buf[w] = byte(digit) + '0' + } + v /= 10 + } + if print { + w-- + buf[w] = '.' + } + return w, v +} + +// fmtInt formats v into the tail of buf. +// It returns the index where the output begins. +func fmtInt(buf []byte, v uint64) int { + w := len(buf) + if v == 0 { + w-- + buf[w] = '0' + } else { + for v > 0 { + w-- + buf[w] = byte(v%10) + '0' + v /= 10 + } + } + return w +} + +// Nanoseconds returns the duration as an integer nanosecond count. +func (d Duration) Nanoseconds() int64 { return int64(d) } + +// Microseconds returns the duration as an integer microsecond count. +func (d Duration) Microseconds() int64 { return int64(d) / 1e3 } + +// Milliseconds returns the duration as an integer millisecond count. +func (d Duration) Milliseconds() int64 { return int64(d) / 1e6 } + +// These methods return float64 because the dominant +// use case is for printing a floating point number like 1.5s, and +// a truncation to integer would make them not useful in those cases. +// Splitting the integer and fraction ourselves guarantees that +// converting the returned float64 to an integer rounds the same +// way that a pure integer conversion would have, even in cases +// where, say, float64(d.Nanoseconds())/1e9 would have rounded +// differently. + +// Seconds returns the duration as a floating point number of seconds. +func (d Duration) Seconds() float64 { + sec := d / Second + nsec := d % Second + return float64(sec) + float64(nsec)/1e9 +} + +// Minutes returns the duration as a floating point number of minutes. +func (d Duration) Minutes() float64 { + min := d / Minute + nsec := d % Minute + return float64(min) + float64(nsec)/(60*1e9) +} + +// Hours returns the duration as a floating point number of hours. +func (d Duration) Hours() float64 { + hour := d / Hour + nsec := d % Hour + return float64(hour) + float64(nsec)/(60*60*1e9) +} + +// Truncate returns the result of rounding d toward zero to a multiple of m. +// If m <= 0, Truncate returns d unchanged. +func (d Duration) Truncate(m Duration) Duration { + if m <= 0 { + return d + } + return d - d%m +} + +// lessThanHalf reports whether x+x < y but avoids overflow, +// assuming x and y are both positive (Duration is signed). +func lessThanHalf(x, y Duration) bool { + return uint64(x)+uint64(x) < uint64(y) +} + +// Round returns the result of rounding d to the nearest multiple of m. +// The rounding behavior for halfway values is to round away from zero. +// If the result exceeds the maximum (or minimum) +// value that can be stored in a Duration, +// Round returns the maximum (or minimum) duration. +// If m <= 0, Round returns d unchanged. +func (d Duration) Round(m Duration) Duration { + if m <= 0 { + return d + } + r := d % m + if d < 0 { + r = -r + if lessThanHalf(r, m) { + return d + r + } + if d1 := d - m + r; d1 < d { + return d1 + } + return minDuration // overflow + } + if lessThanHalf(r, m) { + return d - r + } + if d1 := d + m - r; d1 > d { + return d1 + } + return maxDuration // overflow +} + +// Add returns the time t+d. +func (t Time) Add(d Duration) Time { + dsec := int64(d / 1e9) + nsec := t.nsec() + int32(d%1e9) + if nsec >= 1e9 { + dsec++ + nsec -= 1e9 + } else if nsec < 0 { + dsec-- + nsec += 1e9 + } + t.wall = t.wall&^nsecMask | uint64(nsec) // update nsec + t.addSec(dsec) + if t.wall&hasMonotonic != 0 { + te := t.ext + int64(d) + if d < 0 && te > t.ext || d > 0 && te < t.ext { + // Monotonic clock reading now out of range; degrade to wall-only. + t.stripMono() + } else { + t.ext = te + } + } + return t +} + +// Sub returns the duration t-u. If the result exceeds the maximum (or minimum) +// value that can be stored in a Duration, the maximum (or minimum) duration +// will be returned. +// To compute t-d for a duration d, use t.Add(-d). +func (t Time) Sub(u Time) Duration { + if t.wall&u.wall&hasMonotonic != 0 { + te := t.ext + ue := u.ext + d := Duration(te - ue) + if d < 0 && te > ue { + return maxDuration // t - u is positive out of range + } + if d > 0 && te < ue { + return minDuration // t - u is negative out of range + } + return d + } + d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec()) + // Check for overflow or underflow. + switch { + case u.Add(d).Equal(t): + return d // d is correct + case t.Before(u): + return minDuration // t - u is negative out of range + default: + return maxDuration // t - u is positive out of range + } +} + +// Since returns the time elapsed since t. +// It is shorthand for time.Now().Sub(t). +func Since(t Time) Duration { + var now Time + if t.wall&hasMonotonic != 0 { + // Common case optimization: if t has monotonic time, then Sub will use only it. + now = Time{hasMonotonic, runtimeNano() - startNano, nil} + } else { + now = Now() + } + return now.Sub(t) +} + +// Until returns the duration until t. +// It is shorthand for t.Sub(time.Now()). +func Until(t Time) Duration { + var now Time + if t.wall&hasMonotonic != 0 { + // Common case optimization: if t has monotonic time, then Sub will use only it. + now = Time{hasMonotonic, runtimeNano() - startNano, nil} + } else { + now = Now() + } + return t.Sub(now) +} + +// AddDate returns the time corresponding to adding the +// given number of years, months, and days to t. +// For example, AddDate(-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. +func (t Time) AddDate(years int, months int, days int) Time { + year, month, day := t.Date() + hour, min, sec := t.Clock() + return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) +} + +const ( + secondsPerMinute = 60 + secondsPerHour = 60 * secondsPerMinute + secondsPerDay = 24 * secondsPerHour + secondsPerWeek = 7 * secondsPerDay + daysPer400Years = 365*400 + 97 + daysPer100Years = 365*100 + 24 + daysPer4Years = 365*4 + 1 +) + +// date computes the year, day of year, and when full=true, +// the month and day in which t occurs. +func (t Time) date(full bool) (year int, month Month, day int, yday int) { + return absDate(t.abs(), full) +} + +// absDate is like date but operates on an absolute time. +func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { + // Split into time and day. + d := abs / secondsPerDay + + // Account for 400 year cycles. + n := d / daysPer400Years + y := 400 * n + d -= daysPer400Years * n + + // Cut off 100-year cycles. + // The last cycle has one extra leap year, so on the last day + // of that year, day / daysPer100Years will be 4 instead of 3. + // Cut it back down to 3 by subtracting n>>2. + n = d / daysPer100Years + n -= n >> 2 + y += 100 * n + d -= daysPer100Years * n + + // Cut off 4-year cycles. + // The last cycle has a missing leap year, which does not + // affect the computation. + n = d / daysPer4Years + y += 4 * n + d -= daysPer4Years * n + + // Cut off years within a 4-year cycle. + // The last year is a leap year, so on the last day of that year, + // day / 365 will be 4 instead of 3. Cut it back down to 3 + // by subtracting n>>2. + n = d / 365 + n -= n >> 2 + y += n + d -= 365 * n + + year = int(int64(y) + absoluteZeroYear) + yday = int(d) + + if !full { + return + } + + day = yday + if isLeap(year) { + // Leap year + switch { + case day > 31+29-1: + // After leap day; pretend it wasn't there. + day-- + case day == 31+29-1: + // Leap day. + month = February + day = 29 + return + } + } + + // Estimate month on assumption that every month has 31 days. + // The estimate may be too low by at most one month, so adjust. + month = Month(day / 31) + end := int(daysBefore[month+1]) + var begin int + if day >= end { + month++ + begin = end + } else { + begin = int(daysBefore[month]) + } + + month++ // because January is 1 + day = day - begin + 1 + return +} + +// daysBefore[m] counts the number of days in a non-leap year +// before month m begins. There is an entry for m=12, counting +// the number of days before January of next year (365). +var daysBefore = [...]int32{ + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, +} + +func daysIn(m Month, year int) int { + if m == February && isLeap(year) { + return 29 + } + return int(daysBefore[m] - daysBefore[m-1]) +} + +// daysSinceEpoch takes a year and returns the number of days from +// the absolute epoch to the start of that year. +// This is basically (year - zeroYear) * 365, but accounting for leap days. +func daysSinceEpoch(year int) uint64 { + y := uint64(int64(year) - absoluteZeroYear) + + // Add in days from 400-year cycles. + n := y / 400 + y -= 400 * n + d := daysPer400Years * n + + // Add in 100-year cycles. + n = y / 100 + y -= 100 * n + d += daysPer100Years * n + + // Add in 4-year cycles. + n = y / 4 + y -= 4 * n + d += daysPer4Years * n + + // Add in non-leap years. + n = y + d += 365 * n + + return d +} + +// Provided by package runtime. +func now() (sec int64, nsec int32, mono int64) + +// runtimeNano returns the current value of the runtime clock in nanoseconds. +//go:linkname runtimeNano runtime.nanotime +func runtimeNano() int64 + +// Monotonic times are reported as offsets from startNano. +// We initialize startNano to runtimeNano() - 1 so that on systems where +// monotonic time resolution is fairly low (e.g. Windows 2008 +// which appears to have a default resolution of 15ms), +// we avoid ever reporting a monotonic time of 0. +// (Callers may want to use 0 as "time not set".) +var startNano int64 = runtimeNano() - 1 + +// Now returns the current local time. +func Now() Time { + sec, nsec, mono := now() + mono -= startNano + sec += unixToInternal - minWall + if uint64(sec)>>33 != 0 { + return Time{uint64(nsec), sec + minWall, Local} + } + return Time{hasMonotonic | uint64(sec)<<nsecShift | uint64(nsec), mono, Local} +} + +func unixTime(sec int64, nsec int32) Time { + return Time{uint64(nsec), sec + unixToInternal, Local} +} + +// UTC returns t with the location set to UTC. +func (t Time) UTC() Time { + t.setLoc(&utcLoc) + return t +} + +// Local returns t with the location set to local time. +func (t Time) Local() Time { + t.setLoc(Local) + return t +} + +// In returns a copy of t representing the same time instant, but +// with the copy's location information set to loc for display +// purposes. +// +// In panics if loc is nil. +func (t Time) In(loc *Location) Time { + if loc == nil { + panic("time: missing Location in call to Time.In") + } + t.setLoc(loc) + return t +} + +// Location returns the time zone information associated with t. +func (t Time) Location() *Location { + l := t.loc + if l == nil { + l = UTC + } + return l +} + +// Zone computes the time zone in effect at time t, returning the abbreviated +// name of the zone (such as "CET") and its offset in seconds east of UTC. +func (t Time) Zone() (name string, offset int) { + name, offset, _, _, _ = t.loc.lookup(t.unixSec()) + return +} + +// Unix returns t as a Unix time, the number of seconds elapsed +// since January 1, 1970 UTC. The result does not depend on the +// location associated with t. +// Unix-like operating systems often record time as a 32-bit +// count of seconds, but since the method here returns a 64-bit +// value it is valid for billions of years into the past or future. +func (t Time) Unix() int64 { + return t.unixSec() +} + +// UnixMilli returns t as a Unix time, the number of milliseconds elapsed since +// January 1, 1970 UTC. The result is undefined if the Unix time in +// milliseconds cannot be represented by an int64 (a date more than 292 million +// years before or after 1970). The result does not depend on the +// location associated with t. +func (t Time) UnixMilli() int64 { + return t.unixSec()*1e3 + int64(t.nsec())/1e6 +} + +// UnixMicro returns t as a Unix time, the number of microseconds elapsed since +// January 1, 1970 UTC. The result is undefined if the Unix time in +// microseconds cannot be represented by an int64 (a date before year -290307 or +// after year 294246). The result does not depend on the location associated +// with t. +func (t Time) UnixMicro() int64 { + return t.unixSec()*1e6 + int64(t.nsec())/1e3 +} + +// UnixNano returns t as a Unix time, the number of nanoseconds elapsed +// since January 1, 1970 UTC. The result is undefined if the Unix time +// in nanoseconds cannot be represented by an int64 (a date before the year +// 1678 or after 2262). Note that this means the result of calling UnixNano +// on the zero Time is undefined. The result does not depend on the +// location associated with t. +func (t Time) UnixNano() int64 { + return (t.unixSec())*1e9 + int64(t.nsec()) +} + +const ( + timeBinaryVersionV1 byte = iota + 1 // For general situation + timeBinaryVersionV2 // For LMT only +) + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (t Time) MarshalBinary() ([]byte, error) { + var offsetMin int16 // minutes east of UTC. -1 is UTC. + var offsetSec int8 + version := timeBinaryVersionV1 + + if t.Location() == UTC { + offsetMin = -1 + } else { + _, offset := t.Zone() + if offset%60 != 0 { + version = timeBinaryVersionV2 + offsetSec = int8(offset % 60) + } + + offset /= 60 + if offset < -32768 || offset == -1 || offset > 32767 { + return nil, errors.New("Time.MarshalBinary: unexpected zone offset") + } + offsetMin = int16(offset) + } + + sec := t.sec() + nsec := t.nsec() + enc := []byte{ + version, // byte 0 : version + byte(sec >> 56), // bytes 1-8: seconds + byte(sec >> 48), + byte(sec >> 40), + byte(sec >> 32), + byte(sec >> 24), + byte(sec >> 16), + byte(sec >> 8), + byte(sec), + byte(nsec >> 24), // bytes 9-12: nanoseconds + byte(nsec >> 16), + byte(nsec >> 8), + byte(nsec), + byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes + byte(offsetMin), + } + if version == timeBinaryVersionV2 { + enc = append(enc, byte(offsetSec)) + } + + return enc, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (t *Time) UnmarshalBinary(data []byte) error { + buf := data + if len(buf) == 0 { + return errors.New("Time.UnmarshalBinary: no data") + } + + version := buf[0] + if version != timeBinaryVersionV1 && version != timeBinaryVersionV2 { + return errors.New("Time.UnmarshalBinary: unsupported version") + } + + wantLen := /*version*/ 1 + /*sec*/ 8 + /*nsec*/ 4 + /*zone offset*/ 2 + if version == timeBinaryVersionV2 { + wantLen++ + } + if len(buf) != wantLen { + return errors.New("Time.UnmarshalBinary: invalid length") + } + + buf = buf[1:] + sec := int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 | + int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56 + + buf = buf[8:] + nsec := int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24 + + buf = buf[4:] + offset := int(int16(buf[1])|int16(buf[0])<<8) * 60 + if version == timeBinaryVersionV2 { + offset += int(buf[2]) + } + + *t = Time{} + t.wall = uint64(nsec) + t.ext = sec + + if offset == -1*60 { + t.setLoc(&utcLoc) + } else if _, localoff, _, _, _ := Local.lookup(t.unixSec()); offset == localoff { + t.setLoc(Local) + } else { + t.setLoc(FixedZone("", offset)) + } + + return nil +} + +// TODO(rsc): Remove GobEncoder, GobDecoder, MarshalJSON, UnmarshalJSON in Go 2. +// The same semantics will be provided by the generic MarshalBinary, MarshalText, +// UnmarshalBinary, UnmarshalText. + +// GobEncode implements the gob.GobEncoder interface. +func (t Time) GobEncode() ([]byte, error) { + return t.MarshalBinary() +} + +// GobDecode implements the gob.GobDecoder interface. +func (t *Time) GobDecode(data []byte) error { + return t.UnmarshalBinary(data) +} + +// MarshalJSON implements the json.Marshaler interface. +// The time is a quoted string in RFC 3339 format, with sub-second precision added if present. +func (t Time) MarshalJSON() ([]byte, error) { + if y := t.Year(); y < 0 || y >= 10000 { + // RFC 3339 is clear that years are 4 digits exactly. + // See golang.org/issue/4556#c15 for more discussion. + return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]") + } + + b := make([]byte, 0, len(RFC3339Nano)+2) + b = append(b, '"') + b = t.AppendFormat(b, RFC3339Nano) + b = append(b, '"') + return b, nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +// The time is expected to be a quoted string in RFC 3339 format. +func (t *Time) UnmarshalJSON(data []byte) error { + // Ignore null, like in the main JSON package. + if string(data) == "null" { + return nil + } + // Fractional seconds are handled implicitly by Parse. + var err error + *t, err = Parse(`"`+RFC3339+`"`, string(data)) + return err +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The time is formatted in RFC 3339 format, with sub-second precision added if present. +func (t Time) MarshalText() ([]byte, error) { + if y := t.Year(); y < 0 || y >= 10000 { + return nil, errors.New("Time.MarshalText: year outside of range [0,9999]") + } + + b := make([]byte, 0, len(RFC3339Nano)) + return t.AppendFormat(b, RFC3339Nano), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The time is expected to be in RFC 3339 format. +func (t *Time) UnmarshalText(data []byte) error { + // Fractional seconds are handled implicitly by Parse. + var err error + *t, err = Parse(RFC3339, string(data)) + return err +} + +// Unix returns the local Time corresponding to the given Unix time, +// sec seconds and nsec nanoseconds since January 1, 1970 UTC. +// It is valid to pass nsec outside the range [0, 999999999]. +// Not all sec values have a corresponding time value. One such +// value is 1<<63-1 (the largest int64 value). +func Unix(sec int64, nsec int64) Time { + if nsec < 0 || nsec >= 1e9 { + n := nsec / 1e9 + sec += n + nsec -= n * 1e9 + if nsec < 0 { + nsec += 1e9 + sec-- + } + } + return unixTime(sec, int32(nsec)) +} + +// UnixMilli returns the local Time corresponding to the given Unix time, +// msec milliseconds since January 1, 1970 UTC. +func UnixMilli(msec int64) Time { + return Unix(msec/1e3, (msec%1e3)*1e6) +} + +// UnixMicro returns the local Time corresponding to the given Unix time, +// usec microseconds since January 1, 1970 UTC. +func UnixMicro(usec int64) Time { + return Unix(usec/1e6, (usec%1e6)*1e3) +} + +// IsDST reports whether the time in the configured location is in Daylight Savings Time. +func (t Time) IsDST() bool { + _, _, _, _, isDST := t.loc.lookup(t.Unix()) + return isDST +} + +func isLeap(year int) bool { + return year%4 == 0 && (year%100 != 0 || year%400 == 0) +} + +// norm returns nhi, nlo such that +// hi * base + lo == nhi * base + nlo +// 0 <= nlo < base +func norm(hi, lo, base int) (nhi, nlo int) { + if lo < 0 { + n := (-lo-1)/base + 1 + hi -= n + lo += n * base + } + if lo >= base { + n := lo / base + hi += n + lo -= n * base + } + return hi, lo +} + +// Date returns the Time corresponding to +// yyyy-mm-dd hh:mm:ss + nsec nanoseconds +// in the appropriate zone for that time in the given location. +// +// The month, day, hour, min, sec, and nsec values may be outside +// their usual ranges and will be normalized during the conversion. +// For example, October 32 converts to November 1. +// +// A daylight savings time transition skips or repeats times. +// For example, in the United States, March 13, 2011 2:15am never occurred, +// while November 6, 2011 1:15am occurred twice. In such cases, the +// choice of time zone, and therefore the time, is not well-defined. +// Date returns a time that is correct in one of the two zones involved +// in the transition, but it does not guarantee which. +// +// Date panics if loc is nil. +func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time { + if loc == nil { + panic("time: missing Location in call to Date") + } + + // Normalize month, overflowing into year. + m := int(month) - 1 + year, m = norm(year, m, 12) + month = Month(m) + 1 + + // Normalize nsec, sec, min, hour, overflowing into day. + sec, nsec = norm(sec, nsec, 1e9) + min, sec = norm(min, sec, 60) + hour, min = norm(hour, min, 60) + day, hour = norm(day, hour, 24) + + // Compute days since the absolute epoch. + d := daysSinceEpoch(year) + + // Add in days before this month. + d += uint64(daysBefore[month-1]) + if isLeap(year) && month >= March { + d++ // February 29 + } + + // Add in days before today. + d += uint64(day - 1) + + // Add in time elapsed today. + abs := d * secondsPerDay + abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec) + + unix := int64(abs) + (absoluteToInternal + internalToUnix) + + // Look for zone offset for expected time, so we can adjust to UTC. + // The lookup function expects UTC, so first we pass unix in the + // hope that it will not be too close to a zone transition, + // and then adjust if it is. + _, offset, start, end, _ := loc.lookup(unix) + if offset != 0 { + utc := unix - int64(offset) + // If utc is valid for the time zone we found, then we have the right offset. + // If not, we get the correct offset by looking up utc in the location. + if utc < start || utc >= end { + _, offset, _, _, _ = loc.lookup(utc) + } + unix -= int64(offset) + } + + t := unixTime(unix, int32(nsec)) + t.setLoc(loc) + return t +} + +// Truncate returns the result of rounding t down to a multiple of d (since the zero time). +// If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. +// +// Truncate operates on the time as an absolute duration since the +// zero time; it does not operate on the presentation form of the +// time. Thus, Truncate(Hour) may return a time with a non-zero +// minute, depending on the time's Location. +func (t Time) Truncate(d Duration) Time { + t.stripMono() + if d <= 0 { + return t + } + _, r := div(t, d) + return t.Add(-r) +} + +// Round returns the result of rounding t to the nearest multiple of d (since the zero time). +// The rounding behavior for halfway values is to round up. +// If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. +// +// Round operates on the time as an absolute duration since the +// zero time; it does not operate on the presentation form of the +// time. Thus, Round(Hour) may return a time with a non-zero +// minute, depending on the time's Location. +func (t Time) Round(d Duration) Time { + t.stripMono() + if d <= 0 { + return t + } + _, r := div(t, d) + if lessThanHalf(r, d) { + return t.Add(-r) + } + return t.Add(d - r) +} + +// div divides t by d and returns the quotient parity and remainder. +// We don't use the quotient parity anymore (round half up instead of round to even) +// but it's still here in case we change our minds. +func div(t Time, d Duration) (qmod2 int, r Duration) { + neg := false + nsec := t.nsec() + sec := t.sec() + if sec < 0 { + // Operate on absolute value. + neg = true + sec = -sec + nsec = -nsec + if nsec < 0 { + nsec += 1e9 + sec-- // sec >= 1 before the -- so safe + } + } + + switch { + // Special case: 2d divides 1 second. + case d < Second && Second%(d+d) == 0: + qmod2 = int(nsec/int32(d)) & 1 + r = Duration(nsec % int32(d)) + + // Special case: d is a multiple of 1 second. + case d%Second == 0: + d1 := int64(d / Second) + qmod2 = int(sec/d1) & 1 + r = Duration(sec%d1)*Second + Duration(nsec) + + // General case. + // This could be faster if more cleverness were applied, + // but it's really only here to avoid special case restrictions in the API. + // No one will care about these cases. + default: + // Compute nanoseconds as 128-bit number. + sec := uint64(sec) + tmp := (sec >> 32) * 1e9 + u1 := tmp >> 32 + u0 := tmp << 32 + tmp = (sec & 0xFFFFFFFF) * 1e9 + u0x, u0 := u0, u0+tmp + if u0 < u0x { + u1++ + } + u0x, u0 = u0, u0+uint64(nsec) + if u0 < u0x { + u1++ + } + + // Compute remainder by subtracting r<<k for decreasing k. + // Quotient parity is whether we subtract on last round. + d1 := uint64(d) + for d1>>63 != 1 { + d1 <<= 1 + } + d0 := uint64(0) + for { + qmod2 = 0 + if u1 > d1 || u1 == d1 && u0 >= d0 { + // subtract + qmod2 = 1 + u0x, u0 = u0, u0-d0 + if u0 > u0x { + u1-- + } + u1 -= d1 + } + if d1 == 0 && d0 == uint64(d) { + break + } + d0 >>= 1 + d0 |= (d1 & 1) << 63 + d1 >>= 1 + } + r = Duration(u0) + } + + if neg && r != 0 { + // If input was negative and not an exact multiple of d, we computed q, r such that + // q*d + r = -t + // But the right answers are given by -(q-1), d-r: + // q*d + r = -t + // -q*d - r = t + // -(q-1)*d + (d - r) = t + qmod2 ^= 1 + r = d - r + } + return +} diff --git a/contrib/go/_std_1.18/src/time/zoneinfo.go b/contrib/go/_std_1.18/src/time/zoneinfo.go new file mode 100644 index 0000000000..7b39f869e6 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/zoneinfo.go @@ -0,0 +1,687 @@ +// Copyright 2011 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 time + +import ( + "errors" + "sync" + "syscall" +) + +//go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go + +// A Location maps time instants to the zone in use at that time. +// Typically, the Location represents the collection of time offsets +// in use in a geographical area. For many Locations the time offset varies +// depending on whether daylight savings time is in use at the time instant. +type Location struct { + name string + zone []zone + tx []zoneTrans + + // The tzdata information can be followed by a string that describes + // how to handle DST transitions not recorded in zoneTrans. + // The format is the TZ environment variable without a colon; see + // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html. + // Example string, for America/Los_Angeles: PST8PDT,M3.2.0,M11.1.0 + extend string + + // Most lookups will be for the current time. + // To avoid the binary search through tx, keep a + // static one-element cache that gives the correct + // zone for the time when the Location was created. + // if cacheStart <= t < cacheEnd, + // lookup can return cacheZone. + // The units for cacheStart and cacheEnd are seconds + // since January 1, 1970 UTC, to match the argument + // to lookup. + cacheStart int64 + cacheEnd int64 + cacheZone *zone +} + +// A zone represents a single time zone such as CET. +type zone struct { + name string // abbreviated name, "CET" + offset int // seconds east of UTC + isDST bool // is this zone Daylight Savings Time? +} + +// A zoneTrans represents a single time zone transition. +type zoneTrans struct { + when int64 // transition time, in seconds since 1970 GMT + index uint8 // the index of the zone that goes into effect at that time + isstd, isutc bool // ignored - no idea what these mean +} + +// alpha and omega are the beginning and end of time for zone +// transitions. +const ( + alpha = -1 << 63 // math.MinInt64 + omega = 1<<63 - 1 // math.MaxInt64 +) + +// UTC represents Universal Coordinated Time (UTC). +var UTC *Location = &utcLoc + +// utcLoc is separate so that get can refer to &utcLoc +// and ensure that it never returns a nil *Location, +// even if a badly behaved client has changed UTC. +var utcLoc = Location{name: "UTC"} + +// Local represents the system's local time zone. +// On Unix systems, Local consults the TZ environment +// variable to find the time zone to use. No TZ means +// use the system default /etc/localtime. +// TZ="" means use UTC. +// TZ="foo" means use file foo in the system timezone directory. +var Local *Location = &localLoc + +// localLoc is separate so that initLocal can initialize +// it even if a client has changed Local. +var localLoc Location +var localOnce sync.Once + +func (l *Location) get() *Location { + if l == nil { + return &utcLoc + } + if l == &localLoc { + localOnce.Do(initLocal) + } + return l +} + +// String returns a descriptive name for the time zone information, +// corresponding to the name argument to LoadLocation or FixedZone. +func (l *Location) String() string { + return l.get().name +} + +// FixedZone returns a Location that always uses +// the given zone name and offset (seconds east of UTC). +func FixedZone(name string, offset int) *Location { + l := &Location{ + name: name, + zone: []zone{{name, offset, false}}, + tx: []zoneTrans{{alpha, 0, false, false}}, + cacheStart: alpha, + cacheEnd: omega, + } + l.cacheZone = &l.zone[0] + return l +} + +// lookup returns information about the time zone in use at an +// instant in time expressed as seconds since January 1, 1970 00:00:00 UTC. +// +// The returned information gives the name of the zone (such as "CET"), +// the start and end times bracketing sec when that zone is in effect, +// the offset in seconds east of UTC (such as -5*60*60), and whether +// the daylight savings is being observed at that time. +func (l *Location) lookup(sec int64) (name string, offset int, start, end int64, isDST bool) { + l = l.get() + + if len(l.zone) == 0 { + name = "UTC" + offset = 0 + start = alpha + end = omega + isDST = false + return + } + + if zone := l.cacheZone; zone != nil && l.cacheStart <= sec && sec < l.cacheEnd { + name = zone.name + offset = zone.offset + start = l.cacheStart + end = l.cacheEnd + isDST = zone.isDST + return + } + + if len(l.tx) == 0 || sec < l.tx[0].when { + zone := &l.zone[l.lookupFirstZone()] + name = zone.name + offset = zone.offset + start = alpha + if len(l.tx) > 0 { + end = l.tx[0].when + } else { + end = omega + } + isDST = zone.isDST + return + } + + // Binary search for entry with largest time <= sec. + // Not using sort.Search to avoid dependencies. + tx := l.tx + end = omega + lo := 0 + hi := len(tx) + for hi-lo > 1 { + m := lo + (hi-lo)/2 + lim := tx[m].when + if sec < lim { + end = lim + hi = m + } else { + lo = m + } + } + zone := &l.zone[tx[lo].index] + name = zone.name + offset = zone.offset + start = tx[lo].when + // end = maintained during the search + isDST = zone.isDST + + // If we're at the end of the known zone transitions, + // try the extend string. + if lo == len(tx)-1 && l.extend != "" { + if ename, eoffset, estart, eend, eisDST, ok := tzset(l.extend, end, sec); ok { + return ename, eoffset, estart, eend, eisDST + } + } + + return +} + +// lookupFirstZone returns the index of the time zone to use for times +// before the first transition time, or when there are no transition +// times. +// +// The reference implementation in localtime.c from +// https://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz +// implements the following algorithm for these cases: +// 1) If the first zone is unused by the transitions, use it. +// 2) Otherwise, if there are transition times, and the first +// transition is to a zone in daylight time, find the first +// non-daylight-time zone before and closest to the first transition +// zone. +// 3) Otherwise, use the first zone that is not daylight time, if +// there is one. +// 4) Otherwise, use the first zone. +func (l *Location) lookupFirstZone() int { + // Case 1. + if !l.firstZoneUsed() { + return 0 + } + + // Case 2. + if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST { + for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- { + if !l.zone[zi].isDST { + return zi + } + } + } + + // Case 3. + for zi := range l.zone { + if !l.zone[zi].isDST { + return zi + } + } + + // Case 4. + return 0 +} + +// firstZoneUsed reports whether the first zone is used by some +// transition. +func (l *Location) firstZoneUsed() bool { + for _, tx := range l.tx { + if tx.index == 0 { + return true + } + } + return false +} + +// tzset takes a timezone string like the one found in the TZ environment +// variable, the end of the last time zone transition expressed as seconds +// since January 1, 1970 00:00:00 UTC, and a time expressed the same way. +// We call this a tzset string since in C the function tzset reads TZ. +// The return values are as for lookup, plus ok which reports whether the +// parse succeeded. +func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, isDST, ok bool) { + var ( + stdName, dstName string + stdOffset, dstOffset int + ) + + stdName, s, ok = tzsetName(s) + if ok { + stdOffset, s, ok = tzsetOffset(s) + } + if !ok { + return "", 0, 0, 0, false, false + } + + // The numbers in the tzset string are added to local time to get UTC, + // but our offsets are added to UTC to get local time, + // so we negate the number we see here. + stdOffset = -stdOffset + + if len(s) == 0 || s[0] == ',' { + // No daylight savings time. + return stdName, stdOffset, initEnd, omega, false, true + } + + dstName, s, ok = tzsetName(s) + if ok { + if len(s) == 0 || s[0] == ',' { + dstOffset = stdOffset + secondsPerHour + } else { + dstOffset, s, ok = tzsetOffset(s) + dstOffset = -dstOffset // as with stdOffset, above + } + } + if !ok { + return "", 0, 0, 0, false, false + } + + if len(s) == 0 { + // Default DST rules per tzcode. + s = ",M3.2.0,M11.1.0" + } + // The TZ definition does not mention ';' here but tzcode accepts it. + if s[0] != ',' && s[0] != ';' { + return "", 0, 0, 0, false, false + } + s = s[1:] + + var startRule, endRule rule + startRule, s, ok = tzsetRule(s) + if !ok || len(s) == 0 || s[0] != ',' { + return "", 0, 0, 0, false, false + } + s = s[1:] + endRule, s, ok = tzsetRule(s) + if !ok || len(s) > 0 { + return "", 0, 0, 0, false, false + } + + year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) + + ysec := int64(yday*secondsPerDay) + sec%secondsPerDay + + // Compute start of year in seconds since Unix epoch. + d := daysSinceEpoch(year) + abs := int64(d * secondsPerDay) + abs += absoluteToInternal + internalToUnix + + startSec := int64(tzruleTime(year, startRule, stdOffset)) + endSec := int64(tzruleTime(year, endRule, dstOffset)) + dstIsDST, stdIsDST := true, false + // Note: this is a flipping of "DST" and "STD" while retaining the labels + // This happens in southern hemispheres. The labelling here thus is a little + // inconsistent with the goal. + if endSec < startSec { + startSec, endSec = endSec, startSec + stdName, dstName = dstName, stdName + stdOffset, dstOffset = dstOffset, stdOffset + stdIsDST, dstIsDST = dstIsDST, stdIsDST + } + + // The start and end values that we return are accurate + // close to a daylight savings transition, but are otherwise + // just the start and end of the year. That suffices for + // the only caller that cares, which is Date. + if ysec < startSec { + return stdName, stdOffset, abs, startSec + abs, stdIsDST, true + } else if ysec >= endSec { + return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, stdIsDST, true + } else { + return dstName, dstOffset, startSec + abs, endSec + abs, dstIsDST, true + } +} + +// tzsetName returns the timezone name at the start of the tzset string s, +// and the remainder of s, and reports whether the parsing is OK. +func tzsetName(s string) (string, string, bool) { + if len(s) == 0 { + return "", "", false + } + if s[0] != '<' { + for i, r := range s { + switch r { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '-', '+': + if i < 3 { + return "", "", false + } + return s[:i], s[i:], true + } + } + if len(s) < 3 { + return "", "", false + } + return s, "", true + } else { + for i, r := range s { + if r == '>' { + return s[1:i], s[i+1:], true + } + } + return "", "", false + } +} + +// tzsetOffset returns the timezone offset at the start of the tzset string s, +// and the remainder of s, and reports whether the parsing is OK. +// The timezone offset is returned as a number of seconds. +func tzsetOffset(s string) (offset int, rest string, ok bool) { + if len(s) == 0 { + return 0, "", false + } + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + s = s[1:] + neg = true + } + + // The tzdata code permits values up to 24 * 7 here, + // although POSIX does not. + var hours int + hours, s, ok = tzsetNum(s, 0, 24*7) + if !ok { + return 0, "", false + } + off := hours * secondsPerHour + if len(s) == 0 || s[0] != ':' { + if neg { + off = -off + } + return off, s, true + } + + var mins int + mins, s, ok = tzsetNum(s[1:], 0, 59) + if !ok { + return 0, "", false + } + off += mins * secondsPerMinute + if len(s) == 0 || s[0] != ':' { + if neg { + off = -off + } + return off, s, true + } + + var secs int + secs, s, ok = tzsetNum(s[1:], 0, 59) + if !ok { + return 0, "", false + } + off += secs + + if neg { + off = -off + } + return off, s, true +} + +// ruleKind is the kinds of rules that can be seen in a tzset string. +type ruleKind int + +const ( + ruleJulian ruleKind = iota + ruleDOY + ruleMonthWeekDay +) + +// rule is a rule read from a tzset string. +type rule struct { + kind ruleKind + day int + week int + mon int + time int // transition time +} + +// tzsetRule parses a rule from a tzset string. +// It returns the rule, and the remainder of the string, and reports success. +func tzsetRule(s string) (rule, string, bool) { + var r rule + if len(s) == 0 { + return rule{}, "", false + } + ok := false + if s[0] == 'J' { + var jday int + jday, s, ok = tzsetNum(s[1:], 1, 365) + if !ok { + return rule{}, "", false + } + r.kind = ruleJulian + r.day = jday + } else if s[0] == 'M' { + var mon int + mon, s, ok = tzsetNum(s[1:], 1, 12) + if !ok || len(s) == 0 || s[0] != '.' { + return rule{}, "", false + + } + var week int + week, s, ok = tzsetNum(s[1:], 1, 5) + if !ok || len(s) == 0 || s[0] != '.' { + return rule{}, "", false + } + var day int + day, s, ok = tzsetNum(s[1:], 0, 6) + if !ok { + return rule{}, "", false + } + r.kind = ruleMonthWeekDay + r.day = day + r.week = week + r.mon = mon + } else { + var day int + day, s, ok = tzsetNum(s, 0, 365) + if !ok { + return rule{}, "", false + } + r.kind = ruleDOY + r.day = day + } + + if len(s) == 0 || s[0] != '/' { + r.time = 2 * secondsPerHour // 2am is the default + return r, s, true + } + + offset, s, ok := tzsetOffset(s[1:]) + if !ok { + return rule{}, "", false + } + r.time = offset + + return r, s, true +} + +// tzsetNum parses a number from a tzset string. +// It returns the number, and the remainder of the string, and reports success. +// The number must be between min and max. +func tzsetNum(s string, min, max int) (num int, rest string, ok bool) { + if len(s) == 0 { + return 0, "", false + } + num = 0 + for i, r := range s { + if r < '0' || r > '9' { + if i == 0 || num < min { + return 0, "", false + } + return num, s[i:], true + } + num *= 10 + num += int(r) - '0' + if num > max { + return 0, "", false + } + } + if num < min { + return 0, "", false + } + return num, "", true +} + +// tzruleTime takes a year, a rule, and a timezone offset, +// and returns the number of seconds since the start of the year +// that the rule takes effect. +func tzruleTime(year int, r rule, off int) int { + var s int + switch r.kind { + case ruleJulian: + s = (r.day - 1) * secondsPerDay + if isLeap(year) && r.day >= 60 { + s += secondsPerDay + } + case ruleDOY: + s = r.day * secondsPerDay + case ruleMonthWeekDay: + // Zeller's Congruence. + m1 := (r.mon+9)%12 + 1 + yy0 := year + if r.mon <= 2 { + yy0-- + } + yy1 := yy0 / 100 + yy2 := yy0 % 100 + dow := ((26*m1-2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1) % 7 + if dow < 0 { + dow += 7 + } + // Now dow is the day-of-week of the first day of r.mon. + // Get the day-of-month of the first "dow" day. + d := r.day - dow + if d < 0 { + d += 7 + } + for i := 1; i < r.week; i++ { + if d+7 >= daysIn(Month(r.mon), year) { + break + } + d += 7 + } + d += int(daysBefore[r.mon-1]) + if isLeap(year) && r.mon > 2 { + d++ + } + s = d * secondsPerDay + } + + return s + r.time - off +} + +// lookupName returns information about the time zone with +// the given name (such as "EST") at the given pseudo-Unix time +// (what the given time of day would be in UTC). +func (l *Location) lookupName(name string, unix int64) (offset int, ok bool) { + l = l.get() + + // First try for a zone with the right name that was actually + // in effect at the given time. (In Sydney, Australia, both standard + // and daylight-savings time are abbreviated "EST". Using the + // offset helps us pick the right one for the given time. + // It's not perfect: during the backward transition we might pick + // either one.) + for i := range l.zone { + zone := &l.zone[i] + if zone.name == name { + nam, offset, _, _, _ := l.lookup(unix - int64(zone.offset)) + if nam == zone.name { + return offset, true + } + } + } + + // Otherwise fall back to an ordinary name match. + for i := range l.zone { + zone := &l.zone[i] + if zone.name == name { + return zone.offset, true + } + } + + // Otherwise, give up. + return +} + +// NOTE(rsc): Eventually we will need to accept the POSIX TZ environment +// syntax too, but I don't feel like implementing it today. + +var errLocation = errors.New("time: invalid location name") + +var zoneinfo *string +var zoneinfoOnce sync.Once + +// LoadLocation returns the Location with the given name. +// +// If the name is "" or "UTC", LoadLocation returns UTC. +// If the name is "Local", LoadLocation returns Local. +// +// Otherwise, the name is taken to be a location name corresponding to a file +// in the IANA Time Zone database, such as "America/New_York". +// +// LoadLocation looks for the IANA Time Zone database in the following +// locations in order: +// +// - the directory or uncompressed zip file named by the ZONEINFO environment variable +// - on a Unix system, the system standard installation location +// - $GOROOT/lib/time/zoneinfo.zip +// - the time/tzdata package, if it was imported +func LoadLocation(name string) (*Location, error) { + if name == "" || name == "UTC" { + return UTC, nil + } + if name == "Local" { + return Local, nil + } + if containsDotDot(name) || name[0] == '/' || name[0] == '\\' { + // No valid IANA Time Zone name contains a single dot, + // much less dot dot. Likewise, none begin with a slash. + return nil, errLocation + } + zoneinfoOnce.Do(func() { + env, _ := syscall.Getenv("ZONEINFO") + zoneinfo = &env + }) + var firstErr error + if *zoneinfo != "" { + if zoneData, err := loadTzinfoFromDirOrZip(*zoneinfo, name); err == nil { + if z, err := LoadLocationFromTZData(name, zoneData); err == nil { + return z, nil + } + firstErr = err + } else if err != syscall.ENOENT { + firstErr = err + } + } + if z, err := loadLocation(name, zoneSources); err == nil { + return z, nil + } else if firstErr == nil { + firstErr = err + } + return nil, firstErr +} + +// containsDotDot reports whether s contains "..". +func containsDotDot(s string) bool { + if len(s) < 2 { + return false + } + for i := 0; i < len(s)-1; i++ { + if s[i] == '.' && s[i+1] == '.' { + return true + } + } + return false +} diff --git a/contrib/go/_std_1.18/src/time/zoneinfo_read.go b/contrib/go/_std_1.18/src/time/zoneinfo_read.go new file mode 100644 index 0000000000..b9830265e1 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/zoneinfo_read.go @@ -0,0 +1,586 @@ +// Copyright 2009 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. + +// Parse "zoneinfo" time zone file. +// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others. +// See tzfile(5), https://en.wikipedia.org/wiki/Zoneinfo, +// and ftp://munnari.oz.au/pub/oldtz/ + +package time + +import ( + "errors" + "runtime" + "syscall" +) + +// registerLoadFromEmbeddedTZData is called by the time/tzdata package, +// if it is imported. +func registerLoadFromEmbeddedTZData(f func(string) (string, error)) { + loadFromEmbeddedTZData = f +} + +// loadFromEmbeddedTZData is used to load a specific tzdata file +// from tzdata information embedded in the binary itself. +// This is set when the time/tzdata package is imported, +// via registerLoadFromEmbeddedTzdata. +var loadFromEmbeddedTZData func(zipname string) (string, error) + +// maxFileSize is the max permitted size of files read by readFile. +// As reference, the zoneinfo.zip distributed by Go is ~350 KB, +// so 10MB is overkill. +const maxFileSize = 10 << 20 + +type fileSizeError string + +func (f fileSizeError) Error() string { + return "time: file " + string(f) + " is too large" +} + +// Copies of io.Seek* constants to avoid importing "io": +const ( + seekStart = 0 + seekCurrent = 1 + seekEnd = 2 +) + +// Simple I/O interface to binary blob of data. +type dataIO struct { + p []byte + error bool +} + +func (d *dataIO) read(n int) []byte { + if len(d.p) < n { + d.p = nil + d.error = true + return nil + } + p := d.p[0:n] + d.p = d.p[n:] + return p +} + +func (d *dataIO) big4() (n uint32, ok bool) { + p := d.read(4) + if len(p) < 4 { + d.error = true + return 0, false + } + return uint32(p[3]) | uint32(p[2])<<8 | uint32(p[1])<<16 | uint32(p[0])<<24, true +} + +func (d *dataIO) big8() (n uint64, ok bool) { + n1, ok1 := d.big4() + n2, ok2 := d.big4() + if !ok1 || !ok2 { + d.error = true + return 0, false + } + return (uint64(n1) << 32) | uint64(n2), true +} + +func (d *dataIO) byte() (n byte, ok bool) { + p := d.read(1) + if len(p) < 1 { + d.error = true + return 0, false + } + return p[0], true +} + +// read returns the read of the data in the buffer. +func (d *dataIO) rest() []byte { + r := d.p + d.p = nil + return r +} + +// Make a string by stopping at the first NUL +func byteString(p []byte) string { + for i := 0; i < len(p); i++ { + if p[i] == 0 { + return string(p[0:i]) + } + } + return string(p) +} + +var badData = errors.New("malformed time zone information") + +// LoadLocationFromTZData returns a Location with the given name +// initialized from the IANA Time Zone database-formatted data. +// The data should be in the format of a standard IANA time zone file +// (for example, the content of /etc/localtime on Unix systems). +func LoadLocationFromTZData(name string, data []byte) (*Location, error) { + d := dataIO{data, false} + + // 4-byte magic "TZif" + if magic := d.read(4); string(magic) != "TZif" { + return nil, badData + } + + // 1-byte version, then 15 bytes of padding + var version int + var p []byte + if p = d.read(16); len(p) != 16 { + return nil, badData + } else { + switch p[0] { + case 0: + version = 1 + case '2': + version = 2 + case '3': + version = 3 + default: + return nil, badData + } + } + + // six big-endian 32-bit integers: + // number of UTC/local indicators + // number of standard/wall indicators + // number of leap seconds + // number of transition times + // number of local time zones + // number of characters of time zone abbrev strings + const ( + NUTCLocal = iota + NStdWall + NLeap + NTime + NZone + NChar + ) + var n [6]int + for i := 0; i < 6; i++ { + nn, ok := d.big4() + if !ok { + return nil, badData + } + if uint32(int(nn)) != nn { + return nil, badData + } + n[i] = int(nn) + } + + // If we have version 2 or 3, then the data is first written out + // in a 32-bit format, then written out again in a 64-bit format. + // Skip the 32-bit format and read the 64-bit one, as it can + // describe a broader range of dates. + + is64 := false + if version > 1 { + // Skip the 32-bit data. + skip := n[NTime]*4 + + n[NTime] + + n[NZone]*6 + + n[NChar] + + n[NLeap]*8 + + n[NStdWall] + + n[NUTCLocal] + // Skip the version 2 header that we just read. + skip += 4 + 16 + d.read(skip) + + is64 = true + + // Read the counts again, they can differ. + for i := 0; i < 6; i++ { + nn, ok := d.big4() + if !ok { + return nil, badData + } + if uint32(int(nn)) != nn { + return nil, badData + } + n[i] = int(nn) + } + } + + size := 4 + if is64 { + size = 8 + } + + // Transition times. + txtimes := dataIO{d.read(n[NTime] * size), false} + + // Time zone indices for transition times. + txzones := d.read(n[NTime]) + + // Zone info structures + zonedata := dataIO{d.read(n[NZone] * 6), false} + + // Time zone abbreviations. + abbrev := d.read(n[NChar]) + + // Leap-second time pairs + d.read(n[NLeap] * (size + 4)) + + // Whether tx times associated with local time types + // are specified as standard time or wall time. + isstd := d.read(n[NStdWall]) + + // Whether tx times associated with local time types + // are specified as UTC or local time. + isutc := d.read(n[NUTCLocal]) + + if d.error { // ran out of data + return nil, badData + } + + var extend string + rest := d.rest() + if len(rest) > 2 && rest[0] == '\n' && rest[len(rest)-1] == '\n' { + extend = string(rest[1 : len(rest)-1]) + } + + // Now we can build up a useful data structure. + // First the zone information. + // utcoff[4] isdst[1] nameindex[1] + nzone := n[NZone] + if nzone == 0 { + // Reject tzdata files with no zones. There's nothing useful in them. + // This also avoids a panic later when we add and then use a fake transition (golang.org/issue/29437). + return nil, badData + } + zones := make([]zone, nzone) + for i := range zones { + var ok bool + var n uint32 + if n, ok = zonedata.big4(); !ok { + return nil, badData + } + if uint32(int(n)) != n { + return nil, badData + } + zones[i].offset = int(int32(n)) + var b byte + if b, ok = zonedata.byte(); !ok { + return nil, badData + } + zones[i].isDST = b != 0 + if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { + return nil, badData + } + zones[i].name = byteString(abbrev[b:]) + if runtime.GOOS == "aix" && len(name) > 8 && (name[:8] == "Etc/GMT+" || name[:8] == "Etc/GMT-") { + // There is a bug with AIX 7.2 TL 0 with files in Etc, + // GMT+1 will return GMT-1 instead of GMT+1 or -01. + if name != "Etc/GMT+0" { + // GMT+0 is OK + zones[i].name = name[4:] + } + } + } + + // Now the transition time info. + tx := make([]zoneTrans, n[NTime]) + for i := range tx { + var n int64 + if !is64 { + if n4, ok := txtimes.big4(); !ok { + return nil, badData + } else { + n = int64(int32(n4)) + } + } else { + if n8, ok := txtimes.big8(); !ok { + return nil, badData + } else { + n = int64(n8) + } + } + tx[i].when = n + if int(txzones[i]) >= len(zones) { + return nil, badData + } + tx[i].index = txzones[i] + if i < len(isstd) { + tx[i].isstd = isstd[i] != 0 + } + if i < len(isutc) { + tx[i].isutc = isutc[i] != 0 + } + } + + if len(tx) == 0 { + // Build fake transition to cover all time. + // This happens in fixed locations like "Etc/GMT0". + tx = append(tx, zoneTrans{when: alpha, index: 0}) + } + + // Committed to succeed. + l := &Location{zone: zones, tx: tx, name: name, extend: extend} + + // Fill in the cache with information about right now, + // since that will be the most common lookup. + sec, _, _ := now() + for i := range tx { + if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { + l.cacheStart = tx[i].when + l.cacheEnd = omega + l.cacheZone = &l.zone[tx[i].index] + if i+1 < len(tx) { + l.cacheEnd = tx[i+1].when + } else if l.extend != "" { + // If we're at the end of the known zone transitions, + // try the extend string. + if name, offset, estart, eend, isDST, ok := tzset(l.extend, l.cacheEnd, sec); ok { + l.cacheStart = estart + l.cacheEnd = eend + // Find the zone that is returned by tzset to avoid allocation if possible. + if zoneIdx := findZone(l.zone, name, offset, isDST); zoneIdx != -1 { + l.cacheZone = &l.zone[zoneIdx] + } else { + l.cacheZone = &zone{ + name: name, + offset: offset, + isDST: isDST, + } + } + } + } + break + } + } + + return l, nil +} + +func findZone(zones []zone, name string, offset int, isDST bool) int { + for i, z := range zones { + if z.name == name && z.offset == offset && z.isDST == isDST { + return i + } + } + return -1 +} + +// loadTzinfoFromDirOrZip returns the contents of the file with the given name +// in dir. dir can either be an uncompressed zip file, or a directory. +func loadTzinfoFromDirOrZip(dir, name string) ([]byte, error) { + if len(dir) > 4 && dir[len(dir)-4:] == ".zip" { + return loadTzinfoFromZip(dir, name) + } + if dir != "" { + name = dir + "/" + name + } + return readFile(name) +} + +// There are 500+ zoneinfo files. Rather than distribute them all +// individually, we ship them in an uncompressed zip file. +// Used this way, the zip file format serves as a commonly readable +// container for the individual small files. We choose zip over tar +// because zip files have a contiguous table of contents, making +// individual file lookups faster, and because the per-file overhead +// in a zip file is considerably less than tar's 512 bytes. + +// get4 returns the little-endian 32-bit value in b. +func get4(b []byte) int { + if len(b) < 4 { + return 0 + } + return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24 +} + +// get2 returns the little-endian 16-bit value in b. +func get2(b []byte) int { + if len(b) < 2 { + return 0 + } + return int(b[0]) | int(b[1])<<8 +} + +// loadTzinfoFromZip returns the contents of the file with the given name +// in the given uncompressed zip file. +func loadTzinfoFromZip(zipfile, name string) ([]byte, error) { + fd, err := open(zipfile) + if err != nil { + return nil, err + } + defer closefd(fd) + + const ( + zecheader = 0x06054b50 + zcheader = 0x02014b50 + ztailsize = 22 + + zheadersize = 30 + zheader = 0x04034b50 + ) + + buf := make([]byte, ztailsize) + if err := preadn(fd, buf, -ztailsize); err != nil || get4(buf) != zecheader { + return nil, errors.New("corrupt zip file " + zipfile) + } + n := get2(buf[10:]) + size := get4(buf[12:]) + off := get4(buf[16:]) + + buf = make([]byte, size) + if err := preadn(fd, buf, off); err != nil { + return nil, errors.New("corrupt zip file " + zipfile) + } + + for i := 0; i < n; i++ { + // zip entry layout: + // 0 magic[4] + // 4 madevers[1] + // 5 madeos[1] + // 6 extvers[1] + // 7 extos[1] + // 8 flags[2] + // 10 meth[2] + // 12 modtime[2] + // 14 moddate[2] + // 16 crc[4] + // 20 csize[4] + // 24 uncsize[4] + // 28 namelen[2] + // 30 xlen[2] + // 32 fclen[2] + // 34 disknum[2] + // 36 iattr[2] + // 38 eattr[4] + // 42 off[4] + // 46 name[namelen] + // 46+namelen+xlen+fclen - next header + // + if get4(buf) != zcheader { + break + } + meth := get2(buf[10:]) + size := get4(buf[24:]) + namelen := get2(buf[28:]) + xlen := get2(buf[30:]) + fclen := get2(buf[32:]) + off := get4(buf[42:]) + zname := buf[46 : 46+namelen] + buf = buf[46+namelen+xlen+fclen:] + if string(zname) != name { + continue + } + if meth != 0 { + return nil, errors.New("unsupported compression for " + name + " in " + zipfile) + } + + // zip per-file header layout: + // 0 magic[4] + // 4 extvers[1] + // 5 extos[1] + // 6 flags[2] + // 8 meth[2] + // 10 modtime[2] + // 12 moddate[2] + // 14 crc[4] + // 18 csize[4] + // 22 uncsize[4] + // 26 namelen[2] + // 28 xlen[2] + // 30 name[namelen] + // 30+namelen+xlen - file data + // + buf = make([]byte, zheadersize+namelen) + if err := preadn(fd, buf, off); err != nil || + get4(buf) != zheader || + get2(buf[8:]) != meth || + get2(buf[26:]) != namelen || + string(buf[30:30+namelen]) != name { + return nil, errors.New("corrupt zip file " + zipfile) + } + xlen = get2(buf[28:]) + + buf = make([]byte, size) + if err := preadn(fd, buf, off+30+namelen+xlen); err != nil { + return nil, errors.New("corrupt zip file " + zipfile) + } + + return buf, nil + } + + return nil, syscall.ENOENT +} + +// loadTzinfoFromTzdata returns the time zone information of the time zone +// with the given name, from a tzdata database file as they are typically +// found on android. +var loadTzinfoFromTzdata func(file, name string) ([]byte, error) + +// loadTzinfo returns the time zone information of the time zone +// with the given name, from a given source. A source may be a +// timezone database directory, tzdata database file or an uncompressed +// zip file, containing the contents of such a directory. +func loadTzinfo(name string, source string) ([]byte, error) { + if len(source) >= 6 && source[len(source)-6:] == "tzdata" { + return loadTzinfoFromTzdata(source, name) + } + return loadTzinfoFromDirOrZip(source, name) +} + +// loadLocation returns the Location with the given name from one of +// the specified sources. See loadTzinfo for a list of supported sources. +// The first timezone data matching the given name that is successfully loaded +// and parsed is returned as a Location. +func loadLocation(name string, sources []string) (z *Location, firstErr error) { + for _, source := range sources { + var zoneData, err = loadTzinfo(name, source) + if err == nil { + if z, err = LoadLocationFromTZData(name, zoneData); err == nil { + return z, nil + } + } + if firstErr == nil && err != syscall.ENOENT { + firstErr = err + } + } + if loadFromEmbeddedTZData != nil { + zonedata, err := loadFromEmbeddedTZData(name) + if err == nil { + if z, err = LoadLocationFromTZData(name, []byte(zonedata)); err == nil { + return z, nil + } + } + if firstErr == nil && err != syscall.ENOENT { + firstErr = err + } + } + if firstErr != nil { + return nil, firstErr + } + return nil, errors.New("unknown time zone " + name) +} + +// readFile reads and returns the content of the named file. +// It is a trivial implementation of os.ReadFile, reimplemented +// here to avoid depending on io/ioutil or os. +// It returns an error if name exceeds maxFileSize bytes. +func readFile(name string) ([]byte, error) { + f, err := open(name) + if err != nil { + return nil, err + } + defer closefd(f) + var ( + buf [4096]byte + ret []byte + n int + ) + for { + n, err = read(f, buf[:]) + if n > 0 { + ret = append(ret, buf[:n]...) + } + if n == 0 || err != nil { + break + } + if len(ret) > maxFileSize { + return nil, fileSizeError(name) + } + } + return ret, err +} diff --git a/contrib/go/_std_1.18/src/time/zoneinfo_unix.go b/contrib/go/_std_1.18/src/time/zoneinfo_unix.go new file mode 100644 index 0000000000..23f8b3cdb4 --- /dev/null +++ b/contrib/go/_std_1.18/src/time/zoneinfo_unix.go @@ -0,0 +1,69 @@ +// Copyright 2009 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. + +//go:build aix || (darwin && !ios) || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || solaris + +// Parse "zoneinfo" time zone file. +// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others. +// See tzfile(5), https://en.wikipedia.org/wiki/Zoneinfo, +// and ftp://munnari.oz.au/pub/oldtz/ + +package time + +import ( + "runtime" + "syscall" +) + +// Many systems use /usr/share/zoneinfo, Solaris 2 has +// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ. +var zoneSources = []string{ + "/usr/share/zoneinfo/", + "/usr/share/lib/zoneinfo/", + "/usr/lib/locale/TZ/", + runtime.GOROOT() + "/lib/time/zoneinfo.zip", +} + +func initLocal() { + // consult $TZ to find the time zone to use. + // no $TZ means use the system default /etc/localtime. + // $TZ="" means use UTC. + // $TZ="foo" or $TZ=":foo" if foo is an absolute path, then the file pointed + // by foo will be used to initialize timezone; otherwise, file + // /usr/share/zoneinfo/foo will be used. + + tz, ok := syscall.Getenv("TZ") + switch { + case !ok: + z, err := loadLocation("localtime", []string{"/etc"}) + if err == nil { + localLoc = *z + localLoc.name = "Local" + return + } + case tz != "": + if tz[0] == ':' { + tz = tz[1:] + } + if tz != "" && tz[0] == '/' { + if z, err := loadLocation(tz, []string{""}); err == nil { + localLoc = *z + if tz == "/etc/localtime" { + localLoc.name = "Local" + } else { + localLoc.name = tz + } + return + } + } else if tz != "" && tz != "UTC" { + if z, err := loadLocation(tz, zoneSources); err == nil { + localLoc = *z + return + } + } + } + + // Fall back to UTC. + localLoc.name = "UTC" +} |