1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
9 // These are predefined layouts for use in Time.Format and time.Parse.
10 // The reference time used in the layouts is the specific time:
11 // Mon Jan 2 15:04:05 MST 2006
12 // which is Unix time 1136239445. Since MST is GMT-0700,
13 // the reference time can be thought of as
14 // 01/02 03:04:05PM '06 -0700
15 // To define your own format, write down what the reference time would look
16 // like formatted your way; see the values of constants like ANSIC,
17 // StampMicro or Kitchen for examples. The model is to demonstrate what the
18 // reference time looks like so that the Format and Parse methods can apply
19 // the same transformation to a general time value.
21 // Some valid layouts are invalid time values for time.Parse, due to formats
22 // such as _ for space padding and Z for zone information.
24 // Within the format string, an underscore _ represents a space that may be
25 // replaced by a digit if the following number (a day) has two digits; for
26 // compatibility with fixed-width Unix time formats.
28 // A decimal point followed by one or more zeros represents a fractional
29 // second, printed to the given number of decimal places. A decimal point
30 // followed by one or more nines represents a fractional second, printed to
31 // the given number of decimal places, with trailing zeros removed.
32 // When parsing (only), the input may contain a fractional second
33 // field immediately after the seconds field, even if the layout does not
34 // signify its presence. In that case a decimal point followed by a maximal
35 // series of digits is parsed as a fractional second.
37 // Numeric time zone offsets format as follows:
41 // Replacing the sign in the format with a Z triggers
42 // the ISO 8601 behavior of printing Z instead of an
43 // offset for the UTC zone. Thus:
48 // The recognized day of week formats are "Mon" and "Monday".
49 // The recognized month formats are "Jan" and "January".
51 // The formats 2, _2, and 02 are unpadded, space-padded, and zero-padded
52 // day of month. The formats __2 and 002 are space-padded and zero-padded
53 // three-character day of year; there is no unpadded day of year format.
55 // Text in the format string that is not recognized as part of the reference
56 // time is echoed verbatim during Format and expected to appear verbatim
57 // in the input to Parse.
59 // The executable example for Time.Format demonstrates the working
60 // of the layout string in detail and is a good reference.
62 // Note that the RFC822, RFC850, and RFC1123 formats should be applied
63 // only to local times. Applying them to UTC times will use "UTC" as the
64 // time zone abbreviation, while strictly speaking those RFCs require the
65 // use of "GMT" in that case.
66 // In general RFC1123Z should be used instead of RFC1123 for servers
67 // that insist on that format, and RFC3339 should be preferred for new protocols.
68 // RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
69 // when used with time.Parse they do not accept all the time formats
70 // permitted by the RFCs.
71 // The RFC3339Nano format removes trailing zeros from the seconds field
72 // and thus may not sort correctly once formatted.
74 ANSIC
= "Mon Jan _2 15:04:05 2006"
75 UnixDate
= "Mon Jan _2 15:04:05 MST 2006"
76 RubyDate
= "Mon Jan 02 15:04:05 -0700 2006"
77 RFC822
= "02 Jan 06 15:04 MST"
78 RFC822Z
= "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
79 RFC850
= "Monday, 02-Jan-06 15:04:05 MST"
80 RFC1123
= "Mon, 02 Jan 2006 15:04:05 MST"
81 RFC1123Z
= "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
82 RFC3339
= "2006-01-02T15:04:05Z07:00"
83 RFC3339Nano
= "2006-01-02T15:04:05.999999999Z07:00"
86 Stamp
= "Jan _2 15:04:05"
87 StampMilli
= "Jan _2 15:04:05.000"
88 StampMicro
= "Jan _2 15:04:05.000000"
89 StampNano
= "Jan _2 15:04:05.000000000"
94 stdLongMonth
= iota + stdNeedDate
// "January"
98 stdLongWeekDay
// "Monday"
103 stdUnderYearDay
// "__2"
104 stdZeroYearDay
// "002"
105 stdHour
= iota + stdNeedClock
// "15"
107 stdZeroHour12
// "03"
109 stdZeroMinute
// "04"
111 stdZeroSecond
// "05"
112 stdLongYear
= iota + stdNeedDate
// "2006"
114 stdPM
= iota + stdNeedClock
// "PM"
116 stdTZ
= iota // "MST"
117 stdISO8601TZ
// "Z0700" // prints Z for UTC
118 stdISO8601SecondsTZ
// "Z070000"
119 stdISO8601ShortTZ
// "Z07"
120 stdISO8601ColonTZ
// "Z07:00" // prints Z for UTC
121 stdISO8601ColonSecondsTZ
// "Z07:00:00"
122 stdNumTZ
// "-0700" // always numeric
123 stdNumSecondsTz
// "-070000"
124 stdNumShortTZ
// "-07" // always numeric
125 stdNumColonTZ
// "-07:00" // always numeric
126 stdNumColonSecondsTZ
// "-07:00:00"
127 stdFracSecond0
// ".0", ".00", ... , trailing zeros included
128 stdFracSecond9
// ".9", ".99", ..., trailing zeros omitted
130 stdNeedDate
= 1 << 8 // need month, day, year
131 stdNeedClock
= 2 << 8 // need hour, minute, second
132 stdArgShift
= 16 // extra argument in high bits, above low stdArgShift
133 stdMask
= 1<<stdArgShift
- 1 // mask out argument
136 // std0x records the std values for "01", "02", ..., "06".
137 var std0x
= [...]int{stdZeroMonth
, stdZeroDay
, stdZeroHour12
, stdZeroMinute
, stdZeroSecond
, stdYear
}
139 // startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
140 // Its purpose is to prevent matching strings like "Month" when looking for "Mon".
141 func startsWithLowerCase(str
string) bool {
146 return 'a' <= c
&& c
<= 'z'
149 // nextStdChunk finds the first occurrence of a std string in
150 // layout and returns the text before, the std string, and the text after.
151 func nextStdChunk(layout
string) (prefix
string, std
int, suffix
string) {
152 for i
:= 0; i
< len(layout
); i
++ {
153 switch c
:= int(layout
[i
]); c
{
154 case 'J': // January, Jan
155 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "Jan" {
156 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "January" {
157 return layout
[0:i
], stdLongMonth
, layout
[i
+7:]
159 if !startsWithLowerCase(layout
[i
+3:]) {
160 return layout
[0:i
], stdMonth
, layout
[i
+3:]
164 case 'M': // Monday, Mon, MST
165 if len(layout
) >= i
+3 {
166 if layout
[i
:i
+3] == "Mon" {
167 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Monday" {
168 return layout
[0:i
], stdLongWeekDay
, layout
[i
+6:]
170 if !startsWithLowerCase(layout
[i
+3:]) {
171 return layout
[0:i
], stdWeekDay
, layout
[i
+3:]
174 if layout
[i
:i
+3] == "MST" {
175 return layout
[0:i
], stdTZ
, layout
[i
+3:]
179 case '0': // 01, 02, 03, 04, 05, 06, 002
180 if len(layout
) >= i
+2 && '1' <= layout
[i
+1] && layout
[i
+1] <= '6' {
181 return layout
[0:i
], std0x
[layout
[i
+1]-'1'], layout
[i
+2:]
183 if len(layout
) >= i
+3 && layout
[i
+1] == '0' && layout
[i
+2] == '2' {
184 return layout
[0:i
], stdZeroYearDay
, layout
[i
+3:]
188 if len(layout
) >= i
+2 && layout
[i
+1] == '5' {
189 return layout
[0:i
], stdHour
, layout
[i
+2:]
191 return layout
[0:i
], stdNumMonth
, layout
[i
+1:]
194 if len(layout
) >= i
+4 && layout
[i
:i
+4] == "2006" {
195 return layout
[0:i
], stdLongYear
, layout
[i
+4:]
197 return layout
[0:i
], stdDay
, layout
[i
+1:]
199 case '_': // _2, _2006, __2
200 if len(layout
) >= i
+2 && layout
[i
+1] == '2' {
201 //_2006 is really a literal _, followed by stdLongYear
202 if len(layout
) >= i
+5 && layout
[i
+1:i
+5] == "2006" {
203 return layout
[0 : i
+1], stdLongYear
, layout
[i
+5:]
205 return layout
[0:i
], stdUnderDay
, layout
[i
+2:]
207 if len(layout
) >= i
+3 && layout
[i
+1] == '_' && layout
[i
+2] == '2' {
208 return layout
[0:i
], stdUnderYearDay
, layout
[i
+3:]
212 return layout
[0:i
], stdHour12
, layout
[i
+1:]
215 return layout
[0:i
], stdMinute
, layout
[i
+1:]
218 return layout
[0:i
], stdSecond
, layout
[i
+1:]
221 if len(layout
) >= i
+2 && layout
[i
+1] == 'M' {
222 return layout
[0:i
], stdPM
, layout
[i
+2:]
226 if len(layout
) >= i
+2 && layout
[i
+1] == 'm' {
227 return layout
[0:i
], stdpm
, layout
[i
+2:]
230 case '-': // -070000, -07:00:00, -0700, -07:00, -07
231 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "-070000" {
232 return layout
[0:i
], stdNumSecondsTz
, layout
[i
+7:]
234 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "-07:00:00" {
235 return layout
[0:i
], stdNumColonSecondsTZ
, layout
[i
+9:]
237 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "-0700" {
238 return layout
[0:i
], stdNumTZ
, layout
[i
+5:]
240 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "-07:00" {
241 return layout
[0:i
], stdNumColonTZ
, layout
[i
+6:]
243 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "-07" {
244 return layout
[0:i
], stdNumShortTZ
, layout
[i
+3:]
247 case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,
248 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "Z070000" {
249 return layout
[0:i
], stdISO8601SecondsTZ
, layout
[i
+7:]
251 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "Z07:00:00" {
252 return layout
[0:i
], stdISO8601ColonSecondsTZ
, layout
[i
+9:]
254 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "Z0700" {
255 return layout
[0:i
], stdISO8601TZ
, layout
[i
+5:]
257 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Z07:00" {
258 return layout
[0:i
], stdISO8601ColonTZ
, layout
[i
+6:]
260 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "Z07" {
261 return layout
[0:i
], stdISO8601ShortTZ
, layout
[i
+3:]
264 case '.': // .000 or .999 - repeated digits for fractional seconds.
265 if i
+1 < len(layout
) && (layout
[i
+1] == '0' || layout
[i
+1] == '9') {
268 for j
< len(layout
) && layout
[j
] == ch
{
271 // String of digits must end here - only fractional second is all digits.
272 if !isDigit(layout
, j
) {
273 std
:= stdFracSecond0
274 if layout
[i
+1] == '9' {
277 std |
= (j
- (i
+ 1)) << stdArgShift
278 return layout
[0:i
], std
, layout
[j
:]
286 var longDayNames
= []string{
296 var shortDayNames
= []string{
306 var shortMonthNames
= []string{
321 var longMonthNames
= []string{
336 // match reports whether s1 and s2 match ignoring case.
337 // It is assumed s1 and s2 are the same length.
338 func match(s1
, s2
string) bool {
339 for i
:= 0; i
< len(s1
); i
++ {
343 // Switch to lower-case; 'a'-'A' is known to be a single bit.
346 if c1
!= c2 || c1
< 'a' || c1
> 'z' {
354 func lookup(tab
[]string, val
string) (int, string, error
) {
355 for i
, v
:= range tab
{
356 if len(val
) >= len(v
) && match(val
[0:len(v
)], v
) {
357 return i
, val
[len(v
):], nil
360 return -1, val
, errBad
363 // appendInt appends the decimal form of x to b and returns the result.
364 // If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's.
365 // Duplicates functionality in strconv, but avoids dependency.
366 func appendInt(b
[]byte, x
int, width
int) []byte {
373 // Assemble decimal in reverse order.
379 buf
[i
] = byte('0' + u
- q
*10)
383 buf
[i
] = byte('0' + u
)
386 for w
:= len(buf
) - i
; w
< width
; w
++ {
390 return append(b
, buf
[i
:]...)
393 // Never printed, just needs to be non-nil for return by atoi.
394 var atoiError
= errors
.New("time: invalid number")
396 // Duplicates functionality in strconv, but avoids dependency.
397 func atoi(s
string) (x
int, err error
) {
399 if s
!= "" && (s
[0] == '-' || s
[0] == '+') {
403 q
, rem
, err
:= leadingInt(s
)
405 if err
!= nil || rem
!= "" {
414 // formatNano appends a fractional second, as nanoseconds, to b
415 // and returns the result.
416 func formatNano(b
[]byte, nanosec
uint, n
int, trim
bool) []byte {
419 for start
:= len(buf
); start
> 0; {
421 buf
[start
] = byte(u%10
+ '0')
429 for n
> 0 && buf
[n
-1] == '0' {
437 return append(b
, buf
[:n
]...)
440 // String returns the time formatted using the format string
441 // "2006-01-02 15:04:05.999999999 -0700 MST"
443 // If the time has a monotonic clock reading, the returned string
444 // includes a final field "m=±<value>", where value is the monotonic
445 // clock reading formatted as a decimal number of seconds.
447 // The returned string is meant for debugging; for a stable serialized
448 // representation, use t.MarshalText, t.MarshalBinary, or t.Format
449 // with an explicit format string.
450 func (t Time
) String() string {
451 s
:= t
.Format("2006-01-02 15:04:05.999999999 -0700 MST")
453 // Format monotonic clock reading as m=±ddd.nnnnnnnnn.
454 if t
.wall
&hasMonotonic
!= 0 {
461 m1
, m2
:= m2
/1e9
, m2%1e9
462 m0
, m1
:= m1
/1e9
, m1%1e9
464 buf
= append(buf
, " m="...)
465 buf
= append(buf
, sign
)
468 buf
= appendInt(buf
, int(m0
), 0)
471 buf
= appendInt(buf
, int(m1
), wid
)
472 buf
= append(buf
, '.')
473 buf
= appendInt(buf
, int(m2
), 9)
479 // Format returns a textual representation of the time value formatted
480 // according to layout, which defines the format by showing how the reference
481 // time, defined to be
482 // Mon Jan 2 15:04:05 -0700 MST 2006
483 // would be displayed if it were the value; it serves as an example of the
484 // desired output. The same display rules will then be applied to the time
487 // A fractional second is represented by adding a period and zeros
488 // to the end of the seconds section of layout string, as in "15:04:05.000"
489 // to format a time stamp with millisecond precision.
491 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
492 // and convenient representations of the reference time. For more information
493 // about the formats and the definition of the reference time, see the
494 // documentation for ANSIC and the other constants defined by this package.
495 func (t Time
) Format(layout
string) string {
498 max
:= len(layout
) + 10
500 var buf
[bufSize
]byte
503 b
= make([]byte, 0, max
)
505 b
= t
.AppendFormat(b
, layout
)
509 // AppendFormat is like Format but appends the textual
510 // representation to b and returns the extended buffer.
511 func (t Time
) AppendFormat(b
[]byte, layout
string) []byte {
513 name
, offset
, abs
= t
.locabs()
523 // Each iteration generates one std value.
525 prefix
, std
, suffix
:= nextStdChunk(layout
)
527 b
= append(b
, prefix
...)
534 // Compute year, month, day if needed.
535 if year
< 0 && std
&stdNeedDate
!= 0 {
536 year
, month
, day
, yday
= absDate(abs
, true)
540 // Compute hour, minute, second if needed.
541 if hour
< 0 && std
&stdNeedClock
!= 0 {
542 hour
, min
, sec
= absClock(abs
)
545 switch std
& stdMask
{
551 b
= appendInt(b
, y%100
, 2)
553 b
= appendInt(b
, year
, 4)
555 b
= append(b
, month
.String()[:3]...)
560 b
= appendInt(b
, int(month
), 0)
562 b
= appendInt(b
, int(month
), 2)
564 b
= append(b
, absWeekday(abs
).String()[:3]...)
566 s
:= absWeekday(abs
).String()
569 b
= appendInt(b
, day
, 0)
574 b
= appendInt(b
, day
, 0)
576 b
= appendInt(b
, day
, 2)
577 case stdUnderYearDay
:
584 b
= appendInt(b
, yday
, 0)
586 b
= appendInt(b
, yday
, 3)
588 b
= appendInt(b
, hour
, 2)
590 // Noon is 12PM, midnight is 12AM.
595 b
= appendInt(b
, hr
, 0)
597 // Noon is 12PM, midnight is 12AM.
602 b
= appendInt(b
, hr
, 2)
604 b
= appendInt(b
, min
, 0)
606 b
= appendInt(b
, min
, 2)
608 b
= appendInt(b
, sec
, 0)
610 b
= appendInt(b
, sec
, 2)
613 b
= append(b
, "PM"...)
615 b
= append(b
, "AM"...)
619 b
= append(b
, "pm"...)
621 b
= append(b
, "am"...)
623 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ShortTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumShortTZ
, stdNumColonSecondsTZ
:
624 // Ugly special case. We cheat and take the "Z" variants
625 // to mean "the time zone as formatted for ISO 8601".
626 if offset
== 0 && (std
== stdISO8601TZ || std
== stdISO8601ColonTZ || std
== stdISO8601SecondsTZ || std
== stdISO8601ShortTZ || std
== stdISO8601ColonSecondsTZ
) {
630 zone
:= offset
/ 60 // convert to minutes
635 absoffset
= -absoffset
639 b
= appendInt(b
, zone
/60, 2)
640 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ || std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
643 if std
!= stdNumShortTZ
&& std
!= stdISO8601ShortTZ
{
644 b
= appendInt(b
, zone%60
, 2)
647 // append seconds if appropriate
648 if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz || std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
649 if std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
652 b
= appendInt(b
, absoffset%60
, 2)
657 b
= append(b
, name
...)
660 // No time zone known for this time, but we must print one.
661 // Use the -0700 format.
662 zone
:= offset
/ 60 // convert to minutes
669 b
= appendInt(b
, zone
/60, 2)
670 b
= appendInt(b
, zone%60
, 2)
671 case stdFracSecond0
, stdFracSecond9
:
672 b
= formatNano(b
, uint(t
.Nanosecond()), std
>>stdArgShift
, std
&stdMask
== stdFracSecond9
)
678 var errBad
= errors
.New("bad value for field") // placeholder not passed to user
680 // ParseError describes a problem parsing a time string.
681 type ParseError
struct {
689 func quote(s
string) string {
690 return "\"" + s
+ "\""
693 // Error returns the string representation of a ParseError.
694 func (e
*ParseError
) Error() string {
696 return "parsing time " +
697 quote(e
.Value
) + " as " +
698 quote(e
.Layout
) + ": cannot parse " +
699 quote(e
.ValueElem
) + " as " +
702 return "parsing time " +
703 quote(e
.Value
) + e
.Message
706 // isDigit reports whether s[i] is in range and is a decimal digit.
707 func isDigit(s
string, i
int) bool {
712 return '0' <= c
&& c
<= '9'
715 // getnum parses s[0:1] or s[0:2] (fixed forces s[0:2])
716 // as a decimal integer and returns the integer and the
717 // remainder of the string.
718 func getnum(s
string, fixed
bool) (int, string, error
) {
726 return int(s
[0] - '0'), s
[1:], nil
728 return int(s
[0]-'0')*10 + int(s
[1]-'0'), s
[2:], nil
731 // getnum3 parses s[0:1], s[0:2], or s[0:3] (fixed forces s[0:3])
732 // as a decimal integer and returns the integer and the remainder
734 func getnum3(s
string, fixed
bool) (int, string, error
) {
736 for i
= 0; i
< 3 && isDigit(s
, i
); i
++ {
737 n
= n
*10 + int(s
[i
]-'0')
739 if i
== 0 || fixed
&& i
!= 3 {
745 func cutspace(s
string) string {
746 for len(s
) > 0 && s
[0] == ' ' {
752 // skip removes the given prefix from value,
753 // treating runs of space characters as equivalent.
754 func skip(value
, prefix
string) (string, error
) {
755 for len(prefix
) > 0 {
756 if prefix
[0] == ' ' {
757 if len(value
) > 0 && value
[0] != ' ' {
760 prefix
= cutspace(prefix
)
761 value
= cutspace(value
)
764 if len(value
) == 0 || value
[0] != prefix
[0] {
773 // Parse parses a formatted string and returns the time value it represents.
774 // The layout defines the format by showing how the reference time,
776 // Mon Jan 2 15:04:05 -0700 MST 2006
777 // would be interpreted if it were the value; it serves as an example of
778 // the input format. The same interpretation will then be made to the
781 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
782 // and convenient representations of the reference time. For more information
783 // about the formats and the definition of the reference time, see the
784 // documentation for ANSIC and the other constants defined by this package.
785 // Also, the executable example for Time.Format demonstrates the working
786 // of the layout string in detail and is a good reference.
788 // Elements omitted from the value are assumed to be zero or, when
789 // zero is impossible, one, so parsing "3:04pm" returns the time
790 // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is
791 // 0, this time is before the zero Time).
792 // Years must be in the range 0000..9999. The day of the week is checked
793 // for syntax but it is otherwise ignored.
795 // In the absence of a time zone indicator, Parse returns a time in UTC.
797 // When parsing a time with a zone offset like -0700, if the offset corresponds
798 // to a time zone used by the current location (Local), then Parse uses that
799 // location and zone in the returned time. Otherwise it records the time as
800 // being in a fabricated location with time fixed at the given zone offset.
802 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation
803 // has a defined offset in the current location, then that offset is used.
804 // The zone abbreviation "UTC" is recognized as UTC regardless of location.
805 // If the zone abbreviation is unknown, Parse records the time as being
806 // in a fabricated location with the given zone abbreviation and a zero offset.
807 // This choice means that such a time can be parsed and reformatted with the
808 // same layout losslessly, but the exact instant used in the representation will
809 // differ by the actual zone offset. To avoid such problems, prefer time layouts
810 // that use a numeric zone offset, or use ParseInLocation.
811 func Parse(layout
, value
string) (Time
, error
) {
812 return parse(layout
, value
, UTC
, Local
)
815 // ParseInLocation is like Parse but differs in two important ways.
816 // First, in the absence of time zone information, Parse interprets a time as UTC;
817 // ParseInLocation interprets the time as in the given location.
818 // Second, when given a zone offset or abbreviation, Parse tries to match it
819 // against the Local location; ParseInLocation uses the given location.
820 func ParseInLocation(layout
, value
string, loc
*Location
) (Time
, error
) {
821 return parse(layout
, value
, loc
, loc
)
824 func parse(layout
, value
string, defaultLocation
, local
*Location
) (Time
, error
) {
825 alayout
, avalue
:= layout
, value
826 rangeErrString
:= "" // set if a value is out of range
827 amSet
:= false // do we need to subtract 12 from the hour for midnight?
828 pmSet
:= false // do we need to add 12 to the hour?
830 // Time being constructed.
845 // Each iteration processes one std value.
848 prefix
, std
, suffix
:= nextStdChunk(layout
)
849 stdstr
:= layout
[len(prefix
) : len(layout
)-len(suffix
)]
850 value
, err
= skip(value
, prefix
)
852 return Time
{}, &ParseError
{alayout
, avalue
, prefix
, value
, ""}
856 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": extra text: " + value
}
862 switch std
& stdMask
{
869 p
, value
= value
[0:2], value
[2:]
873 } else if year
>= 69 { // Unix time starts Dec 31 1969 in some time zones
879 if len(value
) < 4 ||
!isDigit(value
, 0) {
883 p
, value
= value
[0:4], value
[4:]
886 month
, value
, err
= lookup(shortMonthNames
, value
)
889 month
, value
, err
= lookup(longMonthNames
, value
)
891 case stdNumMonth
, stdZeroMonth
:
892 month
, value
, err
= getnum(value
, std
== stdZeroMonth
)
893 if err
== nil && (month
<= 0 ||
12 < month
) {
894 rangeErrString
= "month"
897 // Ignore weekday except for error checking.
898 _
, value
, err
= lookup(shortDayNames
, value
)
900 _
, value
, err
= lookup(longDayNames
, value
)
901 case stdDay
, stdUnderDay
, stdZeroDay
:
902 if std
== stdUnderDay
&& len(value
) > 0 && value
[0] == ' ' {
905 day
, value
, err
= getnum(value
, std
== stdZeroDay
)
906 // Note that we allow any one- or two-digit day here.
907 // The month, day, year combination is validated after we've completed parsing.
908 case stdUnderYearDay
, stdZeroYearDay
:
909 for i
:= 0; i
< 2; i
++ {
910 if std
== stdUnderYearDay
&& len(value
) > 0 && value
[0] == ' ' {
914 yday
, value
, err
= getnum3(value
, std
== stdZeroYearDay
)
915 // Note that we allow any one-, two-, or three-digit year-day here.
916 // The year-day, year combination is validated after we've completed parsing.
918 hour
, value
, err
= getnum(value
, false)
919 if hour
< 0 ||
24 <= hour
{
920 rangeErrString
= "hour"
922 case stdHour12
, stdZeroHour12
:
923 hour
, value
, err
= getnum(value
, std
== stdZeroHour12
)
924 if hour
< 0 ||
12 < hour
{
925 rangeErrString
= "hour"
927 case stdMinute
, stdZeroMinute
:
928 min
, value
, err
= getnum(value
, std
== stdZeroMinute
)
929 if min
< 0 ||
60 <= min
{
930 rangeErrString
= "minute"
932 case stdSecond
, stdZeroSecond
:
933 sec
, value
, err
= getnum(value
, std
== stdZeroSecond
)
934 if sec
< 0 ||
60 <= sec
{
935 rangeErrString
= "second"
938 // Special case: do we have a fractional second but no
939 // fractional second in the format?
940 if len(value
) >= 2 && value
[0] == '.' && isDigit(value
, 1) {
941 _
, std
, _
= nextStdChunk(layout
)
943 if std
== stdFracSecond0 || std
== stdFracSecond9
{
944 // Fractional second in the layout; proceed normally
947 // No fractional second in the layout but we have one in the input.
949 for ; n
< len(value
) && isDigit(value
, n
); n
++ {
951 nsec
, rangeErrString
, err
= parseNanoseconds(value
, n
)
959 p
, value
= value
[0:2], value
[2:]
973 p
, value
= value
[0:2], value
[2:]
982 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ShortTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumShortTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumColonSecondsTZ
:
983 if (std
== stdISO8601TZ || std
== stdISO8601ShortTZ || std
== stdISO8601ColonTZ
) && len(value
) >= 1 && value
[0] == 'Z' {
988 var sign
, hour
, min
, seconds
string
989 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ
{
998 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], "00", value
[6:]
999 } else if std
== stdNumShortTZ || std
== stdISO8601ShortTZ
{
1004 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], "00", "00", value
[3:]
1005 } else if std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
1010 if value
[3] != ':' || value
[6] != ':' {
1014 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], value
[7:9], value
[9:]
1015 } else if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz
{
1020 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], value
[5:7], value
[7:]
1026 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], "00", value
[5:]
1029 hr
, err
= atoi(hour
)
1034 ss
, err
= atoi(seconds
)
1036 zoneOffset
= (hr
*60+mm
)*60 + ss
// offset is in seconds
1040 zoneOffset
= -zoneOffset
1045 // Does it look like a time zone?
1046 if len(value
) >= 3 && value
[0:3] == "UTC" {
1051 n
, ok
:= parseTimeZone(value
)
1056 zoneName
, value
= value
[:n
], value
[n
:]
1058 case stdFracSecond0
:
1059 // stdFracSecond0 requires the exact number of digits as specified in
1061 ndigit
:= 1 + (std
>> stdArgShift
)
1062 if len(value
) < ndigit
{
1066 nsec
, rangeErrString
, err
= parseNanoseconds(value
, ndigit
)
1067 value
= value
[ndigit
:]
1069 case stdFracSecond9
:
1070 if len(value
) < 2 || value
[0] != '.' || value
[1] < '0' ||
'9' < value
[1] {
1071 // Fractional second omitted.
1074 // Take any number of digits, even more than asked for,
1075 // because it is what the stdSecond case would do.
1077 for i
< 9 && i
+1 < len(value
) && '0' <= value
[i
+1] && value
[i
+1] <= '9' {
1080 nsec
, rangeErrString
, err
= parseNanoseconds(value
, 1+i
)
1083 if rangeErrString
!= "" {
1084 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ": " + rangeErrString
+ " out of range"}
1087 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ""}
1090 if pmSet
&& hour
< 12 {
1092 } else if amSet
&& hour
== 12 {
1096 // Convert yday to day, month.
1104 } else if yday
> 31+29 {
1108 if yday
< 1 || yday
> 365 {
1109 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": day-of-year out of range"}
1113 if int(daysBefore
[m
]) < yday
{
1116 d
= yday
- int(daysBefore
[m
-1])
1118 // If month, day already seen, yday's m, d must match.
1119 // Otherwise, set them from m, d.
1120 if month
>= 0 && month
!= m
{
1121 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": day-of-year does not match month"}
1124 if day
>= 0 && day
!= d
{
1125 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": day-of-year does not match day"}
1130 month
= int(January
)
1137 // Validate the day of the month.
1138 if day
< 1 || day
> daysIn(Month(month
), year
) {
1139 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": day out of range"}
1143 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, z
), nil
1146 if zoneOffset
!= -1 {
1147 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
1148 t
.addSec(-int64(zoneOffset
))
1150 // Look for local zone with the given offset.
1151 // If that zone was in effect at the given time, use it.
1152 name
, offset
, _
, _
:= local
.lookup(t
.unixSec())
1153 if offset
== zoneOffset
&& (zoneName
== "" || name
== zoneName
) {
1158 // Otherwise create fake zone to record offset.
1159 t
.setLoc(FixedZone(zoneName
, zoneOffset
))
1164 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
1165 // Look for local zone with the given offset.
1166 // If that zone was in effect at the given time, use it.
1167 offset
, ok
:= local
.lookupName(zoneName
, t
.unixSec())
1169 t
.addSec(-int64(offset
))
1174 // Otherwise, create fake zone with unknown offset.
1175 if len(zoneName
) > 3 && zoneName
[:3] == "GMT" {
1176 offset
, _
= atoi(zoneName
[3:]) // Guaranteed OK by parseGMT.
1179 t
.setLoc(FixedZone(zoneName
, offset
))
1183 // Otherwise, fall back to default.
1184 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, defaultLocation
), nil
1187 // parseTimeZone parses a time zone string and returns its length. Time zones
1188 // are human-generated and unpredictable. We can't do precise error checking.
1189 // On the other hand, for a correct parse there must be a time zone at the
1190 // beginning of the string, so it's almost always true that there's one
1191 // there. We look at the beginning of the string for a run of upper-case letters.
1192 // If there are more than 5, it's an error.
1193 // If there are 4 or 5 and the last is a T, it's a time zone.
1194 // If there are 3, it's a time zone.
1195 // Otherwise, other than special cases, it's not a time zone.
1196 // GMT is special because it can have an hour offset.
1197 func parseTimeZone(value
string) (length
int, ok
bool) {
1201 // Special case 1: ChST and MeST are the only zones with a lower-case letter.
1202 if len(value
) >= 4 && (value
[:4] == "ChST" || value
[:4] == "MeST") {
1205 // Special case 2: GMT may have an hour offset; treat it specially.
1206 if value
[:3] == "GMT" {
1207 length
= parseGMT(value
)
1210 // Special Case 3: Some time zones are not named, but have +/-00 format
1211 if value
[0] == '+' || value
[0] == '-' {
1212 length
= parseSignedOffset(value
)
1213 ok
:= length
> 0 // parseSignedOffset returns 0 in case of bad input
1216 // How many upper-case letters are there? Need at least three, at most five.
1218 for nUpper
= 0; nUpper
< 6; nUpper
++ {
1219 if nUpper
>= len(value
) {
1222 if c
:= value
[nUpper
]; c
< 'A' ||
'Z' < c
{
1229 case 5: // Must end in T to match.
1230 if value
[4] == 'T' {
1234 // Must end in T, except one special case.
1235 if value
[3] == 'T' || value
[:4] == "WITA" {
1244 // parseGMT parses a GMT time zone. The input string is known to start "GMT".
1245 // The function checks whether that is followed by a sign and a number in the
1246 // range -23 through +23 excluding zero.
1247 func parseGMT(value
string) int {
1249 if len(value
) == 0 {
1253 return 3 + parseSignedOffset(value
)
1256 // parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04").
1257 // The function checks for a signed number in the range -23 through +23 excluding zero.
1258 // Returns length of the found offset string or 0 otherwise
1259 func parseSignedOffset(value
string) int {
1261 if sign
!= '-' && sign
!= '+' {
1264 x
, rem
, err
:= leadingInt(value
[1:])
1266 // fail if nothing consumed by leadingInt
1267 if err
!= nil || value
[1:] == rem
{
1273 if x
< -23 ||
23 < x
{
1276 return len(value
) - len(rem
)
1279 func parseNanoseconds(value
string, nbytes
int) (ns
int, rangeErrString
string, err error
) {
1280 if value
[0] != '.' {
1284 if ns
, err
= atoi(value
[1:nbytes
]); err
!= nil {
1287 if ns
< 0 ||
1e9
<= ns
{
1288 rangeErrString
= "fractional second"
1291 // We need nanoseconds, which means scaling by the number
1292 // of missing digits in the format, maximum length 10. If it's
1293 // longer than 10, we won't scale.
1294 scaleDigits
:= 10 - nbytes
1295 for i
:= 0; i
< scaleDigits
; i
++ {
1301 var errLeadingInt
= errors
.New("time: bad [0-9]*") // never printed
1303 // leadingInt consumes the leading [0-9]* from s.
1304 func leadingInt(s
string) (x
int64, rem
string, err error
) {
1306 for ; i
< len(s
); i
++ {
1308 if c
< '0' || c
> '9' {
1311 if x
> (1<<63-1)/10 {
1313 return 0, "", errLeadingInt
1315 x
= x
*10 + int64(c
) - '0'
1318 return 0, "", errLeadingInt
1321 return x
, s
[i
:], nil
1324 // leadingFraction consumes the leading [0-9]* from s.
1325 // It is used only for fractions, so does not return an error on overflow,
1326 // it just stops accumulating precision.
1327 func leadingFraction(s
string) (x
int64, scale
float64, rem
string) {
1331 for ; i
< len(s
); i
++ {
1333 if c
< '0' || c
> '9' {
1339 if x
> (1<<63-1)/10 {
1340 // It's possible for overflow to give a positive number, so take care.
1344 y
:= x
*10 + int64(c
) - '0'
1352 return x
, scale
, s
[i
:]
1355 var unitMap
= map[string]int64{
1356 "ns": int64(Nanosecond
),
1357 "us": int64(Microsecond
),
1358 "µs": int64(Microsecond
), // U+00B5 = micro symbol
1359 "μs": int64(Microsecond
), // U+03BC = Greek letter mu
1360 "ms": int64(Millisecond
),
1366 // ParseDuration parses a duration string.
1367 // A duration string is a possibly signed sequence of
1368 // decimal numbers, each with optional fraction and a unit suffix,
1369 // such as "300ms", "-1.5h" or "2h45m".
1370 // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
1371 func ParseDuration(s
string) (Duration
, error
) {
1372 // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
1380 if c
== '-' || c
== '+' {
1385 // Special case: if all that is left is "0", this is zero.
1390 return 0, errors
.New("time: invalid duration " + orig
)
1394 v
, f
int64 // integers before, after decimal point
1395 scale
float64 = 1 // value = v + f/scale
1400 // The next character must be [0-9.]
1401 if !(s
[0] == '.' ||
'0' <= s
[0] && s
[0] <= '9') {
1402 return 0, errors
.New("time: invalid duration " + orig
)
1406 v
, s
, err
= leadingInt(s
)
1408 return 0, errors
.New("time: invalid duration " + orig
)
1410 pre
:= pl
!= len(s
) // whether we consumed anything before a period
1412 // Consume (\.[0-9]*)?
1414 if s
!= "" && s
[0] == '.' {
1417 f
, scale
, s
= leadingFraction(s
)
1421 // no digits (e.g. ".s" or "-.s")
1422 return 0, errors
.New("time: invalid duration " + orig
)
1427 for ; i
< len(s
); i
++ {
1429 if c
== '.' ||
'0' <= c
&& c
<= '9' {
1434 return 0, errors
.New("time: missing unit in duration " + orig
)
1438 unit
, ok
:= unitMap
[u
]
1440 return 0, errors
.New("time: unknown unit " + u
+ " in duration " + orig
)
1442 if v
> (1<<63-1)/unit
{
1444 return 0, errors
.New("time: invalid duration " + orig
)
1448 // float64 is needed to be nanosecond accurate for fractions of hours.
1449 // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
1450 v
+= int64(float64(f
) * (float64(unit
) / scale
))
1453 return 0, errors
.New("time: invalid duration " + orig
)
1459 return 0, errors
.New("time: invalid duration " + orig
)
1466 return Duration(d
), nil