From c08ee6659570e7f76aa05c037c604db1057a1f46 Mon Sep 17 00:00:00 2001 From: Rafi Shamim Date: Wed, 12 May 2021 20:09:33 -0400 Subject: [PATCH] cli: format time zones and floating points to match SQL Release note (cli change): The SQL shell now formats times with time zones so that the minutes and seconds offsets are only shown if they are non-zero. Also, infinite floating point values are formatted as `Infinity` rather than `Inf` now. --- pkg/cli/cli_test.go | 17 +++++++++++------ pkg/cli/sql_util.go | 15 ++++++++++++++- pkg/util/timeutil/timeutil.go | 14 ++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index 496445126733..1390c918be37 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -287,8 +287,9 @@ func Example_sql_format() { c.RunWithArgs([]string{"sql", "-e", "create database t; create table t.times (bare timestamp, withtz timestamptz)"}) c.RunWithArgs([]string{"sql", "-e", "insert into t.times values ('2016-01-25 10:10:10', '2016-01-25 10:10:10-05:00')"}) c.RunWithArgs([]string{"sql", "-e", "select bare from t.times; select withtz from t.times"}) - c.RunWithArgs([]string{"sql", "-e", "select '2021-03-20'::date; select '01:01'::time; select '01:01'::timetz"}) - c.RunWithArgs([]string{"sql", "-e", "select (1/3.0)::real; select (1/3.0)::double precision"}) + c.RunWithArgs([]string{"sql", "-e", + "select '2021-03-20'::date; select '01:01'::time; select '01:01'::timetz; select '01:01+02:02'::timetz"}) + c.RunWithArgs([]string{"sql", "-e", "select (1/3.0)::real; select (1/3.0)::double precision; select '-inf'::float8"}) // Output: // sql -e create database t; create table t.times (bare timestamp, withtz timestamptz) @@ -299,19 +300,23 @@ func Example_sql_format() { // bare // 2016-01-25 10:10:10 // withtz - // 2016-01-25 15:10:10+00:00:00 - // sql -e select '2021-03-20'::date; select '01:01'::time; select '01:01'::timetz + // 2016-01-25 15:10:10+00 + // sql -e select '2021-03-20'::date; select '01:01'::time; select '01:01'::timetz; select '01:01+02:02'::timetz // date // 2021-03-20 // time // 01:01:00 // timetz - // 01:01:00+00:00:00 - // sql -e select (1/3.0)::real; select (1/3.0)::double precision + // 01:01:00+00 + // timetz + // 01:01:00+02:02 + // sql -e select (1/3.0)::real; select (1/3.0)::double precision; select '-inf'::float8 // float4 // 0.33333334 // float8 // 0.3333333333333333 + // float8 + // -Infinity } func Example_sql_column_labels() { diff --git a/pkg/cli/sql_util.go b/pkg/cli/sql_util.go index 5dbf165bdad2..4e5522e67d0d 100644 --- a/pkg/cli/sql_util.go +++ b/pkg/cli/sql_util.go @@ -15,6 +15,7 @@ import ( "database/sql/driver" "fmt" "io" + "math" "net/url" "reflect" "strconv" @@ -1134,6 +1135,11 @@ func formatVal( if colType == "FLOAT4" { width = 32 } + if math.IsInf(t, 1) { + return "Infinity" + } else if math.IsInf(t, -1) { + return "-Infinity" + } return strconv.FormatFloat(t, 'g', -1, width) case string: @@ -1178,6 +1184,13 @@ func formatVal( // Some unknown/new time-like format. tfmt = timeutil.FullTimeFormat } + if tfmt == timeutil.TimestampWithTZFormat || tfmt == timeutil.TimeWithTZFormat { + if _, offsetSeconds := t.Zone(); offsetSeconds%60 != 0 { + tfmt += ":00:00" + } else if offsetSeconds%3600 != 0 { + tfmt += ":00" + } + } return t.Format(tfmt) } @@ -1186,7 +1199,7 @@ func formatVal( var timeOutputFormats = map[string]string{ "TIMESTAMP": timeutil.TimestampWithoutTZFormat, - "TIMESTAMPTZ": timeutil.FullTimeFormat, + "TIMESTAMPTZ": timeutil.TimestampWithTZFormat, "TIME": timeutil.TimeWithoutTZFormat, "TIMETZ": timeutil.TimeWithTZFormat, "DATE": timeutil.DateFormat, diff --git a/pkg/util/timeutil/timeutil.go b/pkg/util/timeutil/timeutil.go index bb6c7b51f597..07d846a598a0 100644 --- a/pkg/util/timeutil/timeutil.go +++ b/pkg/util/timeutil/timeutil.go @@ -10,17 +10,23 @@ package timeutil -// FullTimeFormat is the time format used to display any timestamp -// with date, time and time zone data. +// FullTimeFormat is the time format used to display any unknown timestamp +// type, and always shows the full time zone offset. const FullTimeFormat = "2006-01-02 15:04:05.999999-07:00:00" +// TimestampWithTZFormat is the time format used to display +// timestamps with a time zone offset. The minutes and seconds +// offsets are only added if they are non-zero. +const TimestampWithTZFormat = "2006-01-02 15:04:05.999999-07" + // TimestampWithoutTZFormat is the time format used to display -// timestamps without a time zone offset. +// timestamps without a time zone offset. The minutes and seconds +// offsets are only added if they are non-zero. const TimestampWithoutTZFormat = "2006-01-02 15:04:05.999999" // TimeWithTZFormat is the time format used to display a time // with a time zone offset. -const TimeWithTZFormat = "15:04:05.999999-07:00:00" +const TimeWithTZFormat = "15:04:05.999999-07" // TimeWithoutTZFormat is the time format used to display a time // without a time zone offset.