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 // Within the format string, an underscore _ represents a space that may be
22 // replaced by a digit if the following number (a day) has two digits; for
23 // compatibility with fixed-width Unix time formats.
25 // A decimal point followed by one or more zeros represents a fractional
26 // second, printed to the given number of decimal places. A decimal point
27 // followed by one or more nines represents a fractional second, printed to
28 // the given number of decimal places, with trailing zeros removed.
29 // When parsing (only), the input may contain a fractional second
30 // field immediately after the seconds field, even if the layout does not
31 // signify its presence. In that case a decimal point followed by a maximal
32 // series of digits is parsed as a fractional second.
34 // Numeric time zone offsets format as follows:
37 // Replacing the sign in the format with a Z triggers
38 // the ISO 8601 behavior of printing Z instead of an
39 // offset for the UTC zone. Thus:
43 ANSIC
= "Mon Jan _2 15:04:05 2006"
44 UnixDate
= "Mon Jan _2 15:04:05 MST 2006"
45 RubyDate
= "Mon Jan 02 15:04:05 -0700 2006"
46 RFC822
= "02 Jan 06 15:04 MST"
47 RFC822Z
= "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
48 RFC850
= "Monday, 02-Jan-06 15:04:05 MST"
49 RFC1123
= "Mon, 02 Jan 2006 15:04:05 MST"
50 RFC1123Z
= "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
51 RFC3339
= "2006-01-02T15:04:05Z07:00"
52 RFC3339Nano
= "2006-01-02T15:04:05.999999999Z07:00"
55 Stamp
= "Jan _2 15:04:05"
56 StampMilli
= "Jan _2 15:04:05.000"
57 StampMicro
= "Jan _2 15:04:05.000000"
58 StampNano
= "Jan _2 15:04:05.000000000"
63 stdLongMonth
= iota + stdNeedDate
// "January"
67 stdLongWeekDay
// "Monday"
72 stdHour
= iota + stdNeedClock
// "15"
79 stdLongYear
= iota + stdNeedDate
// "2006"
81 stdPM
= iota + stdNeedClock
// "PM"
84 stdISO8601TZ
// "Z0700" // prints Z for UTC
85 stdISO8601SecondsTZ
// "Z070000"
86 stdISO8601ColonTZ
// "Z07:00" // prints Z for UTC
87 stdISO8601ColonSecondsTZ
// "Z07:00:00"
88 stdNumTZ
// "-0700" // always numeric
89 stdNumSecondsTz
// "-070000"
90 stdNumShortTZ
// "-07" // always numeric
91 stdNumColonTZ
// "-07:00" // always numeric
92 stdNumColonSecondsTZ
// "-07:00:00"
93 stdFracSecond0
// ".0", ".00", ... , trailing zeros included
94 stdFracSecond9
// ".9", ".99", ..., trailing zeros omitted
96 stdNeedDate
= 1 << 8 // need month, day, year
97 stdNeedClock
= 2 << 8 // need hour, minute, second
98 stdArgShift
= 16 // extra argument in high bits, above low stdArgShift
99 stdMask
= 1<<stdArgShift
- 1 // mask out argument
102 // std0x records the std values for "01", "02", ..., "06".
103 var std0x
= [...]int{stdZeroMonth
, stdZeroDay
, stdZeroHour12
, stdZeroMinute
, stdZeroSecond
, stdYear
}
105 // startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
106 // Its purpose is to prevent matching strings like "Month" when looking for "Mon".
107 func startsWithLowerCase(str
string) bool {
112 return 'a' <= c
&& c
<= 'z'
115 // nextStdChunk finds the first occurrence of a std string in
116 // layout and returns the text before, the std string, and the text after.
117 func nextStdChunk(layout
string) (prefix
string, std
int, suffix
string) {
118 for i
:= 0; i
< len(layout
); i
++ {
119 switch c
:= int(layout
[i
]); c
{
120 case 'J': // January, Jan
121 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "Jan" {
122 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "January" {
123 return layout
[0:i
], stdLongMonth
, layout
[i
+7:]
125 if !startsWithLowerCase(layout
[i
+3:]) {
126 return layout
[0:i
], stdMonth
, layout
[i
+3:]
130 case 'M': // Monday, Mon, MST
131 if len(layout
) >= i
+3 {
132 if layout
[i
:i
+3] == "Mon" {
133 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Monday" {
134 return layout
[0:i
], stdLongWeekDay
, layout
[i
+6:]
136 if !startsWithLowerCase(layout
[i
+3:]) {
137 return layout
[0:i
], stdWeekDay
, layout
[i
+3:]
140 if layout
[i
:i
+3] == "MST" {
141 return layout
[0:i
], stdTZ
, layout
[i
+3:]
145 case '0': // 01, 02, 03, 04, 05, 06
146 if len(layout
) >= i
+2 && '1' <= layout
[i
+1] && layout
[i
+1] <= '6' {
147 return layout
[0:i
], std0x
[layout
[i
+1]-'1'], layout
[i
+2:]
151 if len(layout
) >= i
+2 && layout
[i
+1] == '5' {
152 return layout
[0:i
], stdHour
, layout
[i
+2:]
154 return layout
[0:i
], stdNumMonth
, layout
[i
+1:]
157 if len(layout
) >= i
+4 && layout
[i
:i
+4] == "2006" {
158 return layout
[0:i
], stdLongYear
, layout
[i
+4:]
160 return layout
[0:i
], stdDay
, layout
[i
+1:]
163 if len(layout
) >= i
+2 && layout
[i
+1] == '2' {
164 return layout
[0:i
], stdUnderDay
, layout
[i
+2:]
168 return layout
[0:i
], stdHour12
, layout
[i
+1:]
171 return layout
[0:i
], stdMinute
, layout
[i
+1:]
174 return layout
[0:i
], stdSecond
, layout
[i
+1:]
177 if len(layout
) >= i
+2 && layout
[i
+1] == 'M' {
178 return layout
[0:i
], stdPM
, layout
[i
+2:]
182 if len(layout
) >= i
+2 && layout
[i
+1] == 'm' {
183 return layout
[0:i
], stdpm
, layout
[i
+2:]
186 case '-': // -070000, -07:00:00, -0700, -07:00, -07
187 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "-070000" {
188 return layout
[0:i
], stdNumSecondsTz
, layout
[i
+7:]
190 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "-07:00:00" {
191 return layout
[0:i
], stdNumColonSecondsTZ
, layout
[i
+9:]
193 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "-0700" {
194 return layout
[0:i
], stdNumTZ
, layout
[i
+5:]
196 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "-07:00" {
197 return layout
[0:i
], stdNumColonTZ
, layout
[i
+6:]
199 if len(layout
) >= i
+3 && layout
[i
:i
+3] == "-07" {
200 return layout
[0:i
], stdNumShortTZ
, layout
[i
+3:]
203 case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,
204 if len(layout
) >= i
+7 && layout
[i
:i
+7] == "Z070000" {
205 return layout
[0:i
], stdISO8601SecondsTZ
, layout
[i
+7:]
207 if len(layout
) >= i
+9 && layout
[i
:i
+9] == "Z07:00:00" {
208 return layout
[0:i
], stdISO8601ColonSecondsTZ
, layout
[i
+9:]
210 if len(layout
) >= i
+5 && layout
[i
:i
+5] == "Z0700" {
211 return layout
[0:i
], stdISO8601TZ
, layout
[i
+5:]
213 if len(layout
) >= i
+6 && layout
[i
:i
+6] == "Z07:00" {
214 return layout
[0:i
], stdISO8601ColonTZ
, layout
[i
+6:]
217 case '.': // .000 or .999 - repeated digits for fractional seconds.
218 if i
+1 < len(layout
) && (layout
[i
+1] == '0' || layout
[i
+1] == '9') {
221 for j
< len(layout
) && layout
[j
] == ch
{
224 // String of digits must end here - only fractional second is all digits.
225 if !isDigit(layout
, j
) {
226 std
:= stdFracSecond0
227 if layout
[i
+1] == '9' {
230 std |
= (j
- (i
+ 1)) << stdArgShift
231 return layout
[0:i
], std
, layout
[j
:]
239 var longDayNames
= []string{
249 var shortDayNames
= []string{
259 var shortMonthNames
= []string{
275 var longMonthNames
= []string{
291 // match returns true if s1 and s2 match ignoring case.
292 // It is assumed s1 and s2 are the same length.
293 func match(s1
, s2
string) bool {
294 for i
:= 0; i
< len(s1
); i
++ {
298 // Switch to lower-case; 'a'-'A' is known to be a single bit.
301 if c1
!= c2 || c1
< 'a' || c1
> 'z' {
309 func lookup(tab
[]string, val
string) (int, string, error
) {
310 for i
, v
:= range tab
{
311 if len(val
) >= len(v
) && match(val
[0:len(v
)], v
) {
312 return i
, val
[len(v
):], nil
315 return -1, val
, errBad
318 // appendUint appends the decimal form of x to b and returns the result.
319 // If x is a single-digit number and pad != 0, appendUint inserts the pad byte
321 // Duplicates functionality in strconv, but avoids dependency.
322 func appendUint(b
[]byte, x
uint, pad
byte) []byte {
327 return append(b
, byte('0'+x
))
330 b
= append(b
, byte('0'+x
/10))
331 b
= append(b
, byte('0'+x%10
))
338 return append(b
, '0')
342 buf
[n
] = byte(x%10
+ '0')
346 buf
[n
] = byte(x
+ '0')
347 return append(b
, buf
[n
:]...)
350 // Never printed, just needs to be non-nil for return by atoi.
351 var atoiError
= errors
.New("time: invalid number")
353 // Duplicates functionality in strconv, but avoids dependency.
354 func atoi(s
string) (x
int, err error
) {
356 if s
!= "" && (s
[0] == '-' || s
[0] == '+') {
360 q
, rem
, err
:= leadingInt(s
)
362 if err
!= nil || rem
!= "" {
371 // formatNano appends a fractional second, as nanoseconds, to b
372 // and returns the result.
373 func formatNano(b
[]byte, nanosec
uint, n
int, trim
bool) []byte {
376 for start
:= len(buf
); start
> 0; {
378 buf
[start
] = byte(u%10
+ '0')
386 for n
> 0 && buf
[n
-1] == '0' {
394 return append(b
, buf
[:n
]...)
397 // String returns the time formatted using the format string
398 // "2006-01-02 15:04:05.999999999 -0700 MST"
399 func (t Time
) String() string {
400 return t
.Format("2006-01-02 15:04:05.999999999 -0700 MST")
403 // Format returns a textual representation of the time value formatted
404 // according to layout, which defines the format by showing how the reference
405 // time, defined to be
406 // Mon Jan 2 15:04:05 -0700 MST 2006
407 // would be displayed if it were the value; it serves as an example of the
408 // desired output. The same display rules will then be applied to the time
410 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
411 // and convenient representations of the reference time. For more information
412 // about the formats and the definition of the reference time, see the
413 // documentation for ANSIC and the other constants defined by this package.
414 func (t Time
) Format(layout
string) string {
416 name
, offset
, abs
= t
.locabs()
428 max
:= len(layout
) + 10
432 b
= make([]byte, 0, max
)
434 // Each iteration generates one std value.
436 prefix
, std
, suffix
:= nextStdChunk(layout
)
438 b
= append(b
, prefix
...)
445 // Compute year, month, day if needed.
446 if year
< 0 && std
&stdNeedDate
!= 0 {
447 year
, month
, day
, _
= absDate(abs
, true)
450 // Compute hour, minute, second if needed.
451 if hour
< 0 && std
&stdNeedClock
!= 0 {
452 hour
, min
, sec
= absClock(abs
)
455 switch std
& stdMask
{
461 b
= appendUint(b
, uint(y%100
), '0')
463 // Pad year to at least 4 digits.
470 b
= append(b
, "-0"...)
473 b
= append(b
, "-00"...)
476 b
= append(b
, "-000"...)
479 b
= append(b
, "000"...)
481 b
= append(b
, "00"...)
485 b
= appendUint(b
, uint(y
), 0)
487 b
= append(b
, month
.String()[:3]...)
492 b
= appendUint(b
, uint(month
), 0)
494 b
= appendUint(b
, uint(month
), '0')
496 b
= append(b
, absWeekday(abs
).String()[:3]...)
498 s
:= absWeekday(abs
).String()
501 b
= appendUint(b
, uint(day
), 0)
503 b
= appendUint(b
, uint(day
), ' ')
505 b
= appendUint(b
, uint(day
), '0')
507 b
= appendUint(b
, uint(hour
), '0')
509 // Noon is 12PM, midnight is 12AM.
514 b
= appendUint(b
, uint(hr
), 0)
516 // Noon is 12PM, midnight is 12AM.
521 b
= appendUint(b
, uint(hr
), '0')
523 b
= appendUint(b
, uint(min
), 0)
525 b
= appendUint(b
, uint(min
), '0')
527 b
= appendUint(b
, uint(sec
), 0)
529 b
= appendUint(b
, uint(sec
), '0')
532 b
= append(b
, "PM"...)
534 b
= append(b
, "AM"...)
538 b
= append(b
, "pm"...)
540 b
= append(b
, "am"...)
542 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumColonSecondsTZ
:
543 // Ugly special case. We cheat and take the "Z" variants
544 // to mean "the time zone as formatted for ISO 8601".
545 if offset
== 0 && (std
== stdISO8601TZ || std
== stdISO8601ColonTZ || std
== stdISO8601SecondsTZ || std
== stdISO8601ColonSecondsTZ
) {
549 zone
:= offset
/ 60 // convert to minutes
554 absoffset
= -absoffset
558 b
= appendUint(b
, uint(zone
/60), '0')
559 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ || std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
562 b
= appendUint(b
, uint(zone%60
), '0')
564 // append seconds if appropriate
565 if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz || std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
566 if std
== stdNumColonSecondsTZ || std
== stdISO8601ColonSecondsTZ
{
569 b
= appendUint(b
, uint(absoffset%60
), '0')
574 b
= append(b
, name
...)
577 // No time zone known for this time, but we must print one.
578 // Use the -0700 format.
579 zone
:= offset
/ 60 // convert to minutes
586 b
= appendUint(b
, uint(zone
/60), '0')
587 b
= appendUint(b
, uint(zone%60
), '0')
588 case stdFracSecond0
, stdFracSecond9
:
589 b
= formatNano(b
, uint(t
.Nanosecond()), std
>>stdArgShift
, std
&stdMask
== stdFracSecond9
)
595 var errBad
= errors
.New("bad value for field") // placeholder not passed to user
597 // ParseError describes a problem parsing a time string.
598 type ParseError
struct {
606 func quote(s
string) string {
607 return "\"" + s
+ "\""
610 // Error returns the string representation of a ParseError.
611 func (e
*ParseError
) Error() string {
613 return "parsing time " +
614 quote(e
.Value
) + " as " +
615 quote(e
.Layout
) + ": cannot parse " +
616 quote(e
.ValueElem
) + " as " +
619 return "parsing time " +
620 quote(e
.Value
) + e
.Message
623 // isDigit returns true if s[i] is a decimal digit, false if not or
624 // if s[i] is out of range.
625 func isDigit(s
string, i
int) bool {
630 return '0' <= c
&& c
<= '9'
633 // getnum parses s[0:1] or s[0:2] (fixed forces the latter)
634 // as a decimal integer and returns the integer and the
635 // remainder of the string.
636 func getnum(s
string, fixed
bool) (int, string, error
) {
644 return int(s
[0] - '0'), s
[1:], nil
646 return int(s
[0]-'0')*10 + int(s
[1]-'0'), s
[2:], nil
649 func cutspace(s
string) string {
650 for len(s
) > 0 && s
[0] == ' ' {
656 // skip removes the given prefix from value,
657 // treating runs of space characters as equivalent.
658 func skip(value
, prefix
string) (string, error
) {
659 for len(prefix
) > 0 {
660 if prefix
[0] == ' ' {
661 if len(value
) > 0 && value
[0] != ' ' {
664 prefix
= cutspace(prefix
)
665 value
= cutspace(value
)
668 if len(value
) == 0 || value
[0] != prefix
[0] {
677 // Parse parses a formatted string and returns the time value it represents.
678 // The layout defines the format by showing how the reference time,
680 // Mon Jan 2 15:04:05 -0700 MST 2006
681 // would be interpreted if it were the value; it serves as an example of
682 // the input format. The same interpretation will then be made to the
684 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
685 // and convenient representations of the reference time. For more information
686 // about the formats and the definition of the reference time, see the
687 // documentation for ANSIC and the other constants defined by this package.
689 // Elements omitted from the value are assumed to be zero or, when
690 // zero is impossible, one, so parsing "3:04pm" returns the time
691 // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is
692 // 0, this time is before the zero Time).
693 // Years must be in the range 0000..9999. The day of the week is checked
694 // for syntax but it is otherwise ignored.
696 // In the absence of a time zone indicator, Parse returns a time in UTC.
698 // When parsing a time with a zone offset like -0700, if the offset corresponds
699 // to a time zone used by the current location (Local), then Parse uses that
700 // location and zone in the returned time. Otherwise it records the time as
701 // being in a fabricated location with time fixed at the given zone offset.
703 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation
704 // has a defined offset in the current location, then that offset is used.
705 // The zone abbreviation "UTC" is recognized as UTC regardless of location.
706 // If the zone abbreviation is unknown, Parse records the time as being
707 // in a fabricated location with the given zone abbreviation and a zero offset.
708 // This choice means that such a time can be parsed and reformatted with the
709 // same layout losslessly, but the exact instant used in the representation will
710 // differ by the actual zone offset. To avoid such problems, prefer time layouts
711 // that use a numeric zone offset, or use ParseInLocation.
712 func Parse(layout
, value
string) (Time
, error
) {
713 return parse(layout
, value
, UTC
, Local
)
716 // ParseInLocation is like Parse but differs in two important ways.
717 // First, in the absence of time zone information, Parse interprets a time as UTC;
718 // ParseInLocation interprets the time as in the given location.
719 // Second, when given a zone offset or abbreviation, Parse tries to match it
720 // against the Local location; ParseInLocation uses the given location.
721 func ParseInLocation(layout
, value
string, loc
*Location
) (Time
, error
) {
722 return parse(layout
, value
, loc
, loc
)
725 func parse(layout
, value
string, defaultLocation
, local
*Location
) (Time
, error
) {
726 alayout
, avalue
:= layout
, value
727 rangeErrString
:= "" // set if a value is out of range
728 amSet
:= false // do we need to subtract 12 from the hour for midnight?
729 pmSet
:= false // do we need to add 12 to the hour?
731 // Time being constructed.
734 month
int = 1 // January
745 // Each iteration processes one std value.
748 prefix
, std
, suffix
:= nextStdChunk(layout
)
749 stdstr
:= layout
[len(prefix
) : len(layout
)-len(suffix
)]
750 value
, err
= skip(value
, prefix
)
752 return Time
{}, &ParseError
{alayout
, avalue
, prefix
, value
, ""}
756 return Time
{}, &ParseError
{alayout
, avalue
, "", value
, ": extra text: " + value
}
762 switch std
& stdMask
{
768 p
, value
= value
[0:2], value
[2:]
770 if year
>= 69 { // Unix time starts Dec 31 1969 in some time zones
776 if len(value
) < 4 ||
!isDigit(value
, 0) {
780 p
, value
= value
[0:4], value
[4:]
783 month
, value
, err
= lookup(shortMonthNames
, value
)
785 month
, value
, err
= lookup(longMonthNames
, value
)
786 case stdNumMonth
, stdZeroMonth
:
787 month
, value
, err
= getnum(value
, std
== stdZeroMonth
)
788 if month
<= 0 ||
12 < month
{
789 rangeErrString
= "month"
792 // Ignore weekday except for error checking.
793 _
, value
, err
= lookup(shortDayNames
, value
)
795 _
, value
, err
= lookup(longDayNames
, value
)
796 case stdDay
, stdUnderDay
, stdZeroDay
:
797 if std
== stdUnderDay
&& len(value
) > 0 && value
[0] == ' ' {
800 day
, value
, err
= getnum(value
, std
== stdZeroDay
)
801 if day
< 0 ||
31 < day
{
802 rangeErrString
= "day"
805 hour
, value
, err
= getnum(value
, false)
806 if hour
< 0 ||
24 <= hour
{
807 rangeErrString
= "hour"
809 case stdHour12
, stdZeroHour12
:
810 hour
, value
, err
= getnum(value
, std
== stdZeroHour12
)
811 if hour
< 0 ||
12 < hour
{
812 rangeErrString
= "hour"
814 case stdMinute
, stdZeroMinute
:
815 min
, value
, err
= getnum(value
, std
== stdZeroMinute
)
816 if min
< 0 ||
60 <= min
{
817 rangeErrString
= "minute"
819 case stdSecond
, stdZeroSecond
:
820 sec
, value
, err
= getnum(value
, std
== stdZeroSecond
)
821 if sec
< 0 ||
60 <= sec
{
822 rangeErrString
= "second"
824 // Special case: do we have a fractional second but no
825 // fractional second in the format?
826 if len(value
) >= 2 && value
[0] == '.' && isDigit(value
, 1) {
827 _
, std
, _
= nextStdChunk(layout
)
829 if std
== stdFracSecond0 || std
== stdFracSecond9
{
830 // Fractional second in the layout; proceed normally
833 // No fractional second in the layout but we have one in the input.
835 for ; n
< len(value
) && isDigit(value
, n
); n
++ {
837 nsec
, rangeErrString
, err
= parseNanoseconds(value
, n
)
845 p
, value
= value
[0:2], value
[2:]
859 p
, value
= value
[0:2], value
[2:]
868 case stdISO8601TZ
, stdISO8601ColonTZ
, stdISO8601SecondsTZ
, stdISO8601ColonSecondsTZ
, stdNumTZ
, stdNumShortTZ
, stdNumColonTZ
, stdNumSecondsTz
, stdNumColonSecondsTZ
:
869 if (std
== stdISO8601TZ || std
== stdISO8601ColonTZ
) && len(value
) >= 1 && value
[0] == 'Z' {
874 var sign
, hour
, min
, seconds
string
875 if std
== stdISO8601ColonTZ || std
== stdNumColonTZ
{
884 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], "00", value
[6:]
885 } else if std
== stdNumShortTZ
{
890 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], "00", "00", value
[3:]
891 } else if std
== stdISO8601ColonSecondsTZ || std
== stdNumColonSecondsTZ
{
896 if value
[3] != ':' || value
[6] != ':' {
900 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[4:6], value
[7:9], value
[9:]
901 } else if std
== stdISO8601SecondsTZ || std
== stdNumSecondsTz
{
906 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], value
[5:7], value
[7:]
912 sign
, hour
, min
, seconds
, value
= value
[0:1], value
[1:3], value
[3:5], "00", value
[5:]
920 ss
, err
= atoi(seconds
)
922 zoneOffset
= (hr
*60+mm
)*60 + ss
// offset is in seconds
926 zoneOffset
= -zoneOffset
931 // Does it look like a time zone?
932 if len(value
) >= 3 && value
[0:3] == "UTC" {
937 n
, ok
:= parseTimeZone(value
)
942 zoneName
, value
= value
[:n
], value
[n
:]
945 // stdFracSecond0 requires the exact number of digits as specified in
947 ndigit
:= 1 + (std
>> stdArgShift
)
948 if len(value
) < ndigit
{
952 nsec
, rangeErrString
, err
= parseNanoseconds(value
, ndigit
)
953 value
= value
[ndigit
:]
956 if len(value
) < 2 || value
[0] != '.' || value
[1] < '0' ||
'9' < value
[1] {
957 // Fractional second omitted.
960 // Take any number of digits, even more than asked for,
961 // because it is what the stdSecond case would do.
963 for i
< 9 && i
+1 < len(value
) && '0' <= value
[i
+1] && value
[i
+1] <= '9' {
966 nsec
, rangeErrString
, err
= parseNanoseconds(value
, 1+i
)
969 if rangeErrString
!= "" {
970 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ": " + rangeErrString
+ " out of range"}
973 return Time
{}, &ParseError
{alayout
, avalue
, stdstr
, value
, ""}
976 if pmSet
&& hour
< 12 {
978 } else if amSet
&& hour
== 12 {
983 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, z
), nil
986 if zoneOffset
!= -1 {
987 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
988 t
.sec
-= int64(zoneOffset
)
990 // Look for local zone with the given offset.
991 // If that zone was in effect at the given time, use it.
992 name
, offset
, _
, _
, _
:= local
.lookup(t
.sec
+ internalToUnix
)
993 if offset
== zoneOffset
&& (zoneName
== "" || name
== zoneName
) {
998 // Otherwise create fake zone to record offset.
999 t
.loc
= FixedZone(zoneName
, zoneOffset
)
1004 t
:= Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, UTC
)
1005 // Look for local zone with the given offset.
1006 // If that zone was in effect at the given time, use it.
1007 offset
, _
, ok
:= local
.lookupName(zoneName
, t
.sec
+internalToUnix
)
1009 t
.sec
-= int64(offset
)
1014 // Otherwise, create fake zone with unknown offset.
1015 if len(zoneName
) > 3 && zoneName
[:3] == "GMT" {
1016 offset
, _
= atoi(zoneName
[3:]) // Guaranteed OK by parseGMT.
1019 t
.loc
= FixedZone(zoneName
, offset
)
1023 // Otherwise, fall back to default.
1024 return Date(year
, Month(month
), day
, hour
, min
, sec
, nsec
, defaultLocation
), nil
1027 // parseTimeZone parses a time zone string and returns its length. Time zones
1028 // are human-generated and unpredictable. We can't do precise error checking.
1029 // On the other hand, for a correct parse there must be a time zone at the
1030 // beginning of the string, so it's almost always true that there's one
1031 // there. We look at the beginning of the string for a run of upper-case letters.
1032 // If there are more than 5, it's an error.
1033 // If there are 4 or 5 and the last is a T, it's a time zone.
1034 // If there are 3, it's a time zone.
1035 // Otherwise, other than special cases, it's not a time zone.
1036 // GMT is special because it can have an hour offset.
1037 func parseTimeZone(value
string) (length
int, ok
bool) {
1041 // Special case 1: ChST and MeST are the only zones with a lower-case letter.
1042 if len(value
) >= 4 && (value
[:4] == "ChST" || value
[:4] == "MeST") {
1045 // Special case 2: GMT may have an hour offset; treat it specially.
1046 if value
[:3] == "GMT" {
1047 length
= parseGMT(value
)
1050 // How many upper-case letters are there? Need at least three, at most five.
1052 for nUpper
= 0; nUpper
< 6; nUpper
++ {
1053 if nUpper
>= len(value
) {
1056 if c
:= value
[nUpper
]; c
< 'A' ||
'Z' < c
{
1063 case 5: // Must end in T to match.
1064 if value
[4] == 'T' {
1067 case 4: // Must end in T to match.
1068 if value
[3] == 'T' {
1077 // parseGMT parses a GMT time zone. The input string is known to start "GMT".
1078 // The function checks whether that is followed by a sign and a number in the
1079 // range -14 through 12 excluding zero.
1080 func parseGMT(value
string) int {
1082 if len(value
) == 0 {
1086 if sign
!= '-' && sign
!= '+' {
1089 x
, rem
, err
:= leadingInt(value
[1:])
1096 if x
== 0 || x
< -14 ||
12 < x
{
1099 return 3 + len(value
) - len(rem
)
1102 func parseNanoseconds(value
string, nbytes
int) (ns
int, rangeErrString
string, err error
) {
1103 if value
[0] != '.' {
1107 if ns
, err
= atoi(value
[1:nbytes
]); err
!= nil {
1110 if ns
< 0 ||
1e9
<= ns
{
1111 rangeErrString
= "fractional second"
1114 // We need nanoseconds, which means scaling by the number
1115 // of missing digits in the format, maximum length 10. If it's
1116 // longer than 10, we won't scale.
1117 scaleDigits
:= 10 - nbytes
1118 for i
:= 0; i
< scaleDigits
; i
++ {
1124 var errLeadingInt
= errors
.New("time: bad [0-9]*") // never printed
1126 // leadingInt consumes the leading [0-9]* from s.
1127 func leadingInt(s
string) (x
int64, rem
string, err error
) {
1129 for ; i
< len(s
); i
++ {
1131 if c
< '0' || c
> '9' {
1134 if x
>= (1<<63-10)/10 {
1136 return 0, "", errLeadingInt
1138 x
= x
*10 + int64(c
) - '0'
1140 return x
, s
[i
:], nil
1143 var unitMap
= map[string]float64{
1144 "ns": float64(Nanosecond
),
1145 "us": float64(Microsecond
),
1146 "µs": float64(Microsecond
), // U+00B5 = micro symbol
1147 "μs": float64(Microsecond
), // U+03BC = Greek letter mu
1148 "ms": float64(Millisecond
),
1149 "s": float64(Second
),
1150 "m": float64(Minute
),
1154 // ParseDuration parses a duration string.
1155 // A duration string is a possibly signed sequence of
1156 // decimal numbers, each with optional fraction and a unit suffix,
1157 // such as "300ms", "-1.5h" or "2h45m".
1158 // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
1159 func ParseDuration(s
string) (Duration
, error
) {
1160 // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
1168 if c
== '-' || c
== '+' {
1173 // Special case: if all that is left is "0", this is zero.
1178 return 0, errors
.New("time: invalid duration " + orig
)
1181 g
:= float64(0) // this element of the sequence
1186 // The next character must be [0-9.]
1187 if !(s
[0] == '.' ||
('0' <= s
[0] && s
[0] <= '9')) {
1188 return 0, errors
.New("time: invalid duration " + orig
)
1192 x
, s
, err
= leadingInt(s
)
1194 return 0, errors
.New("time: invalid duration " + orig
)
1197 pre
:= pl
!= len(s
) // whether we consumed anything before a period
1199 // Consume (\.[0-9]*)?
1201 if s
!= "" && s
[0] == '.' {
1204 x
, s
, err
= leadingInt(s
)
1206 return 0, errors
.New("time: invalid duration " + orig
)
1209 for n
:= pl
- len(s
); n
> 0; n
-- {
1212 g
+= float64(x
) / scale
1216 // no digits (e.g. ".s" or "-.s")
1217 return 0, errors
.New("time: invalid duration " + orig
)
1222 for ; i
< len(s
); i
++ {
1224 if c
== '.' ||
('0' <= c
&& c
<= '9') {
1229 return 0, errors
.New("time: missing unit in duration " + orig
)
1233 unit
, ok
:= unitMap
[u
]
1235 return 0, errors
.New("time: unknown unit " + u
+ " in duration " + orig
)
1244 if f
< float64(-1<<63) || f
> float64(1<<63-1) {
1245 return 0, errors
.New("time: overflow parsing duration")
1247 return Duration(f
), nil