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 // Text in the format string that is not recognized as part of the reference
52 // time is echoed verbatim during Format and expected to appear verbatim
53 // in the input to Parse.
55 // The executable example for Time.Format demonstrates the working
56 // of the layout string in detail and is a good reference.
58 // Note that the RFC822, RFC850, and RFC1123 formats should be applied
59 // only to local times. Applying them to UTC times will use "UTC" as the
60 // time zone abbreviation, while strictly speaking those RFCs require the
61 // use of "GMT" in that case.
62 // In general RFC1123Z should be used instead of RFC1123 for servers
63 // that insist on that format, and RFC3339 should be preferred for new protocols.
64 // RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
65 // when used with time.Parse they do not accept all the time formats
66 // permitted by the RFCs.
67 // The RFC3339Nano format removes trailing zeros from the seconds field
68 // and thus may not sort correctly once formatted.
70 ANSIC
= "Mon Jan _2 15:04:05 2006"
71 UnixDate
= "Mon Jan _2 15:04:05 MST 2006"
72 RubyDate
= "Mon Jan 02 15:04:05 -0700 2006"
73 RFC822
= "02 Jan 06 15:04 MST"
74 RFC822Z
= "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
75 RFC850
= "Monday, 02-Jan-06 15:04:05 MST"
76 RFC1123
= "Mon, 02 Jan 2006 15:04:05 MST"
77 RFC1123Z
= "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
78 RFC3339
= "2006-01-02T15:04:05Z07:00"
79 RFC3339Nano
= "2006-01-02T15:04:05.999999999Z07:00"
82 Stamp
= "Jan _2 15:04:05"
83 StampMilli
= "Jan _2 15:04:05.000"
84 StampMicro
= "Jan _2 15:04:05.000000"
85 StampNano
= "Jan _2 15:04:05.000000000"
90 stdLongMonth
= iota + stdNeedDate
// "January"
94 stdLongWeekDay
// "Monday"
99 stdHour
= iota + stdNeedClock
// "15"
101 stdZeroHour12
// "03"
103 stdZeroMinute
// "04"
105 stdZeroSecond
// "05"
106 stdLongYear
= iota + stdNeedDate
// "2006"
108 stdPM
= iota + stdNeedClock
// "PM"
110 stdTZ
= iota // "MST"
111 stdISO8601TZ
// "Z0700" // prints Z for UTC
112 stdISO8601SecondsTZ
// "Z070000"
113 stdISO8601ShortTZ
// "Z07"
114 stdISO8601ColonTZ
// "Z07:00" // prints Z for UTC
115 stdISO8601ColonSecondsTZ
// "Z07:00:00"
116 stdNumTZ
// "-0700" // always numeric
117 stdNumSecondsTz
// "-070000"
118 stdNumShortTZ
// "-07" // always numeric
119 stdNumColonTZ
// "-07:00" // always numeric
120 stdNumColonSecondsTZ
// "-07:00:00"
121 stdFracSecond0
// ".0", ".00", ... , trailing zeros included
122 stdFracSecond9
// ".9", ".99", ..., trailing zeros omitted
124 stdNeedDate
= 1 << 8 // need month, day, year
125 stdNeedClock
= 2 << 8 // need hour, minute, second
126 stdArgShift
= 16 // extra argument in high bits, above low stdArgShift
127 stdMask
= 1<<stdArgShift
- 1 // mask out argument
130 // std0x records the std values for "01", "02", ..., "06".
131 var std0x
= [...]int{stdZeroMonth
, stdZeroDay
, stdZeroHour12
, stdZeroMinute
, stdZeroSecond
, stdYear
}
133 // startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
134 // Its purpose is to prevent matching strings like "Month" when looking for "Mon".
135 func startsWithLowerCase(str
string) bool {
140 return 'a' <= c
&& c
<= 'z'
143 // nextStdChunk finds the first occurrence of a std string in
144 // layout and returns the text before, the std string, and the text after.
145 func nextStdChunk(layout
string) (prefix
string, std
int, suffix
string) {
146 for i
:= 0; i
< len(layout
); i
++ {
147 switch c
:= int(layout
[i
]); c
{
148 case 'J': // January, Jan
149 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "Jan" {
150 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "January" {
151 return layout
[0:i
], stdLongMonth
, layout
[i
+7:]
153 if !startsWithLowerCase(layout
[i
+3:]) {
154 return layout
[0:i
], stdMonth
, layout
[i
+3:]
158 case 'M': // Monday, Mon, MST
159 if len(layout
) >= i
+3 {
160 if layout
[i
:i
+3] == "Mon" {
161 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Monday" {
162 return layout
[0:i
], stdLongWeekDay
, layout
[i
+6:]
164 if !startsWithLowerCase(layout
[i
+3:]) {
165 return layout
[0:i
], stdWeekDay
, layout
[i
+3:]
168 if layout
[i
:i
+3] == "MST" {
169 return layout
[0:i
], stdTZ
, layout
[i
+3:]
173 case '0': // 01, 02, 03, 04, 05, 06
174 if len(layout
) >= i
+2 && '1' <= layout
[i
+1] && layout
[i
+1] <= '6' {
175 return layout
[0:i
], std0x
[layout
[i
+1]-'1'], layout
[i
+2:]
179 if len(layout
) >= i
+2 && layout
[i
+1] == '5' {
180 return layout
[0:i
], stdHour
, layout
[i
+2:]
182 return layout
[0:i
], stdNumMonth
, layout
[i
+1:]
185 if len(layout
) >= i
+4 && layout
[i
:i
+4] == "2006" {
186 return layout
[0:i
], stdLongYear
, layout
[i
+4:]
188 return layout
[0:i
], stdDay
, layout
[i
+1:]
190 case '_': // _2, _2006
191 if len(layout
) >= i
+2 && layout
[i
+1] == '2' {
192 //_2006 is really a literal _, followed by stdLongYear
193 if len(layout
) >= i
+5 && layout
[i
+1:i
+5] == "2006" {
194 return layout
[0 : i
+1], stdLongYear
, layout
[i
+5:]
196 return layout
[0:i
], stdUnderDay
, layout
[i
+2:]
200 return layout
[0:i
], stdHour12
, layout
[i
+1:]
203 return layout
[0:i
], stdMinute
, layout
[i
+1:]
206 return layout
[0:i
], stdSecond
, layout
[i
+1:]
209 if len(layout
) >= i
+2 && layout
[i
+1] == 'M' {
210 return layout
[0:i
], stdPM
, layout
[i
+2:]
214 if len(layout
) >= i
+2 && layout
[i
+1] == 'm' {
215 return layout
[0:i
], stdpm
, layout
[i
+2:]
218 case '-': // -070000, -07:00:00, -0700, -07:00, -07
219 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "-070000" {
220 return layout
[0:i
], stdNumSecondsTz
, layout
[i
+7:]
222 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "-07:00:00" {
223 return layout
[0:i
], stdNumColonSecondsTZ
, layout
[i
+9:]
225 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "-0700" {
226 return layout
[0:i
], stdNumTZ
, layout
[i
+5:]
228 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "-07:00" {
229 return layout
[0:i
], stdNumColonTZ
, layout
[i
+6:]
231 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "-07" {
232 return layout
[0:i
], stdNumShortTZ
, layout
[i
+3:]
235 case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,
236 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "Z070000" {
237 return layout
[0:i
], stdISO8601SecondsTZ
, layout
[i
+7:]
239 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "Z07:00:00" {
240 return layout
[0:i
], stdISO8601ColonSecondsTZ
, layout
[i
+9:]
242 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "Z0700" {
243 return layout
[0:i
], stdISO8601TZ
, layout
[i
+5:]
245 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Z07:00" {
246 return layout
[0:i
], stdISO8601ColonTZ
, layout
[i
+6:]
248 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "Z07" {
249 return layout
[0:i
], stdISO8601ShortTZ
, layout
[i
+3:]
252 case '.': // .000 or .999 - repeated digits for fractional seconds.
253 if i
+1 < len(layout
) && (layout
[i
+1] == '0' || layout
[i
+1] == '9') {
256 for j
< len(layout
) && layout
[j
] == ch
{
259 // String of digits must end here - only fractional second is all digits.
260 if !isDigit(layout
, j
) {
261 std
:= stdFracSecond0
262 if layout
[i
+1] == '9' {
265 std |
= (j
- (i
+ 1)) << stdArgShift
266 return layout
[0:i
], std
, layout
[j
:]
274 var longDayNames
= []string{
284 var shortDayNames
= []string{
294 var shortMonthNames
= []string{
309 var longMonthNames
= []string{
324 // match reports whether s1 and s2 match ignoring case.
325 // It is assumed s1 and s2 are the same length.
326 func match(s1
, s2
string) bool {
327 for i
:= 0; i
< len(s1
); i
++ {
331 // Switch to lower-case; 'a'-'A' is known to be a single bit.
334 if c1
!= c2 || c1
< 'a' || c1
> 'z' {
342 func lookup(tab
[]string, val
string) (int, string, error
) {
343 for i
, v
:= range tab
{
344 if len(val
) >= len(v
) && match(val
[0:len(v
)], v
) {
345 return i
, val
[len(v
):], nil
348 return -1, val
, errBad
351 // appendInt appends the decimal form of x to b and returns the result.
352 // If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's.
353 // Duplicates functionality in strconv, but avoids dependency.
354 func appendInt(b
[]byte, x
int, width
int) []byte {
361 // Assemble decimal in reverse order.
367 buf
[i
] = byte('0' + u
- q
*10)
371 buf
[i
] = byte('0' + u
)
374 for w
:= len(buf
) - i
; w
< width
; w
++ {
378 return append(b
, buf
[i
:]...)
381 // Never printed, just needs to be non-nil for return by atoi.
382 var atoiError
= errors
.New("time: invalid number")
384 // Duplicates functionality in strconv, but avoids dependency.
385 func atoi(s
string) (x
int, err error
) {
387 if s
!= "" && (s
[0] == '-' || s
[0] == '+') {
391 q
, rem
, err
:= leadingInt(s
)
393 if err
!= nil || rem
!= "" {
402 // formatNano appends a fractional second, as nanoseconds, to b
403 // and returns the result.
404 func formatNano(b
[]byte, nanosec
uint, n
int, trim
bool) []byte {
407 for start
:= len(buf
); start
> 0; {
409 buf
[start
] = byte(u%10
+ '0')
417 for n
> 0 && buf
[n
-1] == '0' {
425 return append(b
, buf
[:n
]...)
428 // String returns the time formatted using the format string
429 // "2006-01-02 15:04:05.999999999 -0700 MST"
431 // If the time has a monotonic clock reading, the returned string
432 // includes a final field "m=±<value>", where value is the monotonic
433 // clock reading formatted as a decimal number of seconds.
435 // The returned string is meant for debugging; for a stable serialized
436 // representation, use t.MarshalText, t.MarshalBinary, or t.Format
437 // with an explicit format string.
438 func (t Time
) String() string {
439 s
:= t
.Format("2006-01-02 15:04:05.999999999 -0700 MST")
441 // Format monotonic clock reading as m=±ddd.nnnnnnnnn.
442 if t
.wall
&hasMonotonic
!= 0 {
449 m1
, m2
:= m2
/1e9
, m2%1e9
450 m0
, m1
:= m1
/1e9
, m1%1e9
452 buf
= append(buf
, " m="...)
453 buf
= append(buf
, sign
)
456 buf
= appendInt(buf
, int(m0
), 0)
459 buf
= appendInt(buf
, int(m1
), wid
)
460 buf
= append(buf
, '.')
461 buf
= appendInt(buf
, int(m2
), 9)
467 // Format returns a textual representation of the time value formatted
468 // according to layout, which defines the format by showing how the reference
469 // time, defined to be
470 // Mon Jan 2 15:04:05 -0700 MST 2006
471 // would be displayed if it were the value; it serves as an example of the
472 // desired output. The same display rules will then be applied to the time
475 // A fractional second is represented by adding a period and zeros
476 // to the end of the seconds section of layout string, as in "15:04:05.000"
477 // to format a time stamp with millisecond precision.
479 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
480 // and convenient representations of the reference time. For more information
481 // about the formats and the definition of the reference time, see the
482 // documentation for ANSIC and the other constants defined by this package.
483 func (t Time
) Format(layout
string) string {
486 max
:= len(layout
) + 10
488 var buf
[bufSize
]byte
491 b
= make([]byte, 0, max
)
493 b
= t
.AppendFormat(b
, layout
)
497 // AppendFormat is like Format but appends the textual
498 // representation to b and returns the extended buffer.
499 func (t Time
) AppendFormat(b
[]byte, layout
string) []byte {
501 name
, offset
, abs
= t
.locabs()
510 // Each iteration generates one std value.
512 prefix
, std
, suffix
:= nextStdChunk(layout
)
514 b
= append(b
, prefix
...)
521 // Compute year, month, day if needed.
522 if year
< 0 && std
&stdNeedDate
!= 0 {
523 year
, month
, day
, _
= absDate(abs
, true)
526 // Compute hour, minute, second if needed.
527 if hour
< 0 && std
&stdNeedClock
!= 0 {
528 hour
, min
, sec
= absClock(abs
)
531 switch std
& stdMask
{
537 b
= appendInt(b
, y%100
, 2)
539 b
= appendInt(b
, year
, 4)
541 b
= append(b
, month
.String()[:3]...)
546 b
= appendInt(b
, int(month
), 0)
548 b
= appendInt(b
, int(month
), 2)
550 b
= append(b
, absWeekday(abs
).String()[:3]...)
552 s
:= absWeekday(abs
).String()
555 b
= appendInt(b
, day
, 0)
560 b
= appendInt(b
, day
, 0)
562 b
= appendInt(b
, day
, 2)
564 b
= appendInt(b
, hour
, 2)
566 // Noon is 12PM, midnight is 12AM.
571 b
= appendInt(b
, hr
, 0)
573 // Noon is 12PM, midnight is 12AM.
578 b
= appendInt(b
, hr
, 2)
580 b
= appendInt(b
, min
, 0)
582 b
= appendInt(b
, min
, 2)
584 b
= appendInt(b
, sec
, 0)
586 b
= appendInt(b
, sec
, 2)
589 b
= append(b
, "PM"...)
591 b
= append(b
, "AM"...)
595 b
= append(b
, "pm"...)
597 b
= append(b
, "am"...)
599 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ShortTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumShortTZ
, stdNumColonSecondsTZ
:
600 // Ugly special case. We cheat and take the "Z" variants
601 // to mean "the time zone as formatted for ISO 8601".
602 if offset
== 0 && (std
== stdISO8601TZ || std
== stdISO8601ColonTZ || std
== stdISO8601SecondsTZ || std
== stdISO8601ShortTZ || std
== stdISO8601ColonSecondsTZ
) {
606 zone
:= offset
/ 60 // convert to minutes
611 absoffset
= -absoffset
615 b
= appendInt(b
, zone
/60, 2)
616 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ || std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
619 if std
!= stdNumShortTZ
&& std
!= stdISO8601ShortTZ
{
620 b
= appendInt(b
, zone%60
, 2)
623 // append seconds if appropriate
624 if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz || std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
625 if std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
628 b
= appendInt(b
, absoffset%60
, 2)
633 b
= append(b
, name
...)
636 // No time zone known for this time, but we must print one.
637 // Use the -0700 format.
638 zone
:= offset
/ 60 // convert to minutes
645 b
= appendInt(b
, zone
/60, 2)
646 b
= appendInt(b
, zone%60
, 2)
647 case stdFracSecond0
, stdFracSecond9
:
648 b
= formatNano(b
, uint(t
.Nanosecond()), std
>>stdArgShift
, std
&stdMask
== stdFracSecond9
)
654 var errBad
= errors
.New("bad value for field") // placeholder not passed to user
656 // ParseError describes a problem parsing a time string.
657 type ParseError
struct {
665 func quote(s
string) string {
666 return "\"" + s
+ "\""
669 // Error returns the string representation of a ParseError.
670 func (e
*ParseError
) Error() string {
672 return "parsing time " +
673 quote(e
.Value
) + " as " +
674 quote(e
.Layout
) + ": cannot parse " +
675 quote(e
.ValueElem
) + " as " +
678 return "parsing time " +
679 quote(e
.Value
) + e
.Message
682 // isDigit reports whether s[i] is in range and is a decimal digit.
683 func isDigit(s
string, i
int) bool {
688 return '0' <= c
&& c
<= '9'
691 // getnum parses s[0:1] or s[0:2] (fixed forces the latter)
692 // as a decimal integer and returns the integer and the
693 // remainder of the string.
694 func getnum(s
string, fixed
bool) (int, string, error
) {
702 return int(s
[0] - '0'), s
[1:], nil
704 return int(s
[0]-'0')*10 + int(s
[1]-'0'), s
[2:], nil
707 func cutspace(s
string) string {
708 for len(s
) > 0 && s
[0] == ' ' {
714 // skip removes the given prefix from value,
715 // treating runs of space characters as equivalent.
716 func skip(value
, prefix
string) (string, error
) {
717 for len(prefix
) > 0 {
718 if prefix
[0] == ' ' {
719 if len(value
) > 0 && value
[0] != ' ' {
722 prefix
= cutspace(prefix
)
723 value
= cutspace(value
)
726 if len(value
) == 0 || value
[0] != prefix
[0] {
735 // Parse parses a formatted string and returns the time value it represents.
736 // The layout defines the format by showing how the reference time,
738 // Mon Jan 2 15:04:05 -0700 MST 2006
739 // would be interpreted if it were the value; it serves as an example of
740 // the input format. The same interpretation will then be made to the
743 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
744 // and convenient representations of the reference time. For more information
745 // about the formats and the definition of the reference time, see the
746 // documentation for ANSIC and the other constants defined by this package.
747 // Also, the executable example for Time.Format demonstrates the working
748 // of the layout string in detail and is a good reference.
750 // Elements omitted from the value are assumed to be zero or, when
751 // zero is impossible, one, so parsing "3:04pm" returns the time
752 // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is
753 // 0, this time is before the zero Time).
754 // Years must be in the range 0000..9999. The day of the week is checked
755 // for syntax but it is otherwise ignored.
757 // In the absence of a time zone indicator, Parse returns a time in UTC.
759 // When parsing a time with a zone offset like -0700, if the offset corresponds
760 // to a time zone used by the current location (Local), then Parse uses that
761 // location and zone in the returned time. Otherwise it records the time as
762 // being in a fabricated location with time fixed at the given zone offset.
764 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation
765 // has a defined offset in the current location, then that offset is used.
766 // The zone abbreviation "UTC" is recognized as UTC regardless of location.
767 // If the zone abbreviation is unknown, Parse records the time as being
768 // in a fabricated location with the given zone abbreviation and a zero offset.
769 // This choice means that such a time can be parsed and reformatted with the
770 // same layout losslessly, but the exact instant used in the representation will
771 // differ by the actual zone offset. To avoid such problems, prefer time layouts
772 // that use a numeric zone offset, or use ParseInLocation.
773 func Parse(layout
, value
string) (Time
, error
) {
774 return parse(layout
, value
, UTC
, Local
)
777 // ParseInLocation is like Parse but differs in two important ways.
778 // First, in the absence of time zone information, Parse interprets a time as UTC;
779 // ParseInLocation interprets the time as in the given location.
780 // Second, when given a zone offset or abbreviation, Parse tries to match it
781 // against the Local location; ParseInLocation uses the given location.
782 func ParseInLocation(layout
, value
string, loc
*Location
) (Time
, error
) {
783 return parse(layout
, value
, loc
, loc
)
786 func parse(layout
, value
string, defaultLocation
, local
*Location
) (Time
, error
) {
787 alayout
, avalue
:= layout
, value
788 rangeErrString
:= "" // set if a value is out of range
789 amSet
:= false // do we need to subtract 12 from the hour for midnight?
790 pmSet
:= false // do we need to add 12 to the hour?
792 // Time being constructed.
795 month
int = 1 // January
806 // Each iteration processes one std value.
809 prefix
, std
, suffix
:= nextStdChunk(layout
)
810 stdstr
:= layout
[len(prefix
) : len(layout
)-len(suffix
)]
811 value
, err
= skip(value
, prefix
)
813 return Time
{}, &ParseError
{alayout
, avalue
, prefix
, value
, ""}
817 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": extra text: " + value
}
823 switch std
& stdMask
{
829 p
, value
= value
[0:2], value
[2:]
831 if year
>= 69 { // Unix time starts Dec 31 1969 in some time zones
837 if len(value
) < 4 ||
!isDigit(value
, 0) {
841 p
, value
= value
[0:4], value
[4:]
844 month
, value
, err
= lookup(shortMonthNames
, value
)
847 month
, value
, err
= lookup(longMonthNames
, value
)
849 case stdNumMonth
, stdZeroMonth
:
850 month
, value
, err
= getnum(value
, std
== stdZeroMonth
)
851 if month
<= 0 ||
12 < month
{
852 rangeErrString
= "month"
855 // Ignore weekday except for error checking.
856 _
, value
, err
= lookup(shortDayNames
, value
)
858 _
, value
, err
= lookup(longDayNames
, value
)
859 case stdDay
, stdUnderDay
, stdZeroDay
:
860 if std
== stdUnderDay
&& len(value
) > 0 && value
[0] == ' ' {
863 day
, value
, err
= getnum(value
, std
== stdZeroDay
)
865 // Note that we allow any one- or two-digit day here.
866 rangeErrString
= "day"
869 hour
, value
, err
= getnum(value
, false)
870 if hour
< 0 ||
24 <= hour
{
871 rangeErrString
= "hour"
873 case stdHour12
, stdZeroHour12
:
874 hour
, value
, err
= getnum(value
, std
== stdZeroHour12
)
875 if hour
< 0 ||
12 < hour
{
876 rangeErrString
= "hour"
878 case stdMinute
, stdZeroMinute
:
879 min
, value
, err
= getnum(value
, std
== stdZeroMinute
)
880 if min
< 0 ||
60 <= min
{
881 rangeErrString
= "minute"
883 case stdSecond
, stdZeroSecond
:
884 sec
, value
, err
= getnum(value
, std
== stdZeroSecond
)
885 if sec
< 0 ||
60 <= sec
{
886 rangeErrString
= "second"
889 // Special case: do we have a fractional second but no
890 // fractional second in the format?
891 if len(value
) >= 2 && value
[0] == '.' && isDigit(value
, 1) {
892 _
, std
, _
= nextStdChunk(layout
)
894 if std
== stdFracSecond0 || std
== stdFracSecond9
{
895 // Fractional second in the layout; proceed normally
898 // No fractional second in the layout but we have one in the input.
900 for ; n
< len(value
) && isDigit(value
, n
); n
++ {
902 nsec
, rangeErrString
, err
= parseNanoseconds(value
, n
)
910 p
, value
= value
[0:2], value
[2:]
924 p
, value
= value
[0:2], value
[2:]
933 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ShortTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumShortTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumColonSecondsTZ
:
934 if (std
== stdISO8601TZ || std
== stdISO8601ShortTZ || std
== stdISO8601ColonTZ
) && len(value
) >= 1 && value
[0] == 'Z' {
939 var sign
, hour
, min
, seconds
string
940 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ
{
949 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], "00", value
[6:]
950 } else if std
== stdNumShortTZ || std
== stdISO8601ShortTZ
{
955 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], "00", "00", value
[3:]
956 } else if std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
961 if value
[3] != ':' || value
[6] != ':' {
965 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], value
[7:9], value
[9:]
966 } else if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz
{
971 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], value
[5:7], value
[7:]
977 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], "00", value
[5:]
985 ss
, err
= atoi(seconds
)
987 zoneOffset
= (hr
*60+mm
)*60 + ss
// offset is in seconds
991 zoneOffset
= -zoneOffset
996 // Does it look like a time zone?
997 if len(value
) >= 3 && value
[0:3] == "UTC" {
1002 n
, ok
:= parseTimeZone(value
)
1007 zoneName
, value
= value
[:n
], value
[n
:]
1009 case stdFracSecond0
:
1010 // stdFracSecond0 requires the exact number of digits as specified in
1012 ndigit
:= 1 + (std
>> stdArgShift
)
1013 if len(value
) < ndigit
{
1017 nsec
, rangeErrString
, err
= parseNanoseconds(value
, ndigit
)
1018 value
= value
[ndigit
:]
1020 case stdFracSecond9
:
1021 if len(value
) < 2 || value
[0] != '.' || value
[1] < '0' ||
'9' < value
[1] {
1022 // Fractional second omitted.
1025 // Take any number of digits, even more than asked for,
1026 // because it is what the stdSecond case would do.
1028 for i
< 9 && i
+1 < len(value
) && '0' <= value
[i
+1] && value
[i
+1] <= '9' {
1031 nsec
, rangeErrString
, err
= parseNanoseconds(value
, 1+i
)
1034 if rangeErrString
!= "" {
1035 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ": " + rangeErrString
+ " out of range"}
1038 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ""}
1041 if pmSet
&& hour
< 12 {
1043 } else if amSet
&& hour
== 12 {
1047 // Validate the day of the month.
1048 if day
< 1 || day
> daysIn(Month(month
), year
) {
1049 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": day out of range"}
1053 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, z
), nil
1056 if zoneOffset
!= -1 {
1057 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
1058 t
.addSec(-int64(zoneOffset
))
1060 // Look for local zone with the given offset.
1061 // If that zone was in effect at the given time, use it.
1062 name
, offset
, _
, _
, _
:= local
.lookup(t
.unixSec())
1063 if offset
== zoneOffset
&& (zoneName
== "" || name
== zoneName
) {
1068 // Otherwise create fake zone to record offset.
1069 t
.setLoc(FixedZone(zoneName
, zoneOffset
))
1074 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
1075 // Look for local zone with the given offset.
1076 // If that zone was in effect at the given time, use it.
1077 offset
, ok
:= local
.lookupName(zoneName
, t
.unixSec())
1079 t
.addSec(-int64(offset
))
1084 // Otherwise, create fake zone with unknown offset.
1085 if len(zoneName
) > 3 && zoneName
[:3] == "GMT" {
1086 offset
, _
= atoi(zoneName
[3:]) // Guaranteed OK by parseGMT.
1089 t
.setLoc(FixedZone(zoneName
, offset
))
1093 // Otherwise, fall back to default.
1094 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, defaultLocation
), nil
1097 // parseTimeZone parses a time zone string and returns its length. Time zones
1098 // are human-generated and unpredictable. We can't do precise error checking.
1099 // On the other hand, for a correct parse there must be a time zone at the
1100 // beginning of the string, so it's almost always true that there's one
1101 // there. We look at the beginning of the string for a run of upper-case letters.
1102 // If there are more than 5, it's an error.
1103 // If there are 4 or 5 and the last is a T, it's a time zone.
1104 // If there are 3, it's a time zone.
1105 // Otherwise, other than special cases, it's not a time zone.
1106 // GMT is special because it can have an hour offset.
1107 func parseTimeZone(value
string) (length
int, ok
bool) {
1111 // Special case 1: ChST and MeST are the only zones with a lower-case letter.
1112 if len(value
) >= 4 && (value
[:4] == "ChST" || value
[:4] == "MeST") {
1115 // Special case 2: GMT may have an hour offset; treat it specially.
1116 if value
[:3] == "GMT" {
1117 length
= parseGMT(value
)
1120 // How many upper-case letters are there? Need at least three, at most five.
1122 for nUpper
= 0; nUpper
< 6; nUpper
++ {
1123 if nUpper
>= len(value
) {
1126 if c
:= value
[nUpper
]; c
< 'A' ||
'Z' < c
{
1133 case 5: // Must end in T to match.
1134 if value
[4] == 'T' {
1138 // Must end in T, except one special case.
1139 if value
[3] == 'T' || value
[:4] == "WITA" {
1148 // parseGMT parses a GMT time zone. The input string is known to start "GMT".
1149 // The function checks whether that is followed by a sign and a number in the
1150 // range -14 through 12 excluding zero.
1151 func parseGMT(value
string) int {
1153 if len(value
) == 0 {
1157 if sign
!= '-' && sign
!= '+' {
1160 x
, rem
, err
:= leadingInt(value
[1:])
1167 if x
== 0 || x
< -14 ||
12 < x
{
1170 return 3 + len(value
) - len(rem
)
1173 func parseNanoseconds(value
string, nbytes
int) (ns
int, rangeErrString
string, err error
) {
1174 if value
[0] != '.' {
1178 if ns
, err
= atoi(value
[1:nbytes
]); err
!= nil {
1181 if ns
< 0 ||
1e9
<= ns
{
1182 rangeErrString
= "fractional second"
1185 // We need nanoseconds, which means scaling by the number
1186 // of missing digits in the format, maximum length 10. If it's
1187 // longer than 10, we won't scale.
1188 scaleDigits
:= 10 - nbytes
1189 for i
:= 0; i
< scaleDigits
; i
++ {
1195 var errLeadingInt
= errors
.New("time: bad [0-9]*") // never printed
1197 // leadingInt consumes the leading [0-9]* from s.
1198 func leadingInt(s
string) (x
int64, rem
string, err error
) {
1200 for ; i
< len(s
); i
++ {
1202 if c
< '0' || c
> '9' {
1205 if x
> (1<<63-1)/10 {
1207 return 0, "", errLeadingInt
1209 x
= x
*10 + int64(c
) - '0'
1212 return 0, "", errLeadingInt
1215 return x
, s
[i
:], nil
1218 // leadingFraction consumes the leading [0-9]* from s.
1219 // It is used only for fractions, so does not return an error on overflow,
1220 // it just stops accumulating precision.
1221 func leadingFraction(s
string) (x
int64, scale
float64, rem
string) {
1225 for ; i
< len(s
); i
++ {
1227 if c
< '0' || c
> '9' {
1233 if x
> (1<<63-1)/10 {
1234 // It's possible for overflow to give a positive number, so take care.
1238 y
:= x
*10 + int64(c
) - '0'
1246 return x
, scale
, s
[i
:]
1249 var unitMap
= map[string]int64{
1250 "ns": int64(Nanosecond
),
1251 "us": int64(Microsecond
),
1252 "µs": int64(Microsecond
), // U+00B5 = micro symbol
1253 "μs": int64(Microsecond
), // U+03BC = Greek letter mu
1254 "ms": int64(Millisecond
),
1260 // ParseDuration parses a duration string.
1261 // A duration string is a possibly signed sequence of
1262 // decimal numbers, each with optional fraction and a unit suffix,
1263 // such as "300ms", "-1.5h" or "2h45m".
1264 // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
1265 func ParseDuration(s
string) (Duration
, error
) {
1266 // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
1274 if c
== '-' || c
== '+' {
1279 // Special case: if all that is left is "0", this is zero.
1284 return 0, errors
.New("time: invalid duration " + orig
)
1288 v
, f
int64 // integers before, after decimal point
1289 scale
float64 = 1 // value = v + f/scale
1294 // The next character must be [0-9.]
1295 if !(s
[0] == '.' ||
'0' <= s
[0] && s
[0] <= '9') {
1296 return 0, errors
.New("time: invalid duration " + orig
)
1300 v
, s
, err
= leadingInt(s
)
1302 return 0, errors
.New("time: invalid duration " + orig
)
1304 pre
:= pl
!= len(s
) // whether we consumed anything before a period
1306 // Consume (\.[0-9]*)?
1308 if s
!= "" && s
[0] == '.' {
1311 f
, scale
, s
= leadingFraction(s
)
1315 // no digits (e.g. ".s" or "-.s")
1316 return 0, errors
.New("time: invalid duration " + orig
)
1321 for ; i
< len(s
); i
++ {
1323 if c
== '.' ||
'0' <= c
&& c
<= '9' {
1328 return 0, errors
.New("time: missing unit in duration " + orig
)
1332 unit
, ok
:= unitMap
[u
]
1334 return 0, errors
.New("time: unknown unit " + u
+ " in duration " + orig
)
1336 if v
> (1<<63-1)/unit
{
1338 return 0, errors
.New("time: invalid duration " + orig
)
1342 // float64 is needed to be nanosecond accurate for fractions of hours.
1343 // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
1344 v
+= int64(float64(f
) * (float64(unit
) / scale
))
1347 return 0, errors
.New("time: invalid duration " + orig
)
1353 return 0, errors
.New("time: invalid duration " + orig
)
1360 return Duration(d
), nil