github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/interval_test.go (about) 1 // Copyright 2017 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 tree 12 13 import ( 14 "testing" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/types" 17 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 18 ) 19 20 var ( 21 dayToHourITM = types.IntervalTypeMetadata{ 22 DurationField: types.IntervalDurationField{ 23 FromDurationType: types.IntervalDurationType_DAY, 24 DurationType: types.IntervalDurationType_HOUR, 25 }, 26 } 27 minuteToSecondITM = types.IntervalTypeMetadata{ 28 DurationField: types.IntervalDurationField{ 29 FromDurationType: types.IntervalDurationType_MINUTE, 30 DurationType: types.IntervalDurationType_SECOND, 31 }, 32 } 33 ) 34 35 func TestValidSQLIntervalSyntax(t *testing.T) { 36 defer leaktest.AfterTest(t)() 37 testData := []struct { 38 input string 39 itm types.IntervalTypeMetadata 40 output string 41 }{ 42 {`0:1`, types.IntervalTypeMetadata{}, `00:01:00`}, 43 {`0:1.0`, types.IntervalTypeMetadata{}, `00:00:01`}, 44 {`1`, types.IntervalTypeMetadata{}, `00:00:01`}, 45 {`1.0:0:0`, types.IntervalTypeMetadata{}, `1 day`}, 46 {`1.2`, types.IntervalTypeMetadata{}, `00:00:01.2`}, 47 {`:3:4`, types.IntervalTypeMetadata{}, `03:04:00`}, 48 {`:-3:4`, types.IntervalTypeMetadata{}, `-03:04:00`}, 49 {`:3:4.1`, types.IntervalTypeMetadata{}, `00:03:04.1`}, 50 {`1.2:1:1.2`, types.IntervalTypeMetadata{}, `1 day 04:49:01.2`}, 51 {`1.2:+1:1.2`, types.IntervalTypeMetadata{}, `1 day 04:49:01.2`}, 52 {`1.2:-1:1.2`, types.IntervalTypeMetadata{}, `1 day 04:46:58.8`}, 53 {`1:0:0`, types.IntervalTypeMetadata{}, `01:00:00`}, 54 {`1:1.2`, types.IntervalTypeMetadata{}, `00:01:01.2`}, 55 {`1:2`, types.IntervalTypeMetadata{}, `01:02:00`}, 56 {`1:2.3`, types.IntervalTypeMetadata{}, `00:01:02.3`}, 57 {`1:2:3`, types.IntervalTypeMetadata{}, `01:02:03`}, 58 {`1234:56:54`, types.IntervalTypeMetadata{}, `1234:56:54`}, 59 {`-0:1`, types.IntervalTypeMetadata{}, `-00:01:00`}, 60 {`-0:1.0`, types.IntervalTypeMetadata{}, `-00:00:01`}, 61 {`-1`, types.IntervalTypeMetadata{}, `-00:00:01`}, 62 {`-1.2`, types.IntervalTypeMetadata{}, `-00:00:01.2`}, 63 {`-1:0:0`, types.IntervalTypeMetadata{}, `-01:00:00`}, 64 {`-1:1.2`, types.IntervalTypeMetadata{}, `-00:01:01.2`}, 65 {`-1:2`, types.IntervalTypeMetadata{}, `-01:02:00`}, 66 {`-1:2.3`, types.IntervalTypeMetadata{}, `-00:01:02.3`}, 67 {`-1:2:3`, types.IntervalTypeMetadata{}, `-01:02:03`}, 68 {`-1234:56:54`, types.IntervalTypeMetadata{}, `-1234:56:54`}, 69 {`1-2`, types.IntervalTypeMetadata{}, `1 year 2 mons`}, 70 {`-1-2`, types.IntervalTypeMetadata{}, `-1 years -2 mons`}, 71 {`1-2 3`, types.IntervalTypeMetadata{}, `1 year 2 mons 00:00:03`}, 72 {`1-2 3`, types.IntervalTypeMetadata{ 73 DurationField: types.IntervalDurationField{ 74 DurationType: types.IntervalDurationType_YEAR, 75 }, 76 }, `4 years 2 mons`}, // this gets truncated later to 4 years 77 {`1-2 3`, types.IntervalTypeMetadata{ 78 DurationField: types.IntervalDurationField{ 79 DurationType: types.IntervalDurationType_MONTH, 80 }, 81 }, `1 year 5 mons`}, 82 {`1-2 3`, types.IntervalTypeMetadata{ 83 DurationField: types.IntervalDurationField{ 84 DurationType: types.IntervalDurationType_DAY, 85 }, 86 }, `1 year 2 mons 3 days`}, 87 {`1-2 3`, types.IntervalTypeMetadata{ 88 DurationField: types.IntervalDurationField{ 89 DurationType: types.IntervalDurationType_HOUR, 90 }, 91 }, `1 year 2 mons 03:00:00`}, 92 {`1-2 3`, types.IntervalTypeMetadata{ 93 DurationField: types.IntervalDurationField{ 94 DurationType: types.IntervalDurationType_MINUTE, 95 }, 96 }, `1 year 2 mons 00:03:00`}, 97 {`1-2 3`, types.IntervalTypeMetadata{ 98 DurationField: types.IntervalDurationField{ 99 DurationType: types.IntervalDurationType_SECOND, 100 }, 101 }, `1 year 2 mons 00:00:03`}, 102 {`1-2 -3`, types.IntervalTypeMetadata{}, `1 year 2 mons -00:00:03`}, 103 {`-1-2 -3`, types.IntervalTypeMetadata{}, `-1 years -2 mons -00:00:03`}, 104 {`2 4:08`, types.IntervalTypeMetadata{}, `2 days 04:08:00`}, 105 {`2.5 4:08`, types.IntervalTypeMetadata{}, `2 days 16:08:00`}, 106 {`-2 4:08`, types.IntervalTypeMetadata{}, `-2 days +04:08:00`}, 107 {`2 -4:08`, types.IntervalTypeMetadata{}, `2 days -04:08:00`}, 108 {`2 -4:08.1234`, types.IntervalTypeMetadata{}, `2 days -00:04:08.1234`}, 109 {`2 -4:08.1234`, minuteToSecondITM, `2 days -00:04:08.1234`}, 110 {`2 -4:08`, minuteToSecondITM, `2 days -00:04:08`}, 111 {`1-2 4:08`, types.IntervalTypeMetadata{}, `1 year 2 mons 04:08:00`}, 112 {`1-2 3 4:08`, types.IntervalTypeMetadata{}, `1 year 2 mons 3 days 04:08:00`}, 113 {`1-2 3 4:08:05`, types.IntervalTypeMetadata{}, `1 year 2 mons 3 days 04:08:05`}, 114 {`1-2 4:08:23`, types.IntervalTypeMetadata{}, `1 year 2 mons 04:08:23`}, 115 {`1- 4:08:23`, types.IntervalTypeMetadata{}, `1 year 04:08:23`}, 116 {`0-2 3 4:08`, types.IntervalTypeMetadata{}, `2 mons 3 days 04:08:00`}, 117 {`1- 3 4:08:`, types.IntervalTypeMetadata{}, `1 year 3 days 04:08:00`}, 118 {`-1- 3 4:08:`, types.IntervalTypeMetadata{}, `-1 years 3 days +04:08:00`}, 119 {`0- 3 4:08`, types.IntervalTypeMetadata{}, `3 days 04:08:00`}, 120 {`-0- 3 4:08`, types.IntervalTypeMetadata{}, `3 days 04:08:00`}, 121 {`-0- -0 4:08`, types.IntervalTypeMetadata{}, `04:08:00`}, 122 {`-0- -0 0:0`, types.IntervalTypeMetadata{}, `00:00:00`}, 123 {`-0- -0 -0:0`, types.IntervalTypeMetadata{}, `00:00:00`}, 124 {`-0- -3 -4:08`, types.IntervalTypeMetadata{}, `-3 days -04:08:00`}, 125 {`0- 3 4::08`, types.IntervalTypeMetadata{}, `3 days 04:00:08`}, 126 {` 0- 3 4::08 `, types.IntervalTypeMetadata{}, `3 days 04:00:08`}, 127 {`2 4:08:23`, types.IntervalTypeMetadata{}, `2 days 04:08:23`}, 128 {`1-2 3 4:08:23`, types.IntervalTypeMetadata{}, `1 year 2 mons 3 days 04:08:23`}, 129 {`1-`, types.IntervalTypeMetadata{}, `1 year`}, 130 {`1- 2`, types.IntervalTypeMetadata{}, `1 year 00:00:02`}, 131 {`2 3:`, types.IntervalTypeMetadata{}, `2 days 03:00:00`}, 132 {`2 3:4:`, types.IntervalTypeMetadata{}, `2 days 03:04:00`}, 133 {`1- 3:`, types.IntervalTypeMetadata{}, `1 year 03:00:00`}, 134 {`1- 3:4`, types.IntervalTypeMetadata{}, `1 year 03:04:00`}, 135 136 {`2 3`, dayToHourITM, `2 days 03:00:00`}, 137 {`-2 -3`, dayToHourITM, `-2 days -03:00:00`}, 138 {`-2 3`, dayToHourITM, `-2 days +03:00:00`}, 139 {`2 -3`, dayToHourITM, `2 days -03:00:00`}, 140 {`1-2 3`, dayToHourITM, `1 year 2 mons 03:00:00`}, 141 {`-1-2 -3`, dayToHourITM, `-1 years -2 mons -03:00:00`}, 142 {`-1-2 3`, dayToHourITM, `-1 years -2 mons +03:00:00`}, 143 {`1-2 -3`, dayToHourITM, `1 year 2 mons -03:00:00`}, 144 } 145 for _, test := range testData { 146 t.Run(test.input, func(t *testing.T) { 147 dur, err := sqlStdToDuration(test.input, test.itm) 148 if err != nil { 149 t.Fatalf("%q: %v", test.input, err) 150 } 151 s := dur.String() 152 if s != test.output { 153 t.Fatalf(`%q: got "%s", expected "%s"`, test.input, s, test.output) 154 } 155 156 dur2, err := parseDuration(s, test.itm) 157 if err != nil { 158 t.Fatalf(`%q: repr "%s" is not parsable: %v`, test.input, s, err) 159 } 160 s2 := dur2.String() 161 if s2 != s { 162 t.Fatalf(`%q: repr "%s" does not round-trip, got "%s" instead`, 163 test.input, s, s2) 164 } 165 166 // Test that a Datum recognizes the format. 167 di, err := parseDInterval(test.input, test.itm) 168 if err != nil { 169 t.Fatalf(`%q: unrecognized as datum: %v`, test.input, err) 170 } 171 s3 := di.Duration.String() 172 if s3 != test.output { 173 t.Fatalf(`%q: as datum, got "%s", expected "%s"`, test.input, s3, test.output) 174 } 175 }) 176 } 177 } 178 179 func TestInvalidSQLIntervalSyntax(t *testing.T) { 180 defer leaktest.AfterTest(t)() 181 testData := []struct { 182 input string 183 output string 184 error string 185 }{ 186 {`+`, ``, `invalid input syntax for type interval +`}, 187 {`++`, ``, `invalid input syntax for type interval ++`}, 188 {`--`, ``, `invalid input syntax for type interval --`}, 189 {`{1,2}`, ``, `invalid input syntax for type interval {1,2}`}, 190 {`0.000,0`, ``, `invalid input syntax for type interval 0.000,0`}, 191 {`0,0`, ``, `invalid input syntax for type interval 0,0`}, 192 {`2 3`, ``, `invalid input syntax for type interval 2 3`}, 193 {`-2 3`, ``, `invalid input syntax for type interval -2 3`}, 194 {`-2 -3`, ``, `invalid input syntax for type interval -2 -3`}, 195 {`2 -3`, ``, `invalid input syntax for type interval 2 -3`}, 196 {`0:-1`, ``, `invalid input syntax for type interval 0:-1`}, 197 {`0:0:-1`, ``, `invalid input syntax for type interval 0:0:-1`}, 198 {`1.0:0:-1`, ``, `invalid input syntax for type interval 1.0:0:-1`}, 199 {`0:-1:0`, ``, `invalid input syntax for type interval 0:-1:0`}, 200 {`0:-1:-1`, ``, `invalid input syntax for type interval 0:-1:-1`}, 201 {`-1.0:0:0`, ``, `invalid input syntax for type interval -1.0:0:0`}, 202 {`-:0:0`, ``, `invalid input syntax for type interval -:0:0`}, 203 } 204 for i, test := range testData { 205 dur, err := sqlStdToDuration(test.input, types.IntervalTypeMetadata{}) 206 if err != nil { 207 if test.error != "" { 208 if err.Error() != test.error { 209 t.Errorf(`%d: %q: got error "%v", expected "%s"`, i, test.input, err, test.error) 210 } 211 } else { 212 t.Errorf("%d: %q: %v", i, test.input, err) 213 } 214 continue 215 } else { 216 if test.error != "" { 217 t.Errorf(`%d: %q: expected error "%q"`, i, test.input, test.error) 218 continue 219 } 220 } 221 s := dur.String() 222 if s != test.output { 223 t.Errorf(`%d: %q: got "%s", expected "%s"`, i, test.input, s, test.output) 224 continue 225 } 226 227 dur2, err := parseDuration(s, types.IntervalTypeMetadata{}) 228 if err != nil { 229 t.Errorf(`%d: %q: repr "%s" is not parsable: %v`, i, test.input, s, err) 230 continue 231 } 232 s2 := dur2.String() 233 if s2 != s { 234 t.Errorf(`%d: %q: repr "%s" does not round-trip, got "%s" instead`, 235 i, test.input, s, s2) 236 } 237 238 // Test that a Datum recognizes the format. 239 di, err := parseDInterval(test.input, types.IntervalTypeMetadata{}) 240 if err != nil { 241 t.Errorf(`%d: %q: unrecognized as datum: %v`, i, test.input, err) 242 continue 243 } 244 s3 := di.Duration.String() 245 if s3 != test.output { 246 t.Errorf(`%d: %q: as datum, got "%s", expected "%s"`, i, test.input, s3, test.output) 247 } 248 } 249 } 250 251 func TestPGIntervalSyntax(t *testing.T) { 252 defer leaktest.AfterTest(t)() 253 testData := []struct { 254 input string 255 itm types.IntervalTypeMetadata 256 output string 257 error string 258 }{ 259 {``, types.IntervalTypeMetadata{}, ``, `interval: invalid input syntax: ""`}, 260 {`-`, types.IntervalTypeMetadata{}, ``, `interval: missing unit at position 1: "-"`}, 261 {`123`, types.IntervalTypeMetadata{}, ``, `interval: missing unit at position 3: "123"`}, 262 {`123blah`, types.IntervalTypeMetadata{}, ``, `interval: unknown unit "blah" in duration "123blah"`}, 263 264 {`500nanoseconds`, types.IntervalTypeMetadata{}, ``, `interval: unknown unit "nanoseconds" in duration "500nanoseconds"`}, 265 {`500ns`, types.IntervalTypeMetadata{}, ``, `interval: unknown unit "ns" in duration "500ns"`}, 266 267 // ns/us boundary 268 {`.5us`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 269 {`-0.499us`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 270 {`-0.5us`, types.IntervalTypeMetadata{}, `-00:00:00.000001`, ``}, 271 {`0.000000499s`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 272 {`0.0000005s`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 273 {`-0.000000499s`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 274 {`-0.0000005s`, types.IntervalTypeMetadata{}, `-00:00:00.000001`, ``}, 275 276 {`1.2 microsecond`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 277 {`1.2microseconds`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 278 {`1.2us`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 279 // µ = U+00B5 = micro symbol 280 // μ = U+03BC = Greek letter mu 281 {`1.2µs`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 282 {`1.2μs`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 283 {`1.2usec`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 284 {`1.2usecs`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 285 {`1.2usecond`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 286 {`1.2useconds`, types.IntervalTypeMetadata{}, `00:00:00.000001`, ``}, 287 {`0.23us`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 288 {`-0.23us`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 289 {`0.2346us`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 290 {`-1.2us`, types.IntervalTypeMetadata{}, `-00:00:00.000001`, ``}, 291 292 {`1.2millisecond`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 293 {`1.2milliseconds`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 294 {`1.2ms`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 295 {`1.2msec`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 296 {`1.2msecs`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 297 {`1.2msecond`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 298 {`1.2mseconds`, types.IntervalTypeMetadata{}, `00:00:00.0012`, ``}, 299 {`0.2304506ms`, types.IntervalTypeMetadata{}, `00:00:00.00023`, ``}, 300 {`0.0002304506ms`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 301 302 {`1.2second`, types.IntervalTypeMetadata{}, `00:00:01.2`, ``}, 303 {`1.2seconds`, types.IntervalTypeMetadata{}, `00:00:01.2`, ``}, 304 {`1.2s`, types.IntervalTypeMetadata{}, `00:00:01.2`, ``}, 305 {`1.2sec`, types.IntervalTypeMetadata{}, `00:00:01.2`, ``}, 306 {`1.2secs`, types.IntervalTypeMetadata{}, `00:00:01.2`, ``}, 307 {`0.2304506708s`, types.IntervalTypeMetadata{}, `00:00:00.230451`, ``}, 308 {`0.0002304506708s`, types.IntervalTypeMetadata{}, `00:00:00.00023`, ``}, 309 {`0.0000002304506s`, types.IntervalTypeMetadata{}, `00:00:00`, ``}, 310 {`75.5s`, types.IntervalTypeMetadata{}, `00:01:15.5`, ``}, 311 {`3675.5s`, types.IntervalTypeMetadata{}, `01:01:15.5`, ``}, 312 {`86475.5s`, types.IntervalTypeMetadata{}, `24:01:15.5`, ``}, 313 {`86400s -60000ms 100us`, types.IntervalTypeMetadata{}, `23:59:00.0001`, ``}, 314 315 {`1.2minute`, types.IntervalTypeMetadata{}, `00:01:12`, ``}, 316 {`1.2minutes`, types.IntervalTypeMetadata{}, `00:01:12`, ``}, 317 {`1.2m`, types.IntervalTypeMetadata{}, `00:01:12`, ``}, 318 {`1.2min`, types.IntervalTypeMetadata{}, `00:01:12`, ``}, 319 {`1.2mins`, types.IntervalTypeMetadata{}, `00:01:12`, ``}, 320 {`1.2m 8s`, types.IntervalTypeMetadata{}, `00:01:20`, ``}, 321 {`0.5m`, types.IntervalTypeMetadata{}, `00:00:30`, ``}, 322 {`120.5m`, types.IntervalTypeMetadata{}, `02:00:30`, ``}, 323 {`0.23045067089m`, types.IntervalTypeMetadata{}, `00:00:13.82704`, ``}, 324 {`-0.23045067089m`, types.IntervalTypeMetadata{}, `-00:00:13.82704`, ``}, 325 326 {`1.2hour`, types.IntervalTypeMetadata{}, `01:12:00`, ``}, 327 {`1.2hours`, types.IntervalTypeMetadata{}, `01:12:00`, ``}, 328 {`1.2h`, types.IntervalTypeMetadata{}, `01:12:00`, ``}, 329 {`1.2hr`, types.IntervalTypeMetadata{}, `01:12:00`, ``}, 330 {`1.2hrs`, types.IntervalTypeMetadata{}, `01:12:00`, ``}, 331 {`1.2h 8m`, types.IntervalTypeMetadata{}, `01:20:00`, ``}, 332 {`0.5h`, types.IntervalTypeMetadata{}, `00:30:00`, ``}, 333 {`25.5h`, types.IntervalTypeMetadata{}, `25:30:00`, ``}, 334 {`0.23045067089h`, types.IntervalTypeMetadata{}, `00:13:49.622415`, ``}, 335 {`-0.23045067089h`, types.IntervalTypeMetadata{}, `-00:13:49.622415`, ``}, 336 337 {`1 day`, types.IntervalTypeMetadata{}, `1 day`, ``}, 338 {`1 days`, types.IntervalTypeMetadata{}, `1 day`, ``}, 339 {`1d`, types.IntervalTypeMetadata{}, `1 day`, ``}, 340 {`1.1d`, types.IntervalTypeMetadata{}, `1 day 02:24:00`, ``}, 341 {`1.2d`, types.IntervalTypeMetadata{}, `1 day 04:48:00`, ``}, 342 {`1.11d`, types.IntervalTypeMetadata{}, `1 day 02:38:24`, ``}, 343 {`1.111d`, types.IntervalTypeMetadata{}, `1 day 02:39:50.4`, ``}, 344 {`1.1111d`, types.IntervalTypeMetadata{}, `1 day 02:39:59.04`, ``}, 345 {`60d 25h`, types.IntervalTypeMetadata{}, `60 days 25:00:00`, ``}, 346 {`-9223372036854775808d`, types.IntervalTypeMetadata{}, `-9223372036854775808 days`, ``}, 347 {`9223372036854775807d`, types.IntervalTypeMetadata{}, `9223372036854775807 days`, ``}, 348 349 {`1week`, types.IntervalTypeMetadata{}, `7 days`, ``}, 350 {`1weeks`, types.IntervalTypeMetadata{}, `7 days`, ``}, 351 {`1w`, types.IntervalTypeMetadata{}, `7 days`, ``}, 352 {`1.1w`, types.IntervalTypeMetadata{}, `7 days 16:48:00`, ``}, 353 {`1.5w`, types.IntervalTypeMetadata{}, `10 days 12:00:00`, ``}, 354 {`1w -1d`, types.IntervalTypeMetadata{}, `6 days`, ``}, 355 356 {`1month`, types.IntervalTypeMetadata{}, `1 mon`, ``}, 357 {`1months`, types.IntervalTypeMetadata{}, `1 mon`, ``}, 358 {`1mons`, types.IntervalTypeMetadata{}, `1 mon`, ``}, 359 {`1.5mon`, types.IntervalTypeMetadata{}, `1 mon 15 days`, ``}, 360 {`1 mon 2 week`, types.IntervalTypeMetadata{}, `1 mon 14 days`, ``}, 361 {`1.1mon`, types.IntervalTypeMetadata{}, `1 mon 3 days`, ``}, 362 {`1.2mon`, types.IntervalTypeMetadata{}, `1 mon 6 days`, ``}, 363 {`1.11mon`, types.IntervalTypeMetadata{}, `1 mon 3 days 07:12:00`, ``}, 364 {`-9223372036854775808mon`, types.IntervalTypeMetadata{}, `-768614336404564650 years -8 mons`, ``}, 365 {`9223372036854775807mon`, types.IntervalTypeMetadata{}, `768614336404564650 years 7 mons`, ``}, 366 367 {`1year`, types.IntervalTypeMetadata{}, `1 year`, ``}, 368 {`1years`, types.IntervalTypeMetadata{}, `1 year`, ``}, 369 {`1y`, types.IntervalTypeMetadata{}, `1 year`, ``}, 370 {`1yr`, types.IntervalTypeMetadata{}, `1 year`, ``}, 371 {`1yrs`, types.IntervalTypeMetadata{}, `1 year`, ``}, 372 {`1.5y`, types.IntervalTypeMetadata{}, `1 year 6 mons`, ``}, 373 {`1.1y`, types.IntervalTypeMetadata{}, `1 year 1 mon 6 days`, ``}, 374 {`1.11y`, types.IntervalTypeMetadata{}, `1 year 1 mon 9 days 14:24:00`, ``}, 375 376 // Mixed unit/HH:MM:SS formats 377 {`1:2:3`, types.IntervalTypeMetadata{}, `01:02:03`, ``}, 378 {`-1:2:3`, types.IntervalTypeMetadata{}, `-01:02:03`, ``}, 379 {`-0:2:3`, types.IntervalTypeMetadata{}, `-00:02:03`, ``}, 380 {`+0:2:3`, types.IntervalTypeMetadata{}, `00:02:03`, ``}, 381 {`1 day 12:30`, types.IntervalTypeMetadata{}, `1 day 12:30:00`, ``}, 382 {`12:30 1 day`, types.IntervalTypeMetadata{}, `1 day 12:30:00`, ``}, 383 {`1 day -12:30`, types.IntervalTypeMetadata{}, `1 day -12:30:00`, ``}, 384 {`1 day -00:30`, types.IntervalTypeMetadata{}, `1 day -00:30:00`, ``}, 385 {`1 day -00:00:30`, types.IntervalTypeMetadata{}, `1 day -00:00:30`, ``}, 386 {`-1 day +00:00:30`, types.IntervalTypeMetadata{}, `-1 days +00:00:30`, ``}, 387 {`2 days -4:08.1234`, types.IntervalTypeMetadata{}, `2 days -00:04:08.1234`, ``}, 388 {`2 days -4:08`, minuteToSecondITM, `2 days -00:04:08`, ``}, 389 {`1 day 12:30.5`, types.IntervalTypeMetadata{}, `1 day 00:12:30.5`, ``}, 390 {`1 day 12:30:40`, types.IntervalTypeMetadata{}, `1 day 12:30:40`, ``}, 391 {`1 day 12:30:40.5`, types.IntervalTypeMetadata{}, `1 day 12:30:40.5`, ``}, 392 {`1 day 12:30:40.500500001`, types.IntervalTypeMetadata{}, `1 day 12:30:40.5005`, ``}, 393 394 // Regressions 395 396 // This was 1ns off due to float rounding. 397 {`50 years 6 mons 75 days 1572897:25:58.535696141`, types.IntervalTypeMetadata{}, `50 years 6 mons 75 days 1572897:25:58.535696`, ``}, 398 } 399 for _, test := range testData { 400 t.Run(test.input, func(t *testing.T) { 401 dur, err := parseDuration(test.input, test.itm) 402 if err != nil { 403 if test.error != "" { 404 if err.Error() != test.error { 405 t.Fatalf(`%q: got error "%v", expected "%s"`, test.input, err, test.error) 406 } 407 } else { 408 t.Fatalf("%q: %v", test.input, err) 409 } 410 return 411 } 412 if test.error != "" { 413 t.Fatalf(`%q: expected error "%q"`, test.input, test.error) 414 } 415 s := dur.String() 416 if s != test.output { 417 t.Fatalf(`%q: got "%s", expected "%s"`, test.input, s, test.output) 418 } 419 420 dur2, err := parseDuration(s, test.itm) 421 if err != nil { 422 t.Fatalf(`%q: repr "%s" is not parsable: %v`, test.input, s, err) 423 } 424 s2 := dur2.String() 425 if s2 != s { 426 t.Fatalf(`%q: repr "%s" does not round-trip, got "%s" instead`, test.input, s, s2) 427 } 428 429 // Test that a Datum recognizes the format. 430 di, err := parseDInterval(test.input, test.itm) 431 if err != nil { 432 t.Fatalf(`%q: unrecognized as datum: %v`, test.input, err) 433 } 434 s3 := di.Duration.String() 435 if s3 != test.output { 436 t.Fatalf(`%q: as datum, got "%s", expected "%s"`, test.input, s3, test.output) 437 } 438 }) 439 } 440 }