github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/function/builtin/binary/str_to_date_test.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package binary 16 17 import ( 18 "context" 19 "github.com/matrixorigin/matrixone/pkg/container/vector" 20 "github.com/matrixorigin/matrixone/pkg/testutil" 21 "github.com/smartystreets/goconvey/convey" 22 "github.com/stretchr/testify/require" 23 "testing" 24 ) 25 26 func TestStrToDate(t *testing.T) { 27 convey.Convey("Test01 STR_TO_DATE() with multi line", t, func() { 28 cases := []struct { 29 datestr string 30 format string 31 expect string 32 }{ 33 { 34 datestr: "04/31/2004", 35 expect: "2004-04-31", 36 }, 37 { 38 datestr: "05/31/2012", 39 expect: "2012-05-31", 40 }, 41 { 42 datestr: "04/23/2009", 43 expect: "2009-04-23", 44 }, 45 { 46 datestr: "01/31/2004", 47 expect: "2004-01-31", 48 }, 49 { 50 datestr: "07/03/2018", 51 expect: "2018-07-03", 52 }, 53 { 54 datestr: "08/25/2014", 55 expect: "2014-08-25", 56 }, 57 { 58 datestr: "06/30/2022", 59 expect: "2022-06-30", 60 }, 61 } 62 63 var datestrs []string 64 var expects []string 65 for _, c := range cases { 66 datestrs = append(datestrs, c.datestr) 67 expects = append(expects, c.expect) 68 } 69 70 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 71 format := `%m/%d/%Y` 72 formatVector := testutil.MakeScalarVarchar(format, 11) 73 expectVector := testutil.MakeDateVector(expects, []uint64{0}) 74 75 proc := testutil.NewProc() 76 result, err := StrToDate([]*vector.Vector{datestrVector, formatVector}, proc) 77 if err != nil { 78 t.Fatal(err) 79 } 80 convey.So(err, convey.ShouldBeNil) 81 compare := testutil.CompareVectors(expectVector, result) 82 convey.So(compare, convey.ShouldBeTrue) 83 }) 84 } 85 86 func TestStrToDate2(t *testing.T) { 87 convey.Convey("Test02 STR_TO_DATE() with multi line", t, func() { 88 cases := []struct { 89 datestr string 90 format string 91 expect string 92 }{ 93 { 94 datestr: "May 1, 2013", 95 expect: "2013-05-01", 96 }, 97 { 98 datestr: "Feb 28, 2022", 99 expect: "2022-02-28", 100 }, 101 { 102 datestr: "Jul 20, 2022", 103 expect: "2022-07-20", 104 }, 105 { 106 datestr: "Aug 1, 2013", 107 expect: "2013-08-01", 108 }, 109 { 110 datestr: "Nov 28, 2022", 111 expect: "2022-11-28", 112 }, 113 { 114 datestr: "Dec 20, 2022", 115 expect: "2022-12-20", 116 }, 117 } 118 119 var datestrs []string 120 var expects []string 121 for _, c := range cases { 122 datestrs = append(datestrs, c.datestr) 123 expects = append(expects, c.expect) 124 } 125 126 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 127 format := `%b %d,%Y` 128 formatVector := testutil.MakeScalarVarchar(format, 11) 129 expectVector := testutil.MakeDateVector(expects, nil) 130 131 proc := testutil.NewProc() 132 result, err := StrToDate([]*vector.Vector{datestrVector, formatVector}, proc) 133 if err != nil { 134 t.Fatal(err) 135 } 136 convey.So(err, convey.ShouldBeNil) 137 compare := testutil.CompareVectors(expectVector, result) 138 convey.So(compare, convey.ShouldBeTrue) 139 }) 140 } 141 142 func TestStrToTime(t *testing.T) { 143 convey.Convey("Test03 STR_TO_DATE() with multi line", t, func() { 144 cases := []struct { 145 datestr string 146 format string 147 expect string 148 }{ 149 { 150 datestr: "09:30:17", 151 expect: "09:30:17", 152 }, 153 { 154 datestr: "11:30:17", 155 expect: "11:30:17", 156 }, 157 { 158 datestr: "01:30:17", 159 expect: "01:30:17", 160 }, 161 { 162 datestr: "12:30:17", 163 expect: "00:30:17", 164 }, 165 { 166 datestr: "05:30:17", 167 expect: "05:30:17", 168 }, 169 { 170 datestr: "09:30:17", 171 expect: "09:30:17", 172 }, 173 { 174 datestr: "04:30:17", 175 expect: "04:30:17", 176 }, 177 } 178 179 var datestrs []string 180 var expects []string 181 for _, c := range cases { 182 datestrs = append(datestrs, c.datestr) 183 expects = append(expects, c.expect) 184 } 185 186 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 187 format := `%h:%i:%s` 188 formatVector := testutil.MakeScalarVarchar(format, 11) 189 expectVector := testutil.MakeTimeVector(expects, nil) 190 191 proc := testutil.NewProc() 192 result, err := StrToTime([]*vector.Vector{datestrVector, formatVector}, proc) 193 if err != nil { 194 t.Fatal(err) 195 } 196 convey.So(err, convey.ShouldBeNil) 197 compare := testutil.CompareVectors(expectVector, result) 198 convey.So(compare, convey.ShouldBeTrue) 199 }) 200 } 201 202 func TestStrToTime2(t *testing.T) { 203 convey.Convey("Test04 STR_TO_DATE() with multi line", t, func() { 204 cases := []struct { 205 datestr string 206 format string 207 expect string 208 }{ 209 { 210 datestr: "11:13:56", 211 expect: "11:13:56", 212 }, 213 { 214 datestr: "12:33:51", 215 expect: "00:33:51", 216 }, 217 { 218 datestr: "03:23:36", 219 expect: "03:23:36", 220 }, 221 { 222 datestr: "01:43:46", 223 expect: "01:43:46", 224 }, 225 { 226 datestr: "10:53:41", 227 expect: "10:53:41", 228 }, 229 { 230 datestr: "09:23:46", 231 expect: "09:23:46", 232 }, 233 } 234 235 var datestrs []string 236 var expects []string 237 for _, c := range cases { 238 datestrs = append(datestrs, c.datestr) 239 expects = append(expects, c.expect) 240 } 241 242 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 243 format := `%r` 244 formatVector := testutil.MakeScalarVarchar(format, 11) 245 expectVector := testutil.MakeTimeVector(expects, nil) 246 247 proc := testutil.NewProc() 248 result, err := StrToTime([]*vector.Vector{datestrVector, formatVector}, proc) 249 if err != nil { 250 t.Fatal(err) 251 } 252 convey.So(err, convey.ShouldBeNil) 253 compare := testutil.CompareVectors(expectVector, result) 254 convey.So(compare, convey.ShouldBeTrue) 255 }) 256 } 257 258 func TestStrToDateTime(t *testing.T) { 259 convey.Convey("Test05 STR_TO_DATE() with multi line", t, func() { 260 cases := []struct { 261 datestr string 262 format string 263 expect string 264 }{ 265 { 266 datestr: "2022-05-27 11:30:00", 267 expect: "2022-05-27 11:30:00", 268 }, 269 { 270 datestr: "2012-05-26 12:30:00", 271 expect: "2012-05-26 12:30:00", 272 }, 273 { 274 datestr: "2002-07-26 02:30:01", 275 expect: "2002-07-26 02:30:01", 276 }, 277 { 278 datestr: "2001-03-26 08:10:01", 279 expect: "2001-03-26 08:10:01", 280 }, 281 { 282 datestr: "2011-08-26 07:15:01", 283 expect: "2011-08-26 07:15:01", 284 }, 285 { 286 datestr: "2011-11-26 06:15:01", 287 expect: "2011-11-26 06:15:01", 288 }, 289 { 290 datestr: "2011-12-26 06:15:01", 291 expect: "2011-12-26 06:15:01", 292 }, 293 } 294 295 var datestrs []string 296 var expects []string 297 for _, c := range cases { 298 datestrs = append(datestrs, c.datestr) 299 expects = append(expects, c.expect) 300 } 301 302 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 303 format := `%Y-%m-%d %H:%i:%s` 304 formatVector := testutil.MakeScalarVarchar(format, 11) 305 expectVector := testutil.MakeDateTimeVector(expects, nil) 306 307 proc := testutil.NewProc() 308 result, err := StrToDateTime([]*vector.Vector{datestrVector, formatVector}, proc) 309 if err != nil { 310 t.Fatal(err) 311 } 312 convey.So(err, convey.ShouldBeNil) 313 compare := testutil.CompareVectors(expectVector, result) 314 convey.So(compare, convey.ShouldBeTrue) 315 }) 316 } 317 318 func TestStrToDateTime2(t *testing.T) { 319 convey.Convey("Test06 STR_TO_DATE() with multi line", t, func() { 320 cases := []struct { 321 datestr string 322 format string 323 expect string 324 }{ 325 { 326 datestr: "8:10:2.123456 13-01-02", 327 expect: "2013-01-02 08:10:02.123456", 328 }, 329 { 330 datestr: "12:19:2.123456 06-01-02", 331 expect: "2006-01-02 12:19:02.123456", 332 }, 333 { 334 datestr: "15:21:2.123456 22-01-02", 335 expect: "2022-01-02 15:21:02.123456", 336 }, 337 { 338 datestr: "11:11:2.123456 25-01-02", 339 expect: "2025-01-02 11:11:02.123456", 340 }, 341 { 342 datestr: "19:31:2.123456 11-01-02", 343 expect: "2011-01-02 19:31:02.123456", 344 }, 345 { 346 datestr: "1:41:2.123456 02-01-02", 347 expect: "2002-01-02 01:41:02.123456", 348 }, 349 } 350 351 var datestrs []string 352 var expects []string 353 for _, c := range cases { 354 datestrs = append(datestrs, c.datestr) 355 expects = append(expects, c.expect) 356 } 357 358 datestrVector := testutil.MakeVarcharVector(datestrs, nil) 359 format := `%H:%i:%S.%f %y-%m-%d` 360 formatVector := testutil.MakeScalarVarchar(format, 11) 361 expectVector := testutil.MakeDateTimeVector(expects, nil) 362 363 proc := testutil.NewProc() 364 result, err := StrToDateTime([]*vector.Vector{datestrVector, formatVector}, proc) 365 if err != nil { 366 t.Fatal(err) 367 } 368 convey.So(err, convey.ShouldBeNil) 369 compare := testutil.CompareVectors(expectVector, result) 370 convey.So(compare, convey.ShouldBeTrue) 371 }) 372 } 373 374 func Test_CoreStrToDate(t *testing.T) { 375 tests := []struct { 376 name string 377 date string 378 format string 379 expect GeneralTime 380 }{ 381 {`Test1`, `01,05,2013`, `%d,%m,%Y`, FromDate(2013, 5, 1, 0, 0, 0, 0)}, 382 {`Test2`, `5 12 2021`, `%m%d%Y`, FromDate(2021, 5, 12, 0, 0, 0, 0)}, 383 {`Test3`, `May 01, 2013`, `%M %d,%Y`, FromDate(2013, 5, 1, 0, 0, 0, 0)}, 384 {`Test4`, `a09:30:17`, `a%h:%i:%s`, FromDate(0, 0, 0, 9, 30, 17, 0)}, 385 {`Test5`, `09:30:17a`, `%h:%i:%s`, FromDate(0, 0, 0, 9, 30, 17, 0)}, 386 {`Test6`, `12:43:24`, `%h:%i:%s`, FromDate(0, 0, 0, 0, 43, 24, 0)}, 387 //{`Test7`, `abc`, `abc`, ZeroCoreTime}, 388 {`Test8`, `09`, `%m`, FromDate(0, 9, 0, 0, 0, 0, 0)}, 389 {`Test9`, `09`, `%s`, FromDate(0, 0, 0, 0, 0, 9, 0)}, 390 {`Test10`, `12:43:24 AM`, `%r`, FromDate(0, 0, 0, 0, 43, 24, 0)}, 391 {`Test11`, `12:43:24 PM`, `%r`, FromDate(0, 0, 0, 12, 43, 24, 0)}, 392 {`Test12`, `11:43:24 PM`, `%r`, FromDate(0, 0, 0, 23, 43, 24, 0)}, 393 {`Test13`, `00:12:13`, `%T`, FromDate(0, 0, 0, 0, 12, 13, 0)}, 394 {`Test14`, `23:59:59`, `%T`, FromDate(0, 0, 0, 23, 59, 59, 0)}, 395 //{`Test15`, `00/00/0000`, `%m/%d/%Y`, ZeroCoreTime}, 396 {`Test16`, `04/30/2004`, `%m/%d/%Y`, FromDate(2004, 4, 30, 0, 0, 0, 0)}, 397 {`Test17`, `15:35:00`, `%H:%i:%s`, FromDate(0, 0, 0, 15, 35, 0, 0)}, 398 {`Test18`, `Jul 17 33`, `%b %k %S`, FromDate(0, 7, 0, 17, 0, 33, 0)}, 399 {`Test19`, `2016-January:7 432101`, `%Y-%M:%l %f`, FromDate(2016, 1, 0, 7, 0, 0, 432101)}, 400 {`Test20`, `10:13 PM`, `%l:%i %p`, FromDate(0, 0, 0, 22, 13, 0, 0)}, 401 {`Test21`, `12:00:00 AM`, `%h:%i:%s %p`, FromDate(0, 0, 0, 0, 0, 0, 0)}, 402 {`Test22`, `12:00:00 PM`, `%h:%i:%s %p`, FromDate(0, 0, 0, 12, 0, 0, 0)}, 403 {`Test23`, `12:00:00 PM`, `%I:%i:%s %p`, FromDate(0, 0, 0, 12, 0, 0, 0)}, 404 {`Test24`, `1:00:00 PM`, `%h:%i:%s %p`, FromDate(0, 0, 0, 13, 0, 0, 0)}, 405 {`Test25`, `18/10/22`, `%y/%m/%d`, FromDate(2018, 10, 22, 0, 0, 0, 0)}, 406 {`Test26`, `8/10/22`, `%y/%m/%d`, FromDate(2008, 10, 22, 0, 0, 0, 0)}, 407 {`Test27`, `69/10/22`, `%y/%m/%d`, FromDate(2069, 10, 22, 0, 0, 0, 0)}, 408 {`Test28`, `70/10/22`, `%y/%m/%d`, FromDate(1970, 10, 22, 0, 0, 0, 0)}, 409 {`Test29`, `18/10/22`, `%Y/%m/%d`, FromDate(2018, 10, 22, 0, 0, 0, 0)}, 410 {`Test30`, `2018/10/22`, `%Y/%m/%d`, FromDate(2018, 10, 22, 0, 0, 0, 0)}, 411 {`Test31`, `8/10/22`, `%Y/%m/%d`, FromDate(2008, 10, 22, 0, 0, 0, 0)}, 412 {`Test32`, `69/10/22`, `%Y/%m/%d`, FromDate(2069, 10, 22, 0, 0, 0, 0)}, 413 {`Test33`, `70/10/22`, `%Y/%m/%d`, FromDate(1970, 10, 22, 0, 0, 0, 0)}, 414 {`Test34`, `18/10/22`, `%Y/%m/%d`, FromDate(2018, 10, 22, 0, 0, 0, 0)}, 415 {`Test35`, `100/10/22`, `%Y/%m/%d`, FromDate(100, 10, 22, 0, 0, 0, 0)}, 416 {`Test36`, `09/10/1021`, `%d/%m/%y`, FromDate(2010, 10, 9, 0, 0, 0, 0)}, // '%y' only accept up to 2 digits for year 417 {`Test37`, `09/10/1021`, `%d/%m/%Y`, FromDate(1021, 10, 9, 0, 0, 0, 0)}, // '%Y' accept up to 4 digits for year 418 {`Test38`, `09/10/10`, `%d/%m/%Y`, FromDate(2010, 10, 9, 0, 0, 0, 0)}, // '%Y' will fix the year for only 2 digits 419 //'%b'/'%M' should be case insensitive 420 {`Test40`, "31/may/2016 12:34:56.1234", "%d/%b/%Y %H:%i:%S.%f", FromDate(2016, 5, 31, 12, 34, 56, 123400)}, 421 {`Test41`, "30/april/2016 12:34:56.", "%d/%M/%Y %H:%i:%s.%f", FromDate(2016, 4, 30, 12, 34, 56, 0)}, 422 {`Test42`, "31/mAy/2016 12:34:56.1234", "%d/%b/%Y %H:%i:%S.%f", FromDate(2016, 5, 31, 12, 34, 56, 123400)}, 423 {`Test43`, "30/apRil/2016 12:34:56.", "%d/%M/%Y %H:%i:%s.%f", FromDate(2016, 4, 30, 12, 34, 56, 0)}, 424 // '%r' 425 {`Test45`, " 04 :13:56 AM13/05/2019", "%r %d/%c/%Y", FromDate(2019, 5, 13, 4, 13, 56, 0)}, // 426 {`Test46`, "12: 13:56 AM 13/05/2019", "%r%d/%c/%Y", FromDate(2019, 5, 13, 0, 13, 56, 0)}, // 427 {`Test47`, "12:13 :56 pm 13/05/2019", "%r %d/%c/%Y", FromDate(2019, 5, 13, 12, 13, 56, 0)}, // 428 {`Test48`, "12:3: 56pm 13/05/2019", "%r %d/%c/%Y", FromDate(2019, 5, 13, 12, 3, 56, 0)}, // 429 {`Test49`, "11:13:56", "%r", FromDate(0, 0, 0, 11, 13, 56, 0)}, // EOF before parsing "AM"/"PM" 430 {`Test50`, "11:13", "%r", FromDate(0, 0, 0, 11, 13, 0, 0)}, // EOF after hh:mm 431 {`Test51`, "11:", "%r", FromDate(0, 0, 0, 11, 0, 0, 0)}, // EOF after hh: 432 {`Test52`, "11", "%r", FromDate(0, 0, 0, 11, 0, 0, 0)}, // EOF after hh: 433 {`Test53`, "12", "%r", FromDate(0, 0, 0, 0, 0, 0, 0)}, // EOF after hh:, and hh=12 -> 0 434 // '%T' 435 {`Test55`, " 4 :13:56 13/05/2019", "%T %d/%c/%Y", FromDate(2019, 5, 13, 4, 13, 56, 0)}, 436 {`Test56`, "23: 13:56 13/05/2019", "%T%d/%c/%Y", FromDate(2019, 5, 13, 23, 13, 56, 0)}, 437 {`Test57`, "12:13 :56 13/05/2019", "%T %d/%c/%Y", FromDate(2019, 5, 13, 12, 13, 56, 0)}, 438 {`Test58`, "19:3: 56 13/05/2019", "%T %d/%c/%Y", FromDate(2019, 5, 13, 19, 3, 56, 0)}, 439 {`Test59`, "21:13", "%T", FromDate(0, 0, 0, 21, 13, 0, 0)}, // EOF after hh:mm 440 {`Test60`, "21:", "%T", FromDate(0, 0, 0, 21, 0, 0, 0)}, // EOF after hh: 441 // More patterns than input string 442 {`Test62`, " 2/Jun", "%d/%b/%Y", FromDate(0, 6, 2, 0, 0, 0, 0)}, 443 //{`Test63`, " liter", "lit era l", ZeroCoreTime}, 444 // Feb 29 in leap-year 445 {`Test65`, "29/Feb/2020 12:34:56.", "%d/%b/%Y %H:%i:%s.%f", FromDate(2020, 2, 29, 12, 34, 56, 0)}, 446 // When `AllowInvalidDate` is true, check only that the month is in the range from 1 to 12 and the day is in the range from 1 to 31 447 {`Test67`, "31/April/2016 12:34:56.", "%d/%M/%Y %H:%i:%s.%f", FromDate(2016, 4, 31, 12, 34, 56, 0)}, // April 31th 448 {`Test68`, "29/Feb/2021 12:34:56.", "%d/%b/%Y %H:%i:%s.%f", FromDate(2021, 2, 29, 12, 34, 56, 0)}, // Feb 29 in non-leap-year 449 {`Test69`, "30/Feb/2016 12:34:56.1234", "%d/%b/%Y %H:%i:%S.%f", FromDate(2016, 2, 30, 12, 34, 56, 123400)}, // Feb 30th 450 451 } 452 for _, tt := range tests { 453 t.Run(tt.name, func(t *testing.T) { 454 //ctx := make(map[string]int) 455 time := NewGeneralTime() 456 gotSuccess := CoreStrToDate(context.TODO(), time, tt.date, tt.format) 457 458 require.Truef(t, gotSuccess, "%s failed input=%s format=%s", tt.name, tt.date, tt.format) 459 require.Equalf(t, tt.expect, *time, "%s failed input=%s format=%s", tt.name, tt.date, tt.format) 460 }) 461 } 462 } 463 464 func Test_CoreStrToDateErr(t *testing.T) { 465 tests := []struct { 466 name string 467 date string 468 format string 469 }{ 470 // invalid days when `AllowInvalidDate` is false 471 //{"Test01", `04/31/2004`, `%m/%d/%Y`}, // not exists in the real world 472 //{"Test02", "29/Feb/2021 12:34:56.", "%d/%b/%Y %H:%i:%s.%f"}, // Feb 29 in non-leap-year 473 474 {"Test03", `512 2021`, `%m%d %Y`}, // MySQL will try to parse '51' for '%m', fail 475 476 {"Test04", `a09:30:17`, `%h:%i:%s`}, // format mismatch 477 {"Test05", `12:43:24 a`, `%r`}, // followed by incomplete 'AM'/'PM' 478 {"Test06", `23:60:12`, `%T`}, // invalid minute 479 {"Test07", `18`, `%l`}, 480 {"Test08", `00:21:22 AM`, `%h:%i:%s %p`}, 481 {"Test09", `100/10/22`, `%y/%m/%d`}, 482 {"Test10", "2010-11-12 11 am", `%Y-%m-%d %H %p`}, 483 {"Test11", "2010-11-12 13 am", `%Y-%m-%d %h %p`}, 484 {"Test12", "2010-11-12 0 am", `%Y-%m-%d %h %p`}, 485 // MySQL accept `SEPTEMB` as `SEPTEMBER`, but we don't want this "feature" in TiDB 486 // unless we have to. 487 {"Test13", "15 SEPTEMB 2001", "%d %M %Y"}, 488 // '%r' 489 {"Test14", "13:13:56 AM13/5/2019", "%r"}, // hh = 13 with am is invalid 490 {"Test15", "00:13:56 AM13/05/2019", "%r"}, // hh = 0 with am is invalid 491 {"Test16", "00:13:56 pM13/05/2019", "%r"}, // hh = 0 with pm is invalid 492 {"Test17", "11:13:56a", "%r"}, // EOF while parsing "AM"/"PM" 493 } 494 for _, tt := range tests { 495 t.Run(tt.name, func(t *testing.T) { 496 //ctx := make(map[string]int) 497 time := NewGeneralTime() 498 gotSuccess := CoreStrToDate(context.TODO(), time, tt.date, tt.format) 499 require.Falsef(t, gotSuccess, "%s failed input=%s format=%s", tt.name, tt.date, tt.format) 500 }) 501 } 502 503 }