Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 16 additions & 30 deletions enginetest/queries/function_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,47 +990,33 @@ var FunctionQueryTests = []QueryTest{
Query: "select timestampdiff(quarter, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{39999}},
},
// TIMESTAMPDIFF tests for large timestamp differences // https://github.com/dolthub/dolt/issues/10397
// 0000-03-01 is used here instead of 0000-01-01 because 0000 is a leap year in Go (ie 0000-02-29 is a valid date),
// but not in MySQL. As a result, date differences between any day before 0000-02-29 and any after are off by one
// day.
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(microsecond, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{315569433599999999}},
Query: "select timestampdiff(microsecond, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{315564335999999999}},
},
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(second, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{315569433599}},
Query: "select timestampdiff(second, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{315564335999}},
},
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(minute, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{5259490559}},
Query: "select timestampdiff(minute, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{5259405599}},
},
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(hour, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{87658175}},
Query: "select timestampdiff(hour, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{87656759}},
},
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(day, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{3652423}},
Query: "select timestampdiff(day, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{3652364}},
},
{
// https://github.com/dolthub/dolt/issues/10397
Skip: true,
// might need to change first date to 0001-01-01 since 0000 is a leap year in Go but not in MySQL
Query: "select timestampdiff(week, '0000-01-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{521774}},
Query: "select timestampdiff(week, '0000-03-01', '9999-12-31 23:59:59.999999');",
Expected: []sql.Row{{521766}},
},
// TRIM Function Tests
{
Expand Down
27 changes: 15 additions & 12 deletions sql/expression/function/time_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -672,28 +672,26 @@ func (t *TimestampDiff) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
time1 := expr1.(time.Time)
time2 := expr2.(time.Time)

diff := time2.Sub(time1)

var res int64
switch unit {
case "microsecond":
res = diff.Microseconds()
res = microsecondsDiff(time1, time2)
case "second":
res = int64(diff.Seconds())
res = microsecondsDiff(time1, time2) / sql.MicrosecondsPerSecond
case "minute":
res = int64(diff.Minutes())
res = microsecondsDiff(time1, time2) / sql.MicrosecondsPerMinute
case "hour":
res = int64(diff.Hours())
res = microsecondsDiff(time1, time2) / sql.MicrosecondsPerHour
case "day":
res = int64(diff.Hours() / 24)
res = microsecondsDiff(time1, time2) / sql.MicrosecondsPerDay
case "week":
res = int64(diff.Hours() / (24 * 7))
res = microsecondsDiff(time1, time2) / sql.MicrosecondsPerWeek
case "month":
res = monthsDiff(time1, time2)
case "quarter":
res = monthsDiff(time1, time2) / 3
res = monthsDiff(time1, time2) / sql.MonthsPerQuarter
case "year":
res = monthsDiff(time1, time2) / 12
res = monthsDiff(time1, time2) / sql.MonthsPerYear
default:
return nil, errors.NewKind("invalid interval unit: %s").New(unit)
}
Expand Down Expand Up @@ -723,13 +721,18 @@ func monthsDiff(time1, time2 time.Time) int64 {
} else if beforeDay == afterDay {
beforeHour, beforeMin, beforeSec := before.Clock()
afterHour, afterMin, afterSec := after.Clock()
secondDiff := (afterHour-beforeHour)*3600 + (afterMin-beforeMin)*60 + (afterSec - beforeSec)
secondDiff := int64(afterHour-beforeHour)*sql.SecondsPerHour + int64(afterMin-beforeMin)*sql.SecondsPerMinute +
int64(afterSec-beforeSec)
if secondDiff < 0 {
monthDiff -= 1
} else if secondDiff == 0 && before.Nanosecond() > after.Nanosecond() {
monthDiff -= 1
}
}

return int64(sign) * (int64(yearDiff*12) + monthDiff)
return int64(sign) * (int64(yearDiff*sql.MonthsPerYear) + monthDiff)
}

func microsecondsDiff(date1, date2 time.Time) int64 {
return date2.UnixMicro() - date1.UnixMicro()
}
23 changes: 23 additions & 0 deletions sql/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,29 @@ import (
"time"
)

const (
NanosecondsPerMicrosecond = int64(time.Microsecond)

MicrosecondsPerSecond = int64(time.Second / time.Microsecond)

SecondsPerMinute = int64(time.Second / time.Minute)
MicrosecondsPerMinute = int64(time.Minute / time.Microsecond)

SecondsPerHour = int64(time.Hour / time.Second)
MicrosecondsPerHour = int64(time.Hour / time.Microsecond)

hoursPerDay = 24
DayDuration = hoursPerDay * time.Hour
MicrosecondsPerDay = MicrosecondsPerHour * hoursPerDay

daysPerWeek = 7
MicrosecondsPerWeek = MicrosecondsPerDay * daysPerWeek

MonthsPerQuarter = 3

MonthsPerYear = 12
)

// offsetRegex is a regex for matching MySQL offsets (e.g. +01:00).
var offsetRegex = regexp.MustCompile(`(?m)^([+\-])(\d{1,2}):(\d{2})$`)

Expand Down
Loading