// compatibility with fixed-width Unix time formats.
//
// A decimal point followed by one or more zeros represents a fractional
-// second, printed to the given number of decimal places. A decimal point
-// followed by one or more nines represents a fractional second, printed to
-// the given number of decimal places, with trailing zeros removed.
+// second, printed to the given number of decimal places.
+// Either a comma or decimal point followed by one or more nines represents
+// a fractional second, printed to the given number of decimal places, with
+// trailing zeros removed.
// When parsing (only), the input may contain a fractional second
// field immediately after the seconds field, even if the layout does not
-// signify its presence. In that case a decimal point followed by a maximal
-// series of digits is parsed as a fractional second.
+// signify its presence. In that case either a comma or a decimal point
+// followed by a maximal series of digits is parsed as a fractional second.
//
// Numeric time zone offsets format as follows:
// -0700 ±hhmm
return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
}
- case '.': // .000 or .999 - repeated digits for fractional seconds.
+ case '.', ',': // ,000, or .000, or ,999, or .999 - repeated digits for fractional seconds.
if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
ch := layout[i+1]
j := i + 1
// desired output. The same display rules will then be applied to the time
// value.
//
-// A fractional second is represented by adding a period and zeros
-// to the end of the seconds section of layout string, as in "15:04:05.000"
-// to format a time stamp with millisecond precision.
+// A fractional second is represented by adding either a comma or a
+// period and zeros to the end of the seconds section of layout string,
+// as in "15:04:05,000" or "15:04:05.000" to format a time stamp with
+// millisecond precision.
//
// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
// and convenient representations of the reference time. For more information
}
// Special case: do we have a fractional second but no
// fractional second in the format?
- if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) {
+ if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) {
_, std, _ = nextStdChunk(layout)
std &= stdMask
if std == stdFracSecond0 || std == stdFracSecond9 {
value = value[ndigit:]
case stdFracSecond9:
- if len(value) < 2 || value[0] != '.' || value[1] < '0' || '9' < value[1] {
+ if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] {
// Fractional second omitted.
break
}
return len(value) - len(rem)
}
+func commaOrPeriod(b byte) bool {
+ return b == '.' || b == ','
+}
+
func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
- if value[0] != '.' {
+ if !commaOrPeriod(value[0]) {
err = errBad
return
}
{"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
{"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
// Fractional seconds.
- {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
- {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
- {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ {"millisecond:: dot separator", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond:: dot separator", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond:: dot separator", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ {"millisecond:: comma separator", "Mon Jan _2 15:04:05,000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond:: comma separator", "Mon Jan _2 15:04:05,000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond:: comma separator", "Mon Jan _2 15:04:05,000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+
// Leading zeros in other places should not be taken as fractional seconds.
{"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
{"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
// Accept any number of fractional second digits (including none) for .999...
// In Go 1, .999... was completely ignored in the format, meaning the first two
// cases would succeed, but the next four would not. Go 1.1 accepts all six.
+ // decimal "." separator.
{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+ // comma "," separator.
+ {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+ {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+ {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+ {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
// issue 4502.
{"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},