github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/mysql/time.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package mysql 15 16 import ( 17 "bytes" 18 "fmt" 19 "math" 20 "strconv" 21 "strings" 22 "time" 23 "unicode" 24 25 "github.com/insionng/yougam/libraries/juju/errors" 26 ) 27 28 // Portable analogs of some common call errors. 29 var ( 30 ErrInvalidTimeFormat = errors.New("invalid time format") 31 ErrInvalidYearFormat = errors.New("invalid year format") 32 ErrInvalidYear = errors.New("invalid year") 33 ) 34 35 // Time format without fractional seconds precision. 36 const ( 37 DateFormat = "2006-01-02" 38 TimeFormat = "2006-01-02 15:04:05" 39 // TimeFSPFormat is time format with fractional seconds precision. 40 TimeFSPFormat = "2006-01-02 15:04:05.000000" 41 ) 42 43 const ( 44 // MinYear is the minimum for mysql year type. 45 MinYear int16 = 1901 46 // MaxYear is the maximum for mysql year type. 47 MaxYear int16 = 2155 48 49 // MinTime is the minimum for mysql time type. 50 MinTime = -time.Duration(838*3600+59*60+59) * time.Second 51 // MaxTime is the maximum for mysql time type. 52 MaxTime = time.Duration(838*3600+59*60+59) * time.Second 53 54 zeroDatetimeStr = "0000-00-00 00:00:00" 55 zeroDateStr = "0000-00-00" 56 ) 57 58 // Zero values for different types. 59 var ( 60 // ZeroDuration is the zero value for Duration type. 61 ZeroDuration = Duration{Duration: time.Duration(0), Fsp: DefaultFsp} 62 63 // ZeroTime is the zero value for time.Time type. 64 ZeroTime = time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC) 65 66 // ZeroDatetime is the zero value for datetime Time. 67 ZeroDatetime = Time{ 68 Time: ZeroTime, 69 Type: TypeDatetime, 70 Fsp: DefaultFsp, 71 } 72 73 // ZeroTimestamp is the zero value for timestamp Time. 74 ZeroTimestamp = Time{ 75 Time: ZeroTime, 76 Type: TypeTimestamp, 77 Fsp: DefaultFsp, 78 } 79 80 // ZeroDate is the zero value for date Time. 81 ZeroDate = Time{ 82 Time: ZeroTime, 83 Type: TypeDate, 84 Fsp: DefaultFsp, 85 } 86 ) 87 88 var ( 89 // MinDatetime is the minimum for mysql datetime type. 90 MinDatetime = time.Date(1000, 1, 1, 0, 0, 0, 0, time.Local) 91 // MaxDatetime is the maximum for mysql datetime type. 92 MaxDatetime = time.Date(9999, 12, 31, 23, 59, 59, 999999, time.Local) 93 94 // MinTimestamp is the minimum for mysql timestamp type. 95 MinTimestamp = time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC) 96 // MaxTimestamp is the maximum for mysql timestamp type. 97 MaxTimestamp = time.Date(2038, 1, 19, 3, 14, 7, 999999, time.UTC) 98 99 // WeekdayNames lists names of weekdays, which are used in builtin time function `dayname`. 100 WeekdayNames = []string{ 101 "Monday", 102 "Tuesday", 103 "Wednesday", 104 "Thursday", 105 "Friday", 106 "Saturday", 107 "Sunday", 108 } 109 ) 110 111 // Time is the struct for handling datetime, timestamp and date. 112 // TODO: check if need a NewTime function to set Fsp default value? 113 type Time struct { 114 time.Time 115 Type uint8 116 // Fsp is short for Fractional Seconds Precision. 117 // See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html 118 Fsp int 119 } 120 121 // CurrentTime returns current time with type tp. 122 func CurrentTime(tp uint8) Time { 123 return Time{Time: time.Now(), Type: tp, Fsp: 0} 124 } 125 126 func (t Time) String() string { 127 if t.IsZero() { 128 if t.Type == TypeDate { 129 return zeroDateStr 130 } 131 132 return zeroDatetimeStr 133 } 134 135 if t.Type == TypeDate { 136 return t.Time.Format(DateFormat) 137 } 138 139 tfStr := TimeFormat 140 if t.Fsp > 0 { 141 tfStr = fmt.Sprintf("%s.%s", tfStr, strings.Repeat("0", t.Fsp)) 142 } 143 144 return t.Time.Format(tfStr) 145 } 146 147 // IsZero returns a boolean indicating whether the time is equal to ZeroTime. 148 func (t Time) IsZero() bool { 149 return t.Time.Equal(ZeroTime) 150 } 151 152 // Marshal returns the binary encoding of time. 153 func (t Time) Marshal() ([]byte, error) { 154 var ( 155 b []byte 156 err error 157 ) 158 159 switch t.Type { 160 case TypeDatetime, TypeDate: 161 // We must use t's Zone not current Now Zone, 162 // For EDT/EST, even we create the time with time.Local location, 163 // we may still have a different zone with current Now time. 164 _, offset := t.Zone() 165 // For datetime and date type, we have a trick to marshal. 166 // e.g, if local time is 2010-10-10T10:10:10 UTC+8 167 // we will change this to 2010-10-10T10:10:10 UTC and then marshal. 168 b, err = t.Time.Add(time.Duration(offset) * time.Second).UTC().MarshalBinary() 169 case TypeTimestamp: 170 b, err = t.Time.UTC().MarshalBinary() 171 default: 172 err = errors.Errorf("invalid time type %d", t.Type) 173 } 174 175 if err != nil { 176 return nil, errors.Trace(err) 177 } 178 179 return b, nil 180 } 181 182 // Unmarshal decodes the binary data into Time with current local time. 183 func (t *Time) Unmarshal(b []byte) error { 184 return t.UnmarshalInLocation(b, time.Local) 185 } 186 187 // UnmarshalInLocation decodes the binary data 188 // into Time with a specific time Location. 189 func (t *Time) UnmarshalInLocation(b []byte, loc *time.Location) error { 190 if err := t.Time.UnmarshalBinary(b); err != nil { 191 return errors.Trace(err) 192 } 193 194 if t.IsZero() { 195 return nil 196 } 197 198 if t.Type == TypeDatetime || t.Type == TypeDate { 199 // e.g, for 2010-10-10T10:10:10 UTC, we will unmarshal to 2010-10-10T10:10:10 location 200 _, offset := t.Time.In(loc).Zone() 201 202 t.Time = t.Time.Add(-time.Duration(offset) * time.Second).In(loc) 203 if t.Type == TypeDate { 204 // for date type ,we will only use year, month and day. 205 year, month, day := t.Time.Date() 206 t.Time = time.Date(year, month, day, 0, 0, 0, 0, loc) 207 } 208 } else if t.Type == TypeTimestamp { 209 t.Time = t.Time.In(loc) 210 } else { 211 return errors.Errorf("invalid time type %d", t.Type) 212 } 213 214 return nil 215 } 216 217 const numberFormat = "20060102150405" 218 const dateFormat = "20060102" 219 220 // ToNumber returns a formatted number. 221 // e.g, 222 // 2012-12-12 -> 20121212 223 // 2012-12-12T10:10:10 -> 20121212101010 224 // 2012-12-12T10:10:10.123456 -> 20121212101010.123456 225 func (t Time) ToNumber() Decimal { 226 if t.IsZero() { 227 return ZeroDecimal 228 } 229 230 // Fix issue #1046 231 // Prevents from converting 2012-12-12 to 20121212000000 232 var tfStr string 233 if t.Type == TypeDate { 234 tfStr = dateFormat 235 } else { 236 tfStr = numberFormat 237 } 238 239 if t.Fsp > 0 { 240 tfStr = fmt.Sprintf("%s.%s", tfStr, strings.Repeat("0", t.Fsp)) 241 } 242 243 s := t.Time.Format(tfStr) 244 // We skip checking error here because time formatted string can be parsed certainly. 245 d, _ := ParseDecimal(s) 246 return d 247 } 248 249 // Convert converts t with type tp. 250 func (t Time) Convert(tp uint8) (Time, error) { 251 if t.Type == tp || t.IsZero() { 252 return Time{Time: t.Time, Type: tp, Fsp: t.Fsp}, nil 253 } 254 255 switch tp { 256 case TypeDatetime: 257 return Time{Time: t.Time, Type: TypeDatetime, Fsp: t.Fsp}, nil 258 case TypeTimestamp: 259 nt := Time{Time: t.Time, Type: TypeTimestamp, Fsp: t.Fsp} 260 if !checkTimestamp(nt) { 261 return ZeroTimestamp, errors.Trace(ErrInvalidTimeFormat) 262 } 263 return nt, nil 264 case TypeDate: 265 year, month, day := t.Time.Date() 266 return Time{Time: time.Date(year, month, day, 0, 0, 0, 0, time.Local), 267 Type: TypeDate, Fsp: 0}, nil 268 default: 269 return Time{Time: ZeroTime, Type: tp}, errors.Errorf("invalid time type %d", tp) 270 } 271 } 272 273 // ConvertToDuration converts mysql datetime, timestamp and date to mysql time type. 274 // e.g, 275 // 2012-12-12T10:10:10 -> 10:10:10 276 // 2012-12-12 -> 0 277 func (t Time) ConvertToDuration() (Duration, error) { 278 if t.IsZero() { 279 return ZeroDuration, nil 280 } 281 282 hour, minute, second := t.Clock() 283 frac := t.Nanosecond() 284 285 d := time.Duration(hour*3600+minute*60+second)*time.Second + time.Duration(frac) 286 287 // TODO: check convert validation 288 return Duration{Duration: time.Duration(d), Fsp: t.Fsp}, nil 289 } 290 291 // Compare returns an integer comparing the time instant t to o. 292 // If t is after o, return 1, equal o, return 0, before o, return -1. 293 func (t Time) Compare(o Time) int { 294 if t.Time.After(o.Time) { 295 return 1 296 } else if t.Time.Equal(o.Time) { 297 return 0 298 } else { 299 return -1 300 } 301 } 302 303 // CompareString is like Compare, 304 // but parses string to Time then compares. 305 func (t Time) CompareString(str string) (int, error) { 306 // use MaxFsp to parse the string 307 o, err := ParseTime(str, t.Type, MaxFsp) 308 if err != nil { 309 return 0, errors.Trace(err) 310 } 311 312 return t.Compare(o), nil 313 } 314 315 // RoundFrac rounds fractional seconds precision with new fsp and returns a new one. 316 // We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0, 317 // so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11 318 // and 2011:11:11 10:10:10.111111 round 0 -> 2011:11:11 10:10:10 319 func (t Time) RoundFrac(fsp int) (Time, error) { 320 if t.Type == TypeDate { 321 // date type has no fsp 322 return t, nil 323 } 324 325 fsp, err := checkFsp(fsp) 326 if err != nil { 327 return t, errors.Trace(err) 328 } 329 330 if fsp == t.Fsp { 331 // have same fsp 332 return t, nil 333 } 334 335 nt := t.Time.Round(time.Duration(math.Pow10(9-fsp)) * time.Nanosecond) 336 return Time{Time: nt, Type: t.Type, Fsp: fsp}, nil 337 } 338 339 func parseDateFormat(format string) []string { 340 format = strings.TrimSpace(format) 341 342 start := 0 343 seps := []string{} 344 for i := 0; i < len(format); i++ { 345 // Date format must start and end with number. 346 if i == 0 || i == len(format)-1 { 347 if !unicode.IsNumber(rune(format[i])) { 348 return nil 349 } 350 351 continue 352 } 353 354 // Separator is a single none-number char. 355 if !unicode.IsNumber(rune(format[i])) { 356 if !unicode.IsNumber(rune(format[i-1])) { 357 return nil 358 } 359 360 seps = append(seps, format[start:i]) 361 start = i + 1 362 } 363 364 } 365 366 seps = append(seps, format[start:]) 367 return seps 368 } 369 370 func parseDatetime(str string, fsp int) (Time, error) { 371 // Try to split str with delimiter. 372 // TODO: only punctuation can be the delimiter for date parts or time parts. 373 // But only space and T can be the delimiter between the date and time part. 374 var ( 375 year int 376 month int 377 day int 378 hour int 379 minute int 380 second int 381 frac int 382 fracStr string 383 384 err error 385 ) 386 387 seps := parseDateFormat(str) 388 389 switch len(seps) { 390 case 1: 391 // No delimiter. 392 if len(str) == 14 { 393 // YYYYMMDDHHMMSS 394 _, err = fmt.Sscanf(str, "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second) 395 } else if len(str) == 12 { 396 // YYMMDDHHMMSS 397 _, err = fmt.Sscanf(str, "%2d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second) 398 year = adjustYear(year) 399 } else if len(str) == 8 { 400 // YYYYMMDD 401 _, err = fmt.Sscanf(str, "%4d%2d%2d", &year, &month, &day) 402 } else if len(str) == 6 { 403 // YYMMDD 404 _, err = fmt.Sscanf(str, "%2d%2d%2d", &year, &month, &day) 405 year = adjustYear(year) 406 } else { 407 return ZeroDatetime, errors.Trace(ErrInvalidTimeFormat) 408 } 409 case 2: 410 s := seps[0] 411 fracStr = seps[1] 412 413 if len(s) == 14 { 414 // YYYYMMDDHHMMSS.fraction 415 _, err = fmt.Sscanf(s, "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second) 416 } else if len(s) == 12 { 417 // YYMMDDHHMMSS.fraction 418 _, err = fmt.Sscanf(s, "%2d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second) 419 year = adjustYear(year) 420 } else { 421 return ZeroDatetime, errors.Trace(ErrInvalidTimeFormat) 422 } 423 case 3: 424 // YYYY-MM-DD 425 err = scanTimeArgs(seps, &year, &month, &day) 426 case 6: 427 // We don't have fractional seconds part. 428 // YYYY-MM-DD HH-MM-SS 429 err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second) 430 case 7: 431 // We have fractional seconds part. 432 // YYY-MM-DD HH-MM-SS.fraction 433 err = scanTimeArgs(seps[0:len(seps)-1], &year, &month, &day, &hour, &minute, &second) 434 fracStr = seps[len(seps)-1] 435 default: 436 return ZeroDatetime, errors.Trace(ErrInvalidTimeFormat) 437 } 438 439 if err != nil { 440 return ZeroDatetime, errors.Trace(err) 441 } 442 443 // If str is sepereated by delimiters, the first one is year, and if the year is 2 digit, 444 // we should adjust it. 445 // TODO: ajust year is very complex, now we only consider the simplest way. 446 if len(seps[0]) == 2 { 447 year = adjustYear(year) 448 } 449 450 frac, err = parseFrac(fracStr, fsp) 451 if err != nil { 452 return ZeroDatetime, errors.Trace(err) 453 } 454 455 t, err := newTime(year, month, day, hour, minute, second, frac) 456 if err != nil { 457 return ZeroDatetime, errors.Trace(err) 458 } 459 460 nt := Time{ 461 Time: t, 462 Type: TypeDatetime, 463 Fsp: fsp} 464 465 return nt, nil 466 } 467 468 func scanTimeArgs(seps []string, args ...*int) error { 469 if len(seps) != len(args) { 470 return errors.Trace(ErrInvalidTimeFormat) 471 } 472 473 var err error 474 for i, s := range seps { 475 *args[i], err = strconv.Atoi(s) 476 if err != nil { 477 return errors.Trace(err) 478 } 479 } 480 return nil 481 } 482 483 // ParseYear parses a formatted string and returns a year number. 484 func ParseYear(str string) (int16, error) { 485 v, err := strconv.ParseInt(str, 10, 16) 486 if err != nil { 487 return 0, errors.Trace(err) 488 } 489 y := int16(v) 490 491 if len(str) == 4 { 492 // Nothing to do. 493 } else if len(str) == 2 || len(str) == 1 { 494 y = int16(adjustYear(int(y))) 495 } else { 496 return 0, errors.Trace(ErrInvalidYearFormat) 497 } 498 499 if y < MinYear || y > MaxYear { 500 return 0, errors.Trace(ErrInvalidYearFormat) 501 } 502 503 return y, nil 504 } 505 506 func newTime(year int, month int, day int, hour int, minute int, second int, frac int) (time.Time, error) { 507 if year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0 { 508 // Should we check fractional fractional here? 509 // But go time.Time can not support zero time 0000-00-00 00:00:00. 510 return ZeroTime, nil 511 } 512 513 if err := checkTime(year, month, day, hour, minute, second, frac); err != nil { 514 return ZeroTime, errors.Trace(err) 515 } 516 517 return time.Date(year, time.Month(month), day, hour, minute, second, frac*1000, time.Local), nil 518 } 519 520 // See https://dev.mysql.com/doc/refman/5.7/en/two-digit-years.html 521 func adjustYear(y int) int { 522 if y >= 0 && y <= 69 { 523 y = 2000 + y 524 } else if y >= 70 && y <= 99 { 525 y = 1900 + y 526 } 527 return y 528 } 529 530 // AdjustYear is used for adjusting year and checking its validation. 531 func AdjustYear(y int64) (int64, error) { 532 y = int64(adjustYear(int(y))) 533 if y < int64(MinYear) || y > int64(MaxYear) { 534 return 0, errors.Trace(ErrInvalidYear) 535 } 536 537 return y, nil 538 } 539 540 // Duration is the type for MySQL time type. 541 type Duration struct { 542 time.Duration 543 // Fsp is short for Fractional Seconds Precision. 544 // See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html 545 Fsp int 546 } 547 548 // String returns the time formatted using default TimeFormat and fsp. 549 func (d Duration) String() string { 550 var buf bytes.Buffer 551 552 sign, hours, minutes, seconds, fraction := splitDuration(d.Duration) 553 if sign < 0 { 554 buf.WriteByte('-') 555 } 556 557 fmt.Fprintf(&buf, "%02d:%02d:%02d", hours, minutes, seconds) 558 if d.Fsp > 0 { 559 buf.WriteString(".") 560 buf.WriteString(d.formatFrac(fraction)) 561 } 562 563 p := buf.String() 564 565 return p 566 } 567 568 func (d Duration) formatFrac(frac int) string { 569 s := fmt.Sprintf("%06d", frac) 570 return s[0:d.Fsp] 571 } 572 573 // ToNumber changes duration to number format. 574 // e.g, 575 // 10:10:10 -> 101010 576 func (d Duration) ToNumber() Decimal { 577 sign, hours, minutes, seconds, fraction := splitDuration(time.Duration(d.Duration)) 578 var ( 579 s string 580 signStr string 581 ) 582 583 if sign < 0 { 584 signStr = "-" 585 } 586 587 if d.Fsp == 0 { 588 s = fmt.Sprintf("%s%02d%02d%02d", signStr, hours, minutes, seconds) 589 } else { 590 s = fmt.Sprintf("%s%02d%02d%02d.%s", signStr, hours, minutes, seconds, d.formatFrac(fraction)) 591 } 592 593 // We skip checking error here because time formatted string can be parsed certainly. 594 v, _ := ParseDecimal(s) 595 return v 596 } 597 598 // ConvertToTime converts duration to Time. 599 // Tp is TypeDatetime, TypeTimestamp and TypeDate. 600 func (d Duration) ConvertToTime(tp uint8) (Time, error) { 601 year, month, day := time.Now().Date() 602 // just use current year, month and day. 603 n := time.Date(year, month, day, 0, 0, 0, 0, time.Local) 604 n = n.Add(d.Duration) 605 606 t := Time{ 607 Time: n, 608 Type: TypeDatetime, 609 Fsp: d.Fsp, 610 } 611 612 return t.Convert(tp) 613 } 614 615 // RoundFrac rounds fractional seconds precision with new fsp and returns a new one. 616 // We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0, 617 // so 10:10:10.999999 round 0 -> 10:10:11 618 // and 10:10:10.000000 round 0 -> 10:10:10 619 func (d Duration) RoundFrac(fsp int) (Duration, error) { 620 fsp, err := checkFsp(fsp) 621 if err != nil { 622 return d, errors.Trace(err) 623 } 624 625 if fsp == d.Fsp { 626 return d, nil 627 } 628 629 n := ZeroTime 630 nd := n.Add(d.Duration).Round(time.Duration(math.Pow10(9-fsp)) * time.Nanosecond).Sub(n) 631 return Duration{Duration: nd, Fsp: fsp}, nil 632 } 633 634 // Compare returns an integer comparing the Duration instant t to o. 635 // If d is after o, return 1, equal o, return 0, before o, return -1. 636 func (d Duration) Compare(o Duration) int { 637 if d.Duration > o.Duration { 638 return 1 639 } else if d.Duration == o.Duration { 640 return 0 641 } else { 642 return -1 643 } 644 } 645 646 // CompareString is like Compare, 647 // but parses str to Duration then compares. 648 func (d Duration) CompareString(str string) (int, error) { 649 // use MaxFsp to parse the string 650 o, err := ParseDuration(str, MaxFsp) 651 if err != nil { 652 return 0, err 653 } 654 655 return d.Compare(o), nil 656 } 657 658 // Hour returns current hour. 659 // e.g, hour("11:11:11") -> 11 660 func (d Duration) Hour() int { 661 _, hour, _, _, _ := splitDuration(d.Duration) 662 return hour 663 } 664 665 // Minute returns current minute. 666 // e.g, hour("11:11:11") -> 11 667 func (d Duration) Minute() int { 668 _, _, minute, _, _ := splitDuration(d.Duration) 669 return minute 670 } 671 672 // Second returns current second. 673 // e.g, hour("11:11:11") -> 11 674 func (d Duration) Second() int { 675 _, _, _, second, _ := splitDuration(d.Duration) 676 return second 677 } 678 679 // MicroSecond returns current microsecond. 680 // e.g, hour("11:11:11.11") -> 110000 681 func (d Duration) MicroSecond() int { 682 _, _, _, _, frac := splitDuration(d.Duration) 683 return frac 684 } 685 686 // ParseDuration parses the time form a formatted string with a fractional seconds part, 687 // returns the duration type Time value. 688 // See: http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html 689 func ParseDuration(str string, fsp int) (Duration, error) { 690 var ( 691 day int 692 hour int 693 minute int 694 second int 695 frac int 696 697 err error 698 sign = 0 699 dayExists = false 700 ) 701 702 fsp, err = checkFsp(fsp) 703 if err != nil { 704 return ZeroDuration, errors.Trace(err) 705 } 706 707 if len(str) == 0 { 708 return ZeroDuration, nil 709 } else if str[0] == '-' { 710 str = str[1:] 711 sign = -1 712 } 713 714 // Time format may has day. 715 if n := strings.IndexByte(str, ' '); n >= 0 { 716 if day, err = strconv.Atoi(str[:n]); err == nil { 717 dayExists = true 718 } 719 str = str[n+1:] 720 } 721 722 if n := strings.IndexByte(str, '.'); n >= 0 { 723 // It has fractional precesion parts. 724 fracStr := str[n+1:] 725 frac, err = parseFrac(fracStr, fsp) 726 if err != nil { 727 return ZeroDuration, errors.Trace(err) 728 } 729 str = str[0:n] 730 } 731 732 // It tries to split str with delimiter, time delimiter must be : 733 seps := strings.Split(str, ":") 734 735 switch len(seps) { 736 case 1: 737 if dayExists { 738 hour, err = strconv.Atoi(seps[0]) 739 } else { 740 // No delimiter. 741 if len(str) == 6 { 742 // HHMMSS 743 _, err = fmt.Sscanf(str, "%2d%2d%2d", &hour, &minute, &second) 744 } else if len(str) == 4 { 745 // MMSS 746 _, err = fmt.Sscanf(str, "%2d%2d", &minute, &second) 747 } else if len(str) == 2 { 748 // SS 749 _, err = fmt.Sscanf(str, "%2d", &second) 750 } else { 751 // Maybe only contains date. 752 _, err = ParseDate(str) 753 if err == nil { 754 return ZeroDuration, nil 755 } 756 return ZeroDuration, errors.Trace(ErrInvalidTimeFormat) 757 } 758 } 759 case 2: 760 // HH:MM 761 _, err = fmt.Sscanf(str, "%2d:%2d", &hour, &minute) 762 case 3: 763 // Time format maybe HH:MM:SS or HHH:MM:SS. 764 // See: https://dev.mysql.com/doc/refman/5.7/en/time.html 765 if !dayExists && len(seps[0]) == 3 { 766 _, err = fmt.Sscanf(str, "%3d:%2d:%2d", &hour, &minute, &second) 767 } else { 768 _, err = fmt.Sscanf(str, "%2d:%2d:%2d", &hour, &minute, &second) 769 } 770 default: 771 return ZeroDuration, errors.Trace(ErrInvalidTimeFormat) 772 } 773 774 if err != nil { 775 return ZeroDuration, errors.Trace(err) 776 } 777 778 d := time.Duration(day*24*3600+hour*3600+minute*60+second)*time.Second + time.Duration(frac)*time.Microsecond 779 if sign == -1 { 780 d = -d 781 } 782 783 if d > MaxTime { 784 d = MaxTime 785 err = ErrInvalidTimeFormat 786 } else if d < MinTime { 787 d = MinTime 788 err = ErrInvalidTimeFormat 789 } 790 return Duration{Duration: d, Fsp: fsp}, errors.Trace(err) 791 } 792 793 func splitDuration(t time.Duration) (int, int, int, int, int) { 794 sign := 1 795 if t < 0 { 796 t = -t 797 sign = -1 798 } 799 800 hours := t / time.Hour 801 t -= hours * time.Hour 802 minutes := t / time.Minute 803 t -= minutes * time.Minute 804 seconds := t / time.Second 805 t -= seconds * time.Second 806 fraction := t / time.Microsecond 807 808 return sign, int(hours), int(minutes), int(seconds), int(fraction) 809 } 810 811 func checkTime(year int, month int, day int, hour int, minute int, second int, frac int) error { 812 // Notes: for datetime type, `insert t values("0001-01-01 00:00:00");` is valid 813 // so here only check year from 0~9999. 814 if (year < 0 || year > 9999) || 815 (month <= 0 || month > 12) || 816 (day <= 0 || day > 31) || 817 (hour < 0 || hour >= 24) || 818 (minute < 0 || minute >= 60) || 819 (second < 0 || second >= 60) || 820 (frac < 0) { 821 return errors.Trace(ErrInvalidTimeFormat) 822 } 823 824 return nil 825 } 826 827 func getTime(num int64, tp byte) (Time, error) { 828 s1 := num / 1000000 829 s2 := num - s1*1000000 830 831 year := int(s1 / 10000) 832 s1 %= 10000 833 month := int(s1 / 100) 834 day := int(s1 % 100) 835 836 hour := int(s2 / 10000) 837 s2 %= 10000 838 minute := int(s2 / 100) 839 second := int(s2 % 100) 840 841 if err := checkTime(year, month, day, hour, minute, second, 0); err != nil { 842 return Time{ 843 Time: ZeroTime, 844 Type: tp, 845 Fsp: DefaultFsp, 846 }, err 847 } 848 849 t, err := newTime(year, month, day, hour, minute, second, 0) 850 return Time{ 851 Time: t, 852 Type: tp, 853 Fsp: DefaultFsp, 854 }, errors.Trace(err) 855 } 856 857 // See number_to_datetime function. 858 // https://yougam/libraries/mysql/mysql-server/blob/5.7/sql-common/my_time.c 859 func parseDateTimeFromNum(num int64) (Time, error) { 860 t := ZeroDate 861 // Check zero. 862 if num == 0 { 863 return t, nil 864 } 865 866 // Check datetime type. 867 if num >= 10000101000000 { 868 return getTime(num, t.Type) 869 } 870 871 // Check MMDD. 872 if num < 101 { 873 return t, errors.Trace(ErrInvalidTimeFormat) 874 } 875 876 // Adjust year 877 // YYMMDD, year: 2000-2069 878 if num <= (70-1)*10000+1231 { 879 num = (num + 20000000) * 1000000 880 return getTime(num, t.Type) 881 } 882 883 // Check YYMMDD. 884 if num < 70*10000+101 { 885 return t, errors.Trace(ErrInvalidTimeFormat) 886 } 887 888 // Adjust year 889 // YYMMDD, year: 1970-1999 890 if num < 991231 { 891 num = (num + 19000000) * 1000000 892 return getTime(num, t.Type) 893 } 894 895 // Check YYYYMMDD. 896 if num < 10000101 { 897 return t, errors.Trace(ErrInvalidTimeFormat) 898 } 899 900 // Adjust hour/min/second. 901 if num < 99991231 { 902 num = num * 1000000 903 return getTime(num, t.Type) 904 } 905 906 // Check MMDDHHMMSS. 907 if num < 101000000 { 908 return t, errors.Trace(ErrInvalidTimeFormat) 909 } 910 911 // Set TypeDatetime type. 912 t.Type = TypeDatetime 913 914 // Adjust year 915 // YYMMDDHHMMSS, 2000-2069 916 if num <= 69*10000000000+1231235959 { 917 num = num + 20000000000000 918 return getTime(num, t.Type) 919 } 920 921 // Check YYYYMMDDHHMMSS. 922 if num < 70*10000000000+101000000 { 923 return t, errors.Trace(ErrInvalidTimeFormat) 924 } 925 926 // Adjust year 927 // YYMMDDHHMMSS, 1970-1999 928 if num <= 991231235959 { 929 num = num + 19000000000000 930 return getTime(num, t.Type) 931 } 932 933 return getTime(num, t.Type) 934 } 935 936 // ParseTime parses a formatted string with type tp and specific fsp. 937 // Type is TypeDatetime, TypeTimestamp and TypeDate. 938 // Fsp is in range [0, 6]. 939 // MySQL supports many valid datatime format, but still has some limitation. 940 // If delimiter exists, the date part and time part is separated by a space or T, 941 // other punctuation character can be used as the delimiter between date parts or time parts. 942 // If no delimiter, the format must be YYYYMMDDHHMMSS or YYMMDDHHMMSS 943 // If we have fractional seconds part, we must use decimal points as the delimiter. 944 // The valid datetime range is from '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'. 945 // The valid timestamp range is from '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'. 946 // The valid date range is from '1000-01-01' to '9999-12-31' 947 func ParseTime(str string, tp byte, fsp int) (Time, error) { 948 fsp, err := checkFsp(fsp) 949 if err != nil { 950 return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) 951 } 952 953 t, err := parseDatetime(str, fsp) 954 if err != nil { 955 return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) 956 } 957 958 return t.Convert(tp) 959 } 960 961 // ParseDatetime is a helper function wrapping ParseTime with datetime type and default fsp. 962 func ParseDatetime(str string) (Time, error) { 963 return ParseTime(str, TypeDatetime, DefaultFsp) 964 } 965 966 // ParseTimestamp is a helper function wrapping ParseTime with timestamp type and default fsp. 967 func ParseTimestamp(str string) (Time, error) { 968 return ParseTime(str, TypeTimestamp, DefaultFsp) 969 } 970 971 // ParseDate is a helper function wrapping ParseTime with date type. 972 func ParseDate(str string) (Time, error) { 973 // date has no fractional seconds precision 974 return ParseTime(str, TypeDate, MinFsp) 975 } 976 977 // ParseTimeFromNum parses a formatted int64, 978 // returns the value which type is tp. 979 func ParseTimeFromNum(num int64, tp byte, fsp int) (Time, error) { 980 fsp, err := checkFsp(fsp) 981 if err != nil { 982 return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) 983 } 984 985 t, err := parseDateTimeFromNum(num) 986 if err != nil { 987 return Time{Time: ZeroTime, Type: tp}, errors.Trace(err) 988 } 989 990 if !checkDatetime(t) { 991 return Time{Time: ZeroTime, Type: tp}, ErrInvalidTimeFormat 992 } 993 994 t.Fsp = fsp 995 return t.Convert(tp) 996 } 997 998 // ParseDatetimeFromNum is a helper function wrapping ParseTimeFromNum with datetime type and default fsp. 999 func ParseDatetimeFromNum(num int64) (Time, error) { 1000 return ParseTimeFromNum(num, TypeDatetime, DefaultFsp) 1001 } 1002 1003 // ParseTimestampFromNum is a helper function wrapping ParseTimeFromNum with timestamp type and default fsp. 1004 func ParseTimestampFromNum(num int64) (Time, error) { 1005 return ParseTimeFromNum(num, TypeTimestamp, DefaultFsp) 1006 } 1007 1008 // ParseDateFromNum is a helper function wrapping ParseTimeFromNum with date type. 1009 func ParseDateFromNum(num int64) (Time, error) { 1010 // date has no fractional seconds precision 1011 return ParseTimeFromNum(num, TypeDate, MinFsp) 1012 } 1013 1014 func checkDatetime(t Time) bool { 1015 if t.IsZero() { 1016 return true 1017 } 1018 1019 if t.Time.After(MaxDatetime) || t.Time.Before(MinDatetime) { 1020 return false 1021 } 1022 1023 return true 1024 } 1025 1026 func checkTimestamp(t Time) bool { 1027 if t.IsZero() { 1028 return true 1029 } 1030 1031 if t.Time.After(MaxTimestamp) || t.Time.Before(MinTimestamp) { 1032 return false 1033 } 1034 1035 return true 1036 } 1037 1038 // ExtractTimeNum extracts time value number from time unit and format. 1039 func ExtractTimeNum(unit string, t Time) (int64, error) { 1040 switch strings.ToUpper(unit) { 1041 case "MICROSECOND": 1042 return int64(t.Nanosecond() / 1000), nil 1043 case "SECOND": 1044 return int64(t.Second()), nil 1045 case "MINUTE": 1046 return int64(t.Minute()), nil 1047 case "HOUR": 1048 return int64(t.Hour()), nil 1049 case "DAY": 1050 return int64(t.Day()), nil 1051 case "WEEK": 1052 _, week := t.ISOWeek() 1053 return int64(week), nil 1054 case "MONTH": 1055 return int64(t.Month()), nil 1056 case "QUARTER": 1057 m := int64(t.Month()) 1058 // 1 - 3 -> 1 1059 // 4 - 6 -> 2 1060 // 7 - 9 -> 3 1061 // 10 - 12 -> 4 1062 return (m + 2) / 3, nil 1063 case "YEAR": 1064 return int64(t.Year()), nil 1065 case "SECOND_MICROSECOND": 1066 return int64(t.Second())*1000000 + int64(t.Nanosecond())/1000, nil 1067 case "MINUTE_MICROSECOND": 1068 _, m, s := t.Clock() 1069 return int64(m)*100000000 + int64(s)*1000000 + int64(t.Nanosecond())/1000, nil 1070 case "MINUTE_SECOND": 1071 _, m, s := t.Clock() 1072 return int64(m*100 + s), nil 1073 case "HOUR_MICROSECOND": 1074 h, m, s := t.Clock() 1075 return int64(h)*10000000000 + int64(m)*100000000 + int64(s)*1000000 + int64(t.Nanosecond())/1000, nil 1076 case "HOUR_SECOND": 1077 h, m, s := t.Clock() 1078 return int64(h)*10000 + int64(m)*100 + int64(s), nil 1079 case "HOUR_MINUTE": 1080 h, m, _ := t.Clock() 1081 return int64(h)*100 + int64(m), nil 1082 case "DAY_MICROSECOND": 1083 h, m, s := t.Clock() 1084 d := t.Day() 1085 return int64(d*1000000+h*10000+m*100+s)*1000000 + int64(t.Nanosecond())/1000, nil 1086 case "DAY_SECOND": 1087 h, m, s := t.Clock() 1088 d := t.Day() 1089 return int64(d)*1000000 + int64(h)*10000 + int64(m)*100 + int64(s), nil 1090 case "DAY_MINUTE": 1091 h, m, _ := t.Clock() 1092 d := t.Day() 1093 return int64(d)*10000 + int64(h)*100 + int64(m), nil 1094 case "DAY_HOUR": 1095 h, _, _ := t.Clock() 1096 d := t.Day() 1097 return int64(d)*100 + int64(h), nil 1098 case "YEAR_MONTH": 1099 y, m, _ := t.Date() 1100 return int64(y)*100 + int64(m), nil 1101 default: 1102 return 0, errors.Errorf("invalid unit %s", unit) 1103 } 1104 } 1105 1106 func extractSingleTimeValue(unit string, format string) (int64, int64, int64, time.Duration, error) { 1107 iv, err := strconv.ParseInt(format, 10, 64) 1108 if err != nil { 1109 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1110 } 1111 1112 v := time.Duration(iv) 1113 switch strings.ToUpper(unit) { 1114 case "MICROSECOND": 1115 return 0, 0, 0, v * time.Microsecond, nil 1116 case "SECOND": 1117 return 0, 0, 0, v * time.Second, nil 1118 case "MINUTE": 1119 return 0, 0, 0, v * time.Minute, nil 1120 case "HOUR": 1121 return 0, 0, 0, v * time.Hour, nil 1122 case "DAY": 1123 return 0, 0, iv, 0, nil 1124 case "WEEK": 1125 return 0, 0, 7 * iv, 0, nil 1126 case "MONTH": 1127 return 0, iv, 0, 0, nil 1128 case "QUARTER": 1129 return 0, 3 * iv, 0, 0, nil 1130 case "YEAR": 1131 return iv, 0, 0, 0, nil 1132 } 1133 1134 return 0, 0, 0, 0, errors.Errorf("invalid singel timeunit - %s", unit) 1135 } 1136 1137 // Format is `SS.FFFFFF`. 1138 func extractSecondMicrosecond(format string) (int64, int64, int64, time.Duration, error) { 1139 fields := strings.Split(format, ".") 1140 if len(fields) != 2 { 1141 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1142 } 1143 1144 seconds, err := strconv.ParseInt(fields[0], 10, 64) 1145 if err != nil { 1146 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1147 } 1148 1149 microseconds, err := strconv.ParseInt(alignFrac(fields[1], MaxFsp), 10, 64) 1150 if err != nil { 1151 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1152 } 1153 1154 return 0, 0, 0, time.Duration(seconds)*time.Second + time.Duration(microseconds)*time.Microsecond, nil 1155 } 1156 1157 // Format is `MM:SS.FFFFFF`. 1158 func extractMinuteMicrosecond(format string) (int64, int64, int64, time.Duration, error) { 1159 fields := strings.Split(format, ":") 1160 if len(fields) != 2 { 1161 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1162 } 1163 1164 minutes, err := strconv.ParseInt(fields[0], 10, 64) 1165 if err != nil { 1166 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1167 } 1168 1169 _, _, _, value, err := extractSecondMicrosecond(fields[1]) 1170 if err != nil { 1171 return 0, 0, 0, 0, errors.Trace(err) 1172 } 1173 1174 return 0, 0, 0, time.Duration(minutes)*time.Minute + value, nil 1175 } 1176 1177 // Format is `MM:SS`. 1178 func extractMinuteSecond(format string) (int64, int64, int64, time.Duration, error) { 1179 fields := strings.Split(format, ":") 1180 if len(fields) != 2 { 1181 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1182 } 1183 1184 minutes, err := strconv.ParseInt(fields[0], 10, 64) 1185 if err != nil { 1186 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1187 } 1188 1189 seconds, err := strconv.ParseInt(fields[1], 10, 64) 1190 if err != nil { 1191 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1192 } 1193 1194 return 0, 0, 0, time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second, nil 1195 } 1196 1197 // Format is `HH:MM:SS.FFFFFF`. 1198 func extractHourMicrosecond(format string) (int64, int64, int64, time.Duration, error) { 1199 fields := strings.Split(format, ":") 1200 if len(fields) != 3 { 1201 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1202 } 1203 1204 hours, err := strconv.ParseInt(fields[0], 10, 64) 1205 if err != nil { 1206 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1207 } 1208 1209 minutes, err := strconv.ParseInt(fields[1], 10, 64) 1210 if err != nil { 1211 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1212 } 1213 1214 _, _, _, value, err := extractSecondMicrosecond(fields[2]) 1215 if err != nil { 1216 return 0, 0, 0, 0, errors.Trace(err) 1217 } 1218 1219 return 0, 0, 0, time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + value, nil 1220 } 1221 1222 // Format is `HH:MM:SS`. 1223 func extractHourSecond(format string) (int64, int64, int64, time.Duration, error) { 1224 fields := strings.Split(format, ":") 1225 if len(fields) != 3 { 1226 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1227 } 1228 1229 hours, err := strconv.ParseInt(fields[0], 10, 64) 1230 if err != nil { 1231 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1232 } 1233 1234 minutes, err := strconv.ParseInt(fields[1], 10, 64) 1235 if err != nil { 1236 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1237 } 1238 1239 seconds, err := strconv.ParseInt(fields[2], 10, 64) 1240 if err != nil { 1241 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1242 } 1243 1244 return 0, 0, 0, time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second, nil 1245 } 1246 1247 // Format is `HH:MM`. 1248 func extractHourMinute(format string) (int64, int64, int64, time.Duration, error) { 1249 fields := strings.Split(format, ":") 1250 if len(fields) != 2 { 1251 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1252 } 1253 1254 hours, err := strconv.ParseInt(fields[0], 10, 64) 1255 if err != nil { 1256 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1257 } 1258 1259 minutes, err := strconv.ParseInt(fields[1], 10, 64) 1260 if err != nil { 1261 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1262 } 1263 1264 return 0, 0, 0, time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute, nil 1265 } 1266 1267 // Format is `DD HH:MM:SS.FFFFFF`. 1268 func extractDayMicrosecond(format string) (int64, int64, int64, time.Duration, error) { 1269 fields := strings.Split(format, " ") 1270 if len(fields) != 2 { 1271 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1272 } 1273 1274 days, err := strconv.ParseInt(fields[0], 10, 64) 1275 if err != nil { 1276 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1277 } 1278 1279 _, _, _, value, err := extractHourMicrosecond(fields[1]) 1280 if err != nil { 1281 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1282 } 1283 1284 return 0, 0, days, value, nil 1285 } 1286 1287 // Format is `DD HH:MM:SS`. 1288 func extractDaySecond(format string) (int64, int64, int64, time.Duration, error) { 1289 fields := strings.Split(format, " ") 1290 if len(fields) != 2 { 1291 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1292 } 1293 1294 days, err := strconv.ParseInt(fields[0], 10, 64) 1295 if err != nil { 1296 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1297 } 1298 1299 _, _, _, value, err := extractHourSecond(fields[1]) 1300 if err != nil { 1301 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1302 } 1303 1304 return 0, 0, days, value, nil 1305 } 1306 1307 // Format is `DD HH:MM`. 1308 func extractDayMinute(format string) (int64, int64, int64, time.Duration, error) { 1309 fields := strings.Split(format, " ") 1310 if len(fields) != 2 { 1311 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1312 } 1313 1314 days, err := strconv.ParseInt(fields[0], 10, 64) 1315 if err != nil { 1316 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1317 } 1318 1319 _, _, _, value, err := extractHourMinute(fields[1]) 1320 if err != nil { 1321 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1322 } 1323 1324 return 0, 0, days, value, nil 1325 } 1326 1327 // Format is `DD HH`. 1328 func extractDayHour(format string) (int64, int64, int64, time.Duration, error) { 1329 fields := strings.Split(format, " ") 1330 if len(fields) != 2 { 1331 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1332 } 1333 1334 days, err := strconv.ParseInt(fields[0], 10, 64) 1335 if err != nil { 1336 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1337 } 1338 1339 hours, err := strconv.ParseInt(fields[1], 10, 64) 1340 if err != nil { 1341 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1342 } 1343 1344 return 0, 0, days, time.Duration(hours) * time.Hour, nil 1345 } 1346 1347 // Format is `YYYY-MM`. 1348 func extractYearMonth(format string) (int64, int64, int64, time.Duration, error) { 1349 fields := strings.Split(format, "-") 1350 if len(fields) != 2 { 1351 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1352 } 1353 1354 years, err := strconv.ParseInt(fields[0], 10, 64) 1355 if err != nil { 1356 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1357 } 1358 1359 months, err := strconv.ParseInt(fields[1], 10, 64) 1360 if err != nil { 1361 return 0, 0, 0, 0, errors.Errorf("invalid time format - %s", format) 1362 } 1363 1364 return years, months, 0, 0, nil 1365 } 1366 1367 // ExtractTimeValue extracts time value from time unit and format. 1368 func ExtractTimeValue(unit string, format string) (int64, int64, int64, time.Duration, error) { 1369 switch strings.ToUpper(unit) { 1370 case "MICROSECOND", "SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "QUARTER", "YEAR": 1371 return extractSingleTimeValue(unit, format) 1372 case "SECOND_MICROSECOND": 1373 return extractSecondMicrosecond(format) 1374 case "MINUTE_MICROSECOND": 1375 return extractMinuteMicrosecond(format) 1376 case "MINUTE_SECOND": 1377 return extractMinuteSecond(format) 1378 case "HOUR_MICROSECOND": 1379 return extractHourMicrosecond(format) 1380 case "HOUR_SECOND": 1381 return extractHourSecond(format) 1382 case "HOUR_MINUTE": 1383 return extractHourMinute(format) 1384 case "DAY_MICROSECOND": 1385 return extractDayMicrosecond(format) 1386 case "DAY_SECOND": 1387 return extractDaySecond(format) 1388 case "DAY_MINUTE": 1389 return extractDayMinute(format) 1390 case "DAY_HOUR": 1391 return extractDayHour(format) 1392 case "YEAR_MONTH": 1393 return extractYearMonth(format) 1394 default: 1395 return 0, 0, 0, 0, errors.Errorf("invalid singel timeunit - %s", unit) 1396 } 1397 } 1398 1399 // IsClockUnit returns true when unit is interval unit with hour, minute or second. 1400 func IsClockUnit(unit string) bool { 1401 switch strings.ToUpper(unit) { 1402 case "MICROSECOND", "SECOND", "MINUTE", "HOUR", 1403 "SECOND_MICROSECOND", "MINUTE_MICROSECOND", "MINUTE_SECOND", 1404 "HOUR_MICROSECOND", "HOUR_SECOND", "HOUR_MINUTE", 1405 "DAY_MICROSECOND", "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR": 1406 return true 1407 default: 1408 return false 1409 } 1410 } 1411 1412 // IsDateFormat returns true when the specified time format could contain only date. 1413 func IsDateFormat(format string) bool { 1414 format = strings.TrimSpace(format) 1415 seps := parseDateFormat(format) 1416 length := len(format) 1417 switch len(seps) { 1418 case 1: 1419 if (length == 8) || (length == 6) { 1420 return true 1421 } 1422 case 3: 1423 return true 1424 } 1425 return false 1426 } 1427 1428 // ParseTimeFromInt64 parses mysql time value from int64. 1429 func ParseTimeFromInt64(num int64) (Time, error) { 1430 return parseDateTimeFromNum(num) 1431 }