github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/timetz/timetz_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package timetz 12 13 import ( 14 "fmt" 15 "testing" 16 "time" 17 18 "github.com/cockroachdb/cockroach/pkg/util/timeofday" 19 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestParseTimeTZToStringRoundTrip(t *testing.T) { 25 testCases := []string{ 26 "24:00:00-1559", 27 "11:12:13+05:06:07", 28 "10:11:12+0", 29 "10:11:12.05+0", 30 } 31 for _, tc := range testCases { 32 t.Run(tc, func(t *testing.T) { 33 exampleTime, err := ParseTimeTZ(timeutil.Now(), tc, time.Microsecond) 34 assert.NoError(t, err) 35 36 exampleTimeFromString, err := ParseTimeTZ(timeutil.Now(), exampleTime.String(), time.Microsecond) 37 assert.NoError(t, err) 38 39 assert.True(t, exampleTime.Equal(exampleTimeFromString)) 40 }) 41 } 42 } 43 44 func TestTimeTZString(t *testing.T) { 45 testCases := []struct { 46 input TimeTZ 47 expected string 48 }{ 49 {MakeTimeTZ(timeofday.New(0, 0, 0, 0), 0), "00:00:00+00:00:00"}, 50 {MakeTimeTZ(timeofday.New(10, 11, 12, 0), 0), "10:11:12+00:00:00"}, 51 {MakeTimeTZ(timeofday.New(10, 11, 12, 0), -30), "10:11:12+00:00:30"}, 52 {MakeTimeTZ(timeofday.New(10, 11, 12, 0), 30), "10:11:12-00:00:30"}, 53 {MakeTimeTZ(timeofday.New(10, 11, 12, 0), 120), "10:11:12-00:02:00"}, 54 {MakeTimeTZ(timeofday.New(10, 11, 12, 0), 3), "10:11:12-00:00:03"}, 55 {MakeTimeTZ(timeofday.Max-1, -10*60*60), "23:59:59.999999+10:00:00"}, 56 {MakeTimeTZ(timeofday.Time2400, 10*60*60), "24:00:00-10:00:00"}, 57 } 58 for i, tc := range testCases { 59 t.Run(fmt.Sprintf("%d:%s", i, tc.expected), func(t *testing.T) { 60 assert.Equal(t, tc.expected, tc.input.String()) 61 }) 62 } 63 } 64 65 func TestTimeTZ(t *testing.T) { 66 maxTime, err := ParseTimeTZ(timeutil.Now(), "24:00:00-1559", time.Microsecond) 67 require.NoError(t, err) 68 minTime, err := ParseTimeTZ(timeutil.Now(), "00:00:00+1559", time.Microsecond) 69 require.NoError(t, err) 70 71 // These are all the same UTC time equivalents. 72 utcTime, err := ParseTimeTZ(timeutil.Now(), "11:14:15+0", time.Microsecond) 73 require.NoError(t, err) 74 sydneyTime, err := ParseTimeTZ(timeutil.Now(), "21:14:15+10", time.Microsecond) 75 require.NoError(t, err) 76 77 sydneyTimeWithMillisecond, err := ParseTimeTZ(timeutil.Now(), "21:14:15.001+10", time.Microsecond) 78 require.NoError(t, err) 79 80 // No daylight savings in Hawaii! 81 hawaiiZone, err := time.LoadLocation("Pacific/Honolulu") 82 require.NoError(t, err) 83 hawaiiTime := MakeTimeTZFromLocation(timeofday.New(1, 14, 15, 0), hawaiiZone) 84 85 weirdTimeZone := MakeTimeTZ(timeofday.New(10, 0, 0, 0), -((5 * 60 * 60) + 30*60 + 15)) 86 87 testCases := []struct { 88 t TimeTZ 89 toTime time.Time 90 toDuration time.Duration 91 largerThan []TimeTZ 92 smallerThan []TimeTZ 93 equalTo []TimeTZ 94 roundedToSecond TimeTZ 95 }{ 96 { 97 t: weirdTimeZone, 98 toTime: time.Date(1970, 1, 1, 10, 0, 0, 0, timeutil.FixedOffsetTimeZoneToLocation((5*60*60)+(30*60)+15, "TimeTZ")), 99 toDuration: time.Duration((10*60*60 - ((5 * 60 * 60) + 30*60 + 15))) * time.Second, 100 largerThan: []TimeTZ{minTime}, 101 smallerThan: []TimeTZ{maxTime}, 102 equalTo: []TimeTZ{weirdTimeZone}, 103 roundedToSecond: weirdTimeZone, 104 }, 105 { 106 t: utcTime, 107 toTime: time.Date(1970, 1, 1, 11, 14, 15, 0, timeutil.FixedOffsetTimeZoneToLocation(0, "TimeTZ")), 108 toDuration: time.Duration(11*60*60+14*60+15) * time.Second, 109 largerThan: []TimeTZ{minTime, sydneyTime}, 110 smallerThan: []TimeTZ{maxTime, hawaiiTime}, 111 equalTo: []TimeTZ{utcTime}, 112 roundedToSecond: utcTime, 113 }, 114 { 115 t: sydneyTime, 116 toTime: time.Date(1970, 1, 1, 21, 14, 15, 0, timeutil.FixedOffsetTimeZoneToLocation(10*60*60, "TimeTZ")), 117 toDuration: time.Duration(11*60*60+14*60+15) * time.Second, 118 largerThan: []TimeTZ{minTime}, 119 smallerThan: []TimeTZ{maxTime, utcTime, hawaiiTime}, 120 equalTo: []TimeTZ{sydneyTime}, 121 roundedToSecond: sydneyTime, 122 }, 123 { 124 t: sydneyTimeWithMillisecond, 125 toTime: time.Date(1970, 1, 1, 21, 14, 15, 1000000, timeutil.FixedOffsetTimeZoneToLocation(10*60*60, "TimeTZ")), 126 toDuration: time.Duration(11*60*60+14*60+15)*time.Second + 1*time.Millisecond, 127 largerThan: []TimeTZ{minTime, utcTime, hawaiiTime, sydneyTime}, 128 smallerThan: []TimeTZ{maxTime}, 129 equalTo: []TimeTZ{sydneyTimeWithMillisecond}, 130 roundedToSecond: sydneyTime, 131 }, 132 { 133 t: hawaiiTime, 134 toTime: time.Date(1970, 1, 1, 1, 14, 15, 0, timeutil.FixedOffsetTimeZoneToLocation(-10*60*60, "TimeTZ")), 135 toDuration: time.Duration(11*60*60+14*60+15) * time.Second, 136 largerThan: []TimeTZ{minTime, utcTime, sydneyTime}, 137 smallerThan: []TimeTZ{maxTime}, 138 equalTo: []TimeTZ{hawaiiTime}, 139 roundedToSecond: hawaiiTime, 140 }, 141 { 142 t: minTime, 143 toTime: time.Date(1970, 1, 1, 0, 0, 0, 0, timeutil.FixedOffsetTimeZoneToLocation(15*60*60+59*60, "TimeTZ")), 144 toDuration: time.Duration(-(15*60*60 + 59*60)) * time.Second, 145 largerThan: []TimeTZ{}, 146 smallerThan: []TimeTZ{maxTime, utcTime, sydneyTime, hawaiiTime}, 147 equalTo: []TimeTZ{minTime}, 148 roundedToSecond: minTime, 149 }, 150 { 151 t: maxTime, 152 toTime: time.Date(1970, 1, 2, 0, 0, 0, 0, timeutil.FixedOffsetTimeZoneToLocation(-(15*60*60+59*60), "TimeTZ")), 153 toDuration: time.Duration(24*60*60+15*60*60+59*60) * time.Second, 154 largerThan: []TimeTZ{minTime, utcTime, sydneyTime, hawaiiTime}, 155 smallerThan: []TimeTZ{}, 156 equalTo: []TimeTZ{maxTime}, 157 roundedToSecond: maxTime, 158 }, 159 } 160 for i, tc := range testCases { 161 t.Run(fmt.Sprintf("#%d %s", i, tc.t.String()), func(t *testing.T) { 162 assert.Equal(t, tc.toTime, tc.t.ToTime()) 163 assert.Equal(t, tc.roundedToSecond, tc.t.Round(time.Second)) 164 assert.Equal(t, tc.toDuration, tc.t.ToDuration()) 165 166 for _, largerThan := range tc.largerThan { 167 assert.True(t, tc.t.After(largerThan), "%s > %s", tc.t.String(), largerThan) 168 } 169 170 for _, smallerThan := range tc.smallerThan { 171 assert.True(t, tc.t.Before(smallerThan), "%s < %s", tc.t.String(), smallerThan) 172 } 173 174 for _, equalTo := range tc.equalTo { 175 assert.True(t, tc.t.Equal(equalTo), "%s = %s", tc.t.String(), equalTo) 176 } 177 }) 178 } 179 } 180 181 func TestParseTimeTZ(t *testing.T) { 182 testCases := []struct { 183 str string 184 precision time.Duration 185 186 expected TimeTZ 187 expectedError bool 188 }{ 189 {str: "01:02:03", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 190 {str: "01:02:03.000123", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 123), 0)}, 191 {str: "01:24:00", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 24, 0, 0), 0)}, 192 {str: "01:03:24", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 3, 24, 0), 0)}, 193 {str: "1970-01-01 01:02:03", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 194 {str: "1970-01-01T01:02:03", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 195 {str: "1970-01-01T01:02:03", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 196 {str: "0000-01-01 01:02:03", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 197 {str: "01:02:03.000123", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 123), 0)}, 198 {str: "4:5:6", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(4, 5, 6, 0), 0)}, 199 {str: "24:00", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, 0)}, 200 {str: "24:00:00", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, 0)}, 201 {str: "24:00:00.000", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, 0)}, 202 {str: "24:00:00.000000", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, 0)}, 203 {str: "01:02:03+13", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), -13*60*60)}, 204 {str: "01:02:03-13", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 13*60*60)}, 205 {str: "01:02:03+7", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), -7*60*60)}, 206 {str: "01:02:03-0730", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 7*60*60+30*60)}, 207 {str: "24:00+3", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, -3*60*60)}, 208 {str: "24:00:00+4", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, -4*60*60)}, 209 {str: "24:00:00.000-5", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, 5*60*60)}, 210 {str: "24:00:00.000000+6", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, -6*60*60)}, 211 {str: "24:00:00.000000+6", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, -6*60*60)}, 212 {str: "1970-01-01T24:00:00.000000+6", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.Time2400, -6*60*60)}, 213 {str: "00:00-1559", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(0, 0, 0, 0), MaxTimeTZOffsetSecs)}, 214 {str: "00:00+1559", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(0, 0, 0, 0), MinTimeTZOffsetSecs)}, 215 {str: " 01:03:24", precision: time.Microsecond, expected: MakeTimeTZ(timeofday.New(1, 3, 24, 0), 0)}, 216 217 {str: "01:02:03.000123", precision: time.Millisecond, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 0), 0)}, 218 {str: "01:02:03.000123", precision: time.Millisecond / 10, expected: MakeTimeTZ(timeofday.New(1, 2, 3, 100), 0)}, 219 {str: "01:02:03.500123", precision: time.Second, expected: MakeTimeTZ(timeofday.New(1, 2, 4, 0), 0)}, 220 221 {str: "", expectedError: true}, 222 {str: "foo", expectedError: true}, 223 {str: "01", expectedError: true}, 224 {str: "01:00=wat", expectedError: true}, 225 {str: "00:00-1600", expectedError: true}, 226 {str: "00:00+1600", expectedError: true}, 227 {str: "00:00+24:00", expectedError: true}, 228 {str: "1970-01-01 00:00+24:00", expectedError: true}, 229 {str: "2010-09-28", expectedError: true}, 230 } 231 for i, tc := range testCases { 232 t.Run(fmt.Sprintf("#%d: %s", i, tc.str), func(t *testing.T) { 233 actual, err := ParseTimeTZ(timeutil.Now(), tc.str, tc.precision) 234 if tc.expectedError { 235 assert.Error(t, err) 236 } else { 237 assert.NoError(t, err) 238 assert.Equal(t, tc.expected, actual) 239 } 240 }) 241 } 242 }