diff --git a/expression/builtin_time.go b/expression/builtin_time.go index 71abf8398df95..dd04e9c294b05 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -216,15 +216,19 @@ var ( _ builtinFunc = &builtinAddDateStringDecimalSig{} _ builtinFunc = &builtinAddDateIntStringSig{} _ builtinFunc = &builtinAddDateIntIntSig{} + _ builtinFunc = &builtinAddDateIntDecimalSig{} _ builtinFunc = &builtinAddDateDatetimeStringSig{} _ builtinFunc = &builtinAddDateDatetimeIntSig{} + _ builtinFunc = &builtinAddDateDatetimeDecimalSig{} _ builtinFunc = &builtinSubDateStringStringSig{} _ builtinFunc = &builtinSubDateStringIntSig{} _ builtinFunc = &builtinSubDateStringDecimalSig{} _ builtinFunc = &builtinSubDateIntStringSig{} _ builtinFunc = &builtinSubDateIntIntSig{} + _ builtinFunc = &builtinSubDateIntDecimalSig{} _ builtinFunc = &builtinSubDateDatetimeStringSig{} _ builtinFunc = &builtinSubDateDatetimeIntSig{} + _ builtinFunc = &builtinSubDateDatetimeDecimalSig{} ) func convertTimeToMysqlTime(t time.Time, fsp int) (types.Time, error) { @@ -2589,8 +2593,14 @@ func (du *baseDateArithmitical) getIntervalFromDecimal(ctx sessionctx.Context, a interval = "00:" + interval case "SECOND_MICROSECOND": /* keep interval as original decimal */ + case "SECOND", "MICROSECOND": + args[1] = WrapWithCastAsReal(ctx, args[1]) + interval, isNull, err = args[1].EvalString(ctx, row) + if isNull || err != nil { + return "", true, errors.Trace(err) + } default: - // YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MICROSECOND + // YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE args[1] = WrapWithCastAsInt(ctx, args[1]) interval, isNull, err = args[1].EvalString(ctx, row) if isNull || err != nil { @@ -2620,7 +2630,8 @@ func (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, int return types.Time{}, true, errors.Trace(err) } - goTime = goTime.Add(dur) + duration := time.Duration(dur) + goTime = goTime.Add(duration) goTime = goTime.AddDate(int(year), int(month), int(day)) if goTime.Nanosecond() == 0 { @@ -2645,7 +2656,8 @@ func (du *baseDateArithmitical) sub(ctx sessionctx.Context, date types.Time, int return types.Time{}, true, errors.Trace(err) } - goTime = goTime.Add(dur) + duration := time.Duration(dur) + goTime = goTime.Add(duration) goTime = goTime.AddDate(int(year), int(month), int(day)) if goTime.Nanosecond() == 0 { @@ -2707,6 +2719,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres baseBuiltinFunc: bf, baseDateArithmitical: newDateArighmeticalUtil(), } + case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal: + sig = &builtinAddDateIntDecimalSig{ + baseBuiltinFunc: bf, + baseDateArithmitical: newDateArighmeticalUtil(), + } case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETString: sig = &builtinAddDateDatetimeStringSig{ baseBuiltinFunc: bf, @@ -2717,6 +2734,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres baseBuiltinFunc: bf, baseDateArithmitical: newDateArighmeticalUtil(), } + case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal: + sig = &builtinAddDateDatetimeDecimalSig{ + baseBuiltinFunc: bf, + baseDateArithmitical: newDateArighmeticalUtil(), + } } return sig, nil } @@ -2886,6 +2908,39 @@ func (b *builtinAddDateIntIntSig) evalTime(row chunk.Row) (types.Time, bool, err return result, isNull || err != nil, errors.Trace(err) } +type builtinAddDateIntDecimalSig struct { + baseBuiltinFunc + baseDateArithmitical +} + +func (b *builtinAddDateIntDecimalSig) Clone() builtinFunc { + newSig := &builtinAddDateIntDecimalSig{baseDateArithmitical: b.baseDateArithmitical} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalTime evals ADDDATE(date,INTERVAL expr unit). +// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate +func (b *builtinAddDateIntDecimalSig) evalTime(row chunk.Row) (types.Time, bool, error) { + unit, isNull, err := b.args[2].EvalString(b.ctx, row) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + result, isNull, err := b.add(b.ctx, date, interval, unit) + return result, isNull || err != nil, errors.Trace(err) +} + type builtinAddDateDatetimeStringSig struct { baseBuiltinFunc baseDateArithmitical @@ -2952,6 +3007,39 @@ func (b *builtinAddDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool return result, isNull || err != nil, errors.Trace(err) } +type builtinAddDateDatetimeDecimalSig struct { + baseBuiltinFunc + baseDateArithmitical +} + +func (b *builtinAddDateDatetimeDecimalSig) Clone() builtinFunc { + newSig := &builtinAddDateDatetimeDecimalSig{baseDateArithmitical: b.baseDateArithmitical} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalTime evals ADDDATE(date,INTERVAL expr unit). +// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate +func (b *builtinAddDateDatetimeDecimalSig) evalTime(row chunk.Row) (types.Time, bool, error) { + unit, isNull, err := b.args[2].EvalString(b.ctx, row) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + result, isNull, err := b.add(b.ctx, date, interval, unit) + return result, isNull || err != nil, errors.Trace(err) +} + type subDateFunctionClass struct { baseFunctionClass } @@ -3001,6 +3089,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres baseBuiltinFunc: bf, baseDateArithmitical: newDateArighmeticalUtil(), } + case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal: + sig = &builtinSubDateIntDecimalSig{ + baseBuiltinFunc: bf, + baseDateArithmitical: newDateArighmeticalUtil(), + } case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETString: sig = &builtinSubDateDatetimeStringSig{ baseBuiltinFunc: bf, @@ -3011,6 +3104,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres baseBuiltinFunc: bf, baseDateArithmitical: newDateArighmeticalUtil(), } + case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal: + sig = &builtinSubDateDatetimeDecimalSig{ + baseBuiltinFunc: bf, + baseDateArithmitical: newDateArighmeticalUtil(), + } } return sig, nil } @@ -3183,6 +3281,39 @@ type builtinSubDateDatetimeStringSig struct { baseDateArithmitical } +type builtinSubDateIntDecimalSig struct { + baseBuiltinFunc + baseDateArithmitical +} + +func (b *builtinSubDateIntDecimalSig) Clone() builtinFunc { + newSig := &builtinSubDateIntDecimalSig{baseDateArithmitical: b.baseDateArithmitical} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalTime evals SUBDATE(date,INTERVAL expr unit). +// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate +func (b *builtinSubDateIntDecimalSig) evalTime(row chunk.Row) (types.Time, bool, error) { + unit, isNull, err := b.args[2].EvalString(b.ctx, row) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + result, isNull, err := b.sub(b.ctx, date, interval, unit) + return result, isNull || err != nil, errors.Trace(err) +} + func (b *builtinSubDateDatetimeStringSig) Clone() builtinFunc { newSig := &builtinSubDateDatetimeStringSig{baseDateArithmitical: b.baseDateArithmitical} newSig.cloneFrom(&b.baseBuiltinFunc) @@ -3244,6 +3375,39 @@ func (b *builtinSubDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool return result, isNull || err != nil, errors.Trace(err) } +type builtinSubDateDatetimeDecimalSig struct { + baseBuiltinFunc + baseDateArithmitical +} + +func (b *builtinSubDateDatetimeDecimalSig) Clone() builtinFunc { + newSig := &builtinSubDateDatetimeDecimalSig{baseDateArithmitical: b.baseDateArithmitical} + newSig.cloneFrom(&b.baseBuiltinFunc) + return newSig +} + +// evalTime evals SUBDATE(date,INTERVAL expr unit). +// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate +func (b *builtinSubDateDatetimeDecimalSig) evalTime(row chunk.Row) (types.Time, bool, error) { + unit, isNull, err := b.args[2].EvalString(b.ctx, row) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit) + if isNull || err != nil { + return types.Time{}, true, errors.Trace(err) + } + + result, isNull, err := b.sub(b.ctx, date, interval, unit) + return result, isNull || err != nil, errors.Trace(err) +} + type timestampDiffFunctionClass struct { baseFunctionClass } diff --git a/expression/integration_test.go b/expression/integration_test.go index f16cdd8aae73d..d2e0dc125767c 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -1798,8 +1798,9 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) { {"\"2011-01-01 00:00:00\"", "10.10", "DAY", "2011-01-11 00:00:00", "2010-12-22 00:00:00"}, {"\"2011-01-01 00:00:00\"", "10.10", "HOUR", "2011-01-01 10:00:00", "2010-12-31 14:00:00"}, {"\"2011-01-01 00:00:00\"", "10.10", "MINUTE", "2011-01-01 00:10:00", "2010-12-31 23:50:00"}, - {"\"2011-01-01 00:00:00\"", "10.10", "SECOND", "2011-01-01 00:00:10", "2010-12-31 23:59:50"}, + {"\"2011-01-01 00:00:00\"", "10.10", "SECOND", "2011-01-01 00:00:10.100000", "2010-12-31 23:59:49.900000"}, {"\"2011-01-01 00:00:00\"", "10.10", "MICROSECOND", "2011-01-01 00:00:00.000010", "2010-12-31 23:59:59.999990"}, + {"\"2011-01-01 00:00:00\"", "10.90", "MICROSECOND", "2011-01-01 00:00:00.000011", "2010-12-31 23:59:59.999989"}, {"\"2009-01-01\"", "6/4", "HOUR_MINUTE", "2009-01-04 12:20:00", "2008-12-28 11:40:00"}, {"\"2009-01-01\"", "6/0", "HOUR_MINUTE", "", ""}, diff --git a/parser/parser_test.go b/parser/parser_test.go index eb8d2fffdb4a1..58501e849cfe4 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -871,6 +871,8 @@ func (s *testParserSuite) TestBuiltin(c *C) { {"select now(6)", true}, {"select sysdate(), sysdate(6)", true}, {"SELECT time('01:02:03');", true}, + {"SELECT time('01:02:03.1')", true}, + {"SELECT time('20.1')", true}, {"SELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001');", true}, {"SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');", true}, {"SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');", true}, diff --git a/types/time.go b/types/time.go index 3d179b441b677..fa06db224e58a 100644 --- a/types/time.go +++ b/types/time.go @@ -153,7 +153,8 @@ var ( func FromGoTime(t gotime.Time) MysqlTime { year, month, day := t.Date() hour, minute, second := t.Clock() - microsecond := t.Nanosecond() / 1000 + // Nanosecond plus 500 then divided 1000 means rounding to microseconds. + microsecond := (t.Nanosecond() + 500) / 1000 return FromDate(year, int(month), day, hour, minute, second, microsecond) } @@ -1515,22 +1516,22 @@ func ExtractDurationNum(d *Duration, unit string) (int64, error) { } } -func extractSingleTimeValue(unit string, format string) (int64, int64, int64, gotime.Duration, error) { - iv, err := strconv.ParseInt(format, 10, 64) +func extractSingleTimeValue(unit string, format string) (int64, int64, int64, float64, error) { + fv, err := strconv.ParseFloat(format, 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } + iv := int64(fv + 0.5) - v := gotime.Duration(iv) switch strings.ToUpper(unit) { case "MICROSECOND": - return 0, 0, 0, v * gotime.Microsecond, nil + return 0, 0, 0, fv * float64(gotime.Microsecond), nil case "SECOND": - return 0, 0, 0, v * gotime.Second, nil + return 0, 0, 0, fv * float64(gotime.Second), nil case "MINUTE": - return 0, 0, 0, v * gotime.Minute, nil + return 0, 0, 0, float64(iv * int64(gotime.Minute)), nil case "HOUR": - return 0, 0, 0, v * gotime.Hour, nil + return 0, 0, 0, float64(iv * int64(gotime.Hour)), nil case "DAY": return 0, 0, iv, 0, nil case "WEEK": @@ -1547,33 +1548,33 @@ func extractSingleTimeValue(unit string, format string) (int64, int64, int64, go } // extractSecondMicrosecond extracts second and microsecond from a string and its format is `SS.FFFFFF`. -func extractSecondMicrosecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractSecondMicrosecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ".") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - seconds, err := strconv.ParseInt(fields[0], 10, 64) + seconds, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - microseconds, err := strconv.ParseInt(alignFrac(fields[1], MaxFsp), 10, 64) + microseconds, err := strconv.ParseFloat(alignFrac(fields[1], MaxFsp), 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - return 0, 0, 0, gotime.Duration(seconds)*gotime.Second + gotime.Duration(microseconds)*gotime.Microsecond, nil + return 0, 0, 0, seconds*float64(gotime.Second) + microseconds*float64(gotime.Microsecond), nil } // extractMinuteMicrosecond extracts minutes and microsecond from a string and its format is `MM:SS.FFFFFF`. -func extractMinuteMicrosecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractMinuteMicrosecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ":") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - minutes, err := strconv.ParseInt(fields[0], 10, 64) + minutes, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } @@ -1583,42 +1584,42 @@ func extractMinuteMicrosecond(format string) (int64, int64, int64, gotime.Durati return 0, 0, 0, 0, errors.Trace(err) } - return 0, 0, 0, gotime.Duration(minutes)*gotime.Minute + value, nil + return 0, 0, 0, minutes*float64(gotime.Minute) + value, nil } // extractMinuteSecond extracts minutes and second from a string and its format is `MM:SS`. -func extractMinuteSecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractMinuteSecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ":") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - minutes, err := strconv.ParseInt(fields[0], 10, 64) + minutes, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - seconds, err := strconv.ParseInt(fields[1], 10, 64) + seconds, err := strconv.ParseFloat(fields[1], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - return 0, 0, 0, gotime.Duration(minutes)*gotime.Minute + gotime.Duration(seconds)*gotime.Second, nil + return 0, 0, 0, minutes*float64(gotime.Minute) + seconds*float64(gotime.Second), nil } // extractHourMicrosecond extracts hour and microsecond from a string and its format is `HH:MM:SS.FFFFFF`. -func extractHourMicrosecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractHourMicrosecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ":") if len(fields) != 3 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - hours, err := strconv.ParseInt(fields[0], 10, 64) + hours, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - minutes, err := strconv.ParseInt(fields[1], 10, 64) + minutes, err := strconv.ParseFloat(fields[1], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } @@ -1628,56 +1629,56 @@ func extractHourMicrosecond(format string) (int64, int64, int64, gotime.Duration return 0, 0, 0, 0, errors.Trace(err) } - return 0, 0, 0, gotime.Duration(hours)*gotime.Hour + gotime.Duration(minutes)*gotime.Minute + value, nil + return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute) + value, nil } // extractHourSecond extracts hour and second from a string and its format is `HH:MM:SS`. -func extractHourSecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractHourSecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ":") if len(fields) != 3 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - hours, err := strconv.ParseInt(fields[0], 10, 64) + hours, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - minutes, err := strconv.ParseInt(fields[1], 10, 64) + minutes, err := strconv.ParseFloat(fields[1], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - seconds, err := strconv.ParseInt(fields[2], 10, 64) + seconds, err := strconv.ParseFloat(fields[2], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - return 0, 0, 0, gotime.Duration(hours)*gotime.Hour + gotime.Duration(minutes)*gotime.Minute + gotime.Duration(seconds)*gotime.Second, nil + return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute) + seconds*float64(gotime.Second), nil } // extractHourMinute extracts hour and minute from a string and its format is `HH:MM`. -func extractHourMinute(format string) (int64, int64, int64, gotime.Duration, error) { +func extractHourMinute(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, ":") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - hours, err := strconv.ParseInt(fields[0], 10, 64) + hours, err := strconv.ParseFloat(fields[0], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - minutes, err := strconv.ParseInt(fields[1], 10, 64) + minutes, err := strconv.ParseFloat(fields[1], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - return 0, 0, 0, gotime.Duration(hours)*gotime.Hour + gotime.Duration(minutes)*gotime.Minute, nil + return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute), nil } // extractDayMicrosecond extracts day and microsecond from a string and its format is `DD HH:MM:SS.FFFFFF`. -func extractDayMicrosecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractDayMicrosecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, " ") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) @@ -1697,7 +1698,7 @@ func extractDayMicrosecond(format string) (int64, int64, int64, gotime.Duration, } // extractDaySecond extracts day and hour from a string and its format is `DD HH:MM:SS`. -func extractDaySecond(format string) (int64, int64, int64, gotime.Duration, error) { +func extractDaySecond(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, " ") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) @@ -1717,7 +1718,7 @@ func extractDaySecond(format string) (int64, int64, int64, gotime.Duration, erro } // extractDayMinute extracts day and minute from a string and its format is `DD HH:MM`. -func extractDayMinute(format string) (int64, int64, int64, gotime.Duration, error) { +func extractDayMinute(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, " ") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) @@ -1737,7 +1738,7 @@ func extractDayMinute(format string) (int64, int64, int64, gotime.Duration, erro } // extractDayHour extracts day and hour from a string and its format is `DD HH`. -func extractDayHour(format string) (int64, int64, int64, gotime.Duration, error) { +func extractDayHour(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, " ") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) @@ -1748,16 +1749,16 @@ func extractDayHour(format string) (int64, int64, int64, gotime.Duration, error) return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - hours, err := strconv.ParseInt(fields[1], 10, 64) + hours, err := strconv.ParseFloat(fields[1], 64) if err != nil { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) } - return 0, 0, days, gotime.Duration(hours) * gotime.Hour, nil + return 0, 0, days, hours * float64(gotime.Hour), nil } // extractYearMonth extracts year and month from a string and its format is `YYYY-MM`. -func extractYearMonth(format string) (int64, int64, int64, gotime.Duration, error) { +func extractYearMonth(format string) (int64, int64, int64, float64, error) { fields := strings.Split(format, "-") if len(fields) != 2 { return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format) @@ -1777,7 +1778,7 @@ func extractYearMonth(format string) (int64, int64, int64, gotime.Duration, erro } // ExtractTimeValue extracts time value from time unit and format. -func ExtractTimeValue(unit string, format string) (int64, int64, int64, gotime.Duration, error) { +func ExtractTimeValue(unit string, format string) (int64, int64, int64, float64, error) { switch strings.ToUpper(unit) { case "MICROSECOND", "SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "QUARTER", "YEAR": return extractSingleTimeValue(unit, format)