diff --git a/period/parse.go b/period/parse.go index 304bc501..d88f1e7c 100644 --- a/period/parse.go +++ b/period/parse.go @@ -76,10 +76,10 @@ func parse(period string, normalise bool) (*period64, error) { } remaining = remaining[1:] - var number, weekValue, prevFraction int64 + var integer, fraction, weekValue int64 result := &period64{input: period, neg: neg} var years, months, weeks, days, hours, minutes, seconds itemState - var designator, prevDesignator byte + var designator, previousFractionDesignator byte var err error nComponents := 0 @@ -99,16 +99,17 @@ func parse(period string, normalise bool) (*period64, error) { remaining = remaining[1:] } else { - number, designator, remaining, err = parseNextField(remaining, period) + integer, fraction, designator, remaining, err = parseNextField(remaining, period) if err != nil { return nil, err } - fraction := number % 10 - if prevFraction != 0 && fraction != 0 { - return nil, fmt.Errorf("%s: '%c' & '%c' only the last field can have a fraction", period, prevDesignator, designator) + if previousFractionDesignator != 0 && fraction != 0 { + return nil, fmt.Errorf("%s: '%c' & '%c' only the last field can have a fraction", period, previousFractionDesignator, designator) } + number := integer*10 + fraction + switch designator { case 'Y': years, err = years.testAndSet(number, 'Y', result, &result.years) @@ -135,8 +136,9 @@ func parse(period string, normalise bool) (*period64, error) { return nil, err } - prevFraction = fraction - prevDesignator = designator + if fraction != 0 { + previousFractionDesignator = designator + } } } @@ -177,19 +179,19 @@ func (i itemState) testAndSet(number int64, designator byte, result *period64, v //------------------------------------------------------------------------------------------------- -func parseNextField(str, original string) (int64, byte, string, error) { +func parseNextField(str, original string) (int64, int64, byte, string, error) { i := scanDigits(str) if i < 0 { - return 0, 0, "", fmt.Errorf("%s: missing designator at the end", original) + return 0, 0, 0, "", fmt.Errorf("%s: missing designator at the end", original) } des := str[i] - number, err := parseDecimalNumber(str[:i], original, des) - return number, des, str[i+1:], err + integer, fraction, err := parseDecimalNumber(str[:i], original, des) + return integer, fraction, des, str[i+1:], err } // Fixed-point one decimal place -func parseDecimalNumber(number, original string, des byte) (int64, error) { +func parseDecimalNumber(number, original string, des byte) (int64, int64, error) { dec := strings.IndexByte(number, '.') if dec < 0 { dec = strings.IndexByte(number, ',') @@ -214,10 +216,10 @@ func parseDecimalNumber(number, original string, des byte) (int64, error) { } if err != nil { - return 0, fmt.Errorf("%s: expected a number but found '%c'", original, des) + return 0, 0, fmt.Errorf("%s: expected a number but found '%c'", original, des) } - return integer*10 + fraction, err + return integer, fraction, err } // scanDigits finds the first non-digit byte after a given starting point. diff --git a/period/period_test.go b/period/period_test.go index 043fe782..d89a0d00 100644 --- a/period/period_test.go +++ b/period/period_test.go @@ -41,7 +41,9 @@ func TestParseErrors(t *testing.T) { {"P1D2D", false, ": 'D' designator cannot occur more than once", "P1D2D"}, {"PT1HT1S", false, ": 'T' designator cannot occur more than once", "PT1HT1S"}, {"P0.1YT0.1S", false, ": 'Y' & 'S' only the last field can have a fraction", "P0.1YT0.1S"}, + {"P0.1Y1M1DT1H1M0.1S", false, ": 'Y' & 'S' only the last field can have a fraction", "P0.1Y1M1DT1H1M0.1S"}, {"P", false, ": expected 'Y', 'M', 'W', 'D', 'H', 'M', or 'S' designator", "P"}, + // integer overflow {"P32768Y", false, ": integer overflow occurred in years", "P32768Y"}, {"P32768M", false, ": integer overflow occurred in months", "P32768M"},