Skip to content

Commit

Permalink
sql: Allow 24:00 and variants to be parsed
Browse files Browse the repository at this point in the history
Fixes: #36118

Release note (sql change): Add support for the time value 24:00 and variants.
  • Loading branch information
rohany committed May 30, 2019
1 parent c280de4 commit 096c8e0
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
19 changes: 18 additions & 1 deletion pkg/sql/logictest/testdata/logic_test/time
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,25 @@ SELECT '23:59:59.999999':::TIME;
----
0000-01-01 23:59:59.999999 +0000 UTC

query T
select ('24:00'::TIME)::STRING
----
24:00:00

query T
SELECT ('24:00:00'::TIME)::STRING
----
24:00:00

statement error could not parse
SELECT '24:00:00':::TIME;
SELECT '124:00'::TIME;

statement error could not parse
SELECT '24:00:01'::TIME;

statement error could not parse
SELECT '24:00:00.001'::TIME;


# Timezone should be ignored.
query T
Expand Down
11 changes: 11 additions & 0 deletions pkg/sql/sem/tree/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"math"
"math/big"
"net"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -64,6 +65,9 @@ var (

// DZero is the zero-valued integer Datum.
DZero = NewDInt(0)

// DTimeRegex is a compiled regex for parsing the 24:00 time value
DTimeRegex = regexp.MustCompile("^24:00($|(:00$)|(:00.0+$))")
)

// Datum represents a SQL value.
Expand Down Expand Up @@ -1817,6 +1821,13 @@ func MakeDTime(t timeofday.TimeOfDay) *DTime {
// provided string, or an error if parsing is unsuccessful.
func ParseDTime(ctx ParseTimeContext, s string) (*DTime, error) {
now := relativeParseTime(ctx)

// special case on 24:00 and 24:00:00 as the parser
// does not handle these correctly.
if DTimeRegex.MatchString(s) {
return MakeDTime(timeofday.Time2400), nil
}

t, err := pgdate.ParseTime(now, 0 /* mode */, s)
if err != nil {
// Build our own error message to avoid exposing the dummy date.
Expand Down
6 changes: 5 additions & 1 deletion pkg/sql/sem/tree/datum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func TestDatumOrdering(t *testing.T) {
`'00:00:00'`, `'23:59:59.999999'`},
{`'23:59:59.999999':::time`, `'23:59:59.999998'`, valIsMax,
`'00:00:00'`, `'23:59:59.999999'`},
{`'24:00':::time`, `'23:59:59.999999'`, `'00:00:00.000001'`,
`'00:00:00'`, `'23:59:59.999999'`},

// Intervals
{`'1 day':::interval`, noPrev, noNext,
Expand Down Expand Up @@ -484,6 +486,9 @@ func TestParseDTime(t *testing.T) {
{"04:05:06.000001", timeofday.New(4, 5, 6, 1)},
{"04:05:06-07", timeofday.New(4, 5, 6, 0)},
{"4:5:6", timeofday.New(4, 5, 6, 0)},
{"24:00:00", timeofday.Time2400},
{"24:00:00.000", timeofday.Time2400},
{"24:00:00.000000", timeofday.Time2400},
}
for _, td := range testData {
actual, err := tree.ParseDTime(nil, td.str)
Expand All @@ -502,7 +507,6 @@ func TestParseDTimeError(t *testing.T) {
"",
"foo",
"01",
"24:00:00",
}
for _, s := range testData {
actual, _ := tree.ParseDTime(nil, s)
Expand Down
11 changes: 9 additions & 2 deletions pkg/util/timeofday/time_of_day.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ type TimeOfDay int64
const (
// Min is the minimum TimeOfDay value (midnight).
Min = TimeOfDay(0)
// Max is the maximum TimeOfDay value (1 microsecond before midnight).

// Max is the maximum TimeOfDay value (1 second before midnight)
Max = TimeOfDay(microsecondsPerDay - 1)

// Time2400 is a special value to represent the 24:00 input time
Time2400 = TimeOfDay(microsecondsPerDay)

microsecondsPerSecond = 1e6
microsecondsPerMinute = 60 * microsecondsPerSecond
microsecondsPerHour = 60 * microsecondsPerMinute
Expand Down Expand Up @@ -107,8 +111,11 @@ func Difference(t1 TimeOfDay, t2 TimeOfDay) duration.Duration {
return duration.MakeDuration(int64(t1-t2)*nanosPerMicro, 0, 0)
}

// Hour returns the hour specified by t, in the range [0, 23].
// Hour returns the hour specified by t, in the range [0, 24].
func (t TimeOfDay) Hour() int {
if t == Time2400 {
return 24
}
return int(int64(t)%microsecondsPerDay) / microsecondsPerHour
}

Expand Down

0 comments on commit 096c8e0

Please sign in to comment.