github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/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 types
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"math"
    20  	"regexp"
    21  	"strconv"
    22  	"strings"
    23  	gotime "time"
    24  	"unicode"
    25  
    26  	"github.com/pingcap/errors"
    27  
    28  	"github.com/XiaoMi/Gaea/log"
    29  	"github.com/XiaoMi/Gaea/mysql"
    30  	"github.com/XiaoMi/Gaea/parser/stmtctx"
    31  	"github.com/XiaoMi/Gaea/parser/terror"
    32  )
    33  
    34  // Portable of some common call errors.
    35  var (
    36  	ErrInvalidTimeFormat      = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "invalid time format: '%v'")
    37  	ErrInvalidYearFormat      = errors.New("invalid year format")
    38  	ErrInvalidYear            = errors.New("invalid year")
    39  	ErrZeroDate               = errors.New("datetime zero in date")
    40  	ErrIncorrectDatetimeValue = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, "Incorrect datetime value: '%s'")
    41  	ErrTruncatedWrongValue    = terror.ClassTypes.New(mysql.ErrTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue])
    42  )
    43  
    44  // Time format without fractional seconds precision.
    45  const (
    46  	DateFormat = "2006-01-02"
    47  	TimeFormat = "2006-01-02 15:04:05"
    48  	// TimeFSPFormat is time format with fractional seconds precision.
    49  	TimeFSPFormat = "2006-01-02 15:04:05.000000"
    50  )
    51  
    52  const (
    53  	// MinYear is the minimum for mysql year type.
    54  	MinYear int16 = 1901
    55  	// MaxYear is the maximum for mysql year type.
    56  	MaxYear int16 = 2155
    57  	// MaxDuration is the maximum for duration.
    58  	MaxDuration int64 = 838*10000 + 59*100 + 59
    59  	// MinTime is the minimum for mysql time type.
    60  	MinTime = -gotime.Duration(838*3600+59*60+59) * gotime.Second
    61  	// MaxTime is the maximum for mysql time type.
    62  	MaxTime = gotime.Duration(838*3600+59*60+59) * gotime.Second
    63  	// ZeroDatetimeStr is the string representation of a zero datetime.
    64  	ZeroDatetimeStr = "0000-00-00 00:00:00"
    65  	// ZeroDateStr is the string representation of a zero date.
    66  	ZeroDateStr = "0000-00-00"
    67  
    68  	// TimeMaxHour is the max hour for mysql time type.
    69  	TimeMaxHour = 838
    70  	// TimeMaxMinute is the max minute for mysql time type.
    71  	TimeMaxMinute = 59
    72  	// TimeMaxSecond is the max second for mysql time type.
    73  	TimeMaxSecond = 59
    74  	// TimeMaxValue is the maximum value for mysql time type.
    75  	TimeMaxValue = TimeMaxHour*10000 + TimeMaxMinute*100 + TimeMaxSecond
    76  	// TimeMaxValueSeconds is the maximum second value for mysql time type.
    77  	TimeMaxValueSeconds = TimeMaxHour*3600 + TimeMaxMinute*60 + TimeMaxSecond
    78  )
    79  
    80  // Zero values for different types.
    81  var (
    82  	// ZeroDuration is the zero value for Duration type.
    83  	ZeroDuration = Duration{Duration: gotime.Duration(0), Fsp: DefaultFsp}
    84  
    85  	// ZeroTime is the zero value for TimeInternal type.
    86  	ZeroTime = MysqlTime{}
    87  
    88  	// ZeroDatetime is the zero value for datetime Time.
    89  	ZeroDatetime = Time{
    90  		Time: ZeroTime,
    91  		Type: mysql.TypeDatetime,
    92  		Fsp:  DefaultFsp,
    93  	}
    94  
    95  	// ZeroTimestamp is the zero value for timestamp Time.
    96  	ZeroTimestamp = Time{
    97  		Time: ZeroTime,
    98  		Type: mysql.TypeTimestamp,
    99  		Fsp:  DefaultFsp,
   100  	}
   101  
   102  	// ZeroDate is the zero value for date Time.
   103  	ZeroDate = Time{
   104  		Time: ZeroTime,
   105  		Type: mysql.TypeDate,
   106  		Fsp:  DefaultFsp,
   107  	}
   108  )
   109  
   110  var (
   111  	// MinDatetime is the minimum for mysql datetime type.
   112  	MinDatetime = FromDate(1000, 1, 1, 0, 0, 0, 0)
   113  	// MaxDatetime is the maximum for mysql datetime type.
   114  	MaxDatetime = FromDate(9999, 12, 31, 23, 59, 59, 999999)
   115  
   116  	// BoundTimezone is the timezone for min and max timestamp.
   117  	BoundTimezone = gotime.UTC
   118  	// MinTimestamp is the minimum for mysql timestamp type.
   119  	MinTimestamp = Time{
   120  		Time: FromDate(1970, 1, 1, 0, 0, 1, 0),
   121  		Type: mysql.TypeTimestamp,
   122  		Fsp:  DefaultFsp,
   123  	}
   124  	// MaxTimestamp is the maximum for mysql timestamp type.
   125  	MaxTimestamp = Time{
   126  		Time: FromDate(2038, 1, 19, 3, 14, 7, 999999),
   127  		Type: mysql.TypeTimestamp,
   128  		Fsp:  DefaultFsp,
   129  	}
   130  
   131  	// WeekdayNames lists names of weekdays, which are used in builtin time function `dayname`.
   132  	WeekdayNames = []string{
   133  		"Monday",
   134  		"Tuesday",
   135  		"Wednesday",
   136  		"Thursday",
   137  		"Friday",
   138  		"Saturday",
   139  		"Sunday",
   140  	}
   141  
   142  	// MonthNames lists names of months, which are used in builtin time function `monthname`.
   143  	MonthNames = []string{
   144  		"January", "February",
   145  		"March", "April",
   146  		"May", "June",
   147  		"July", "August",
   148  		"September", "October",
   149  		"November", "December",
   150  	}
   151  )
   152  
   153  // FromGoTime translates time.Time to mysql time internal representation.
   154  func FromGoTime(t gotime.Time) MysqlTime {
   155  	year, month, day := t.Date()
   156  	hour, minute, second := t.Clock()
   157  	// Nanosecond plus 500 then divided 1000 means rounding to microseconds.
   158  	microsecond := (t.Nanosecond() + 500) / 1000
   159  	return FromDate(year, int(month), day, hour, minute, second, microsecond)
   160  }
   161  
   162  // FromDate makes a internal time representation from the given date.
   163  func FromDate(year int, month int, day int, hour int, minute int, second int, microsecond int) MysqlTime {
   164  	return MysqlTime{
   165  		uint16(year),
   166  		uint8(month),
   167  		uint8(day),
   168  		hour,
   169  		uint8(minute),
   170  		uint8(second),
   171  		uint32(microsecond),
   172  	}
   173  }
   174  
   175  // Clock returns the hour, minute, and second within the day specified by t.
   176  func (t Time) Clock() (hour int, minute int, second int) {
   177  	return t.Time.Hour(), t.Time.Minute(), t.Time.Second()
   178  }
   179  
   180  // Time is the struct for handling datetime, timestamp and date.
   181  // TODO: check if need a NewTime function to set Fsp default value?
   182  type Time struct {
   183  	Time MysqlTime
   184  	Type uint8
   185  	// Fsp is short for Fractional Seconds Precision.
   186  	// See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
   187  	Fsp int
   188  }
   189  
   190  // MaxMySQLTime returns Time with maximum mysql time type.
   191  func MaxMySQLTime(fsp int) Time {
   192  	return Time{Time: FromDate(0, 0, 0, TimeMaxHour, TimeMaxMinute, TimeMaxSecond, 0), Type: mysql.TypeDuration, Fsp: fsp}
   193  }
   194  
   195  // CurrentTime returns current time with type tp.
   196  func CurrentTime(tp uint8) Time {
   197  	return Time{Time: FromGoTime(gotime.Now()), Type: tp, Fsp: 0}
   198  }
   199  
   200  // ConvertTimeZone converts the time value from one timezone to another.
   201  // The input time should be a valid timestamp.
   202  func (t *Time) ConvertTimeZone(from, to *gotime.Location) error {
   203  	if !t.IsZero() {
   204  		raw, err := t.Time.GoTime(from)
   205  		if err != nil {
   206  			return errors.Trace(err)
   207  		}
   208  		converted := raw.In(to)
   209  		t.Time = FromGoTime(converted)
   210  	}
   211  	return nil
   212  }
   213  
   214  func (t Time) String() string {
   215  	if t.Type == mysql.TypeDate {
   216  		// We control the format, so no error would occur.
   217  		str, err := t.DateFormat("%Y-%m-%d")
   218  		terror.Log(errors.Trace(err))
   219  		return str
   220  	}
   221  
   222  	str, err := t.DateFormat("%Y-%m-%d %H:%i:%s")
   223  	terror.Log(errors.Trace(err))
   224  	if t.Fsp > 0 {
   225  		tmp := fmt.Sprintf(".%06d", t.Time.Microsecond())
   226  		str = str + tmp[:1+t.Fsp]
   227  	}
   228  
   229  	return str
   230  }
   231  
   232  // IsZero returns a boolean indicating whether the time is equal to ZeroTime.
   233  func (t Time) IsZero() bool {
   234  	return compareTime(t.Time, ZeroTime) == 0
   235  }
   236  
   237  // InvalidZero returns a boolean indicating whether the month or day is zero.
   238  func (t Time) InvalidZero() bool {
   239  	return t.Time.Month() == 0 || t.Time.Day() == 0
   240  }
   241  
   242  const numberFormat = "%Y%m%d%H%i%s"
   243  const dateFormat = "%Y%m%d"
   244  
   245  // ToNumber returns a formatted number.
   246  // e.g,
   247  // 2012-12-12 -> 20121212
   248  // 2012-12-12T10:10:10 -> 20121212101010
   249  // 2012-12-12T10:10:10.123456 -> 20121212101010.123456
   250  func (t Time) ToNumber() *MyDecimal {
   251  	if t.IsZero() {
   252  		return &MyDecimal{}
   253  	}
   254  
   255  	// Fix issue #1046
   256  	// Prevents from converting 2012-12-12 to 20121212000000
   257  	var tfStr string
   258  	if t.Type == mysql.TypeDate {
   259  		tfStr = dateFormat
   260  	} else {
   261  		tfStr = numberFormat
   262  	}
   263  
   264  	s, err := t.DateFormat(tfStr)
   265  	if err != nil {
   266  		log.Warn("Fatal: never happen because we've control the format!")
   267  	}
   268  
   269  	if t.Fsp > 0 {
   270  		s1 := fmt.Sprintf("%s.%06d", s, t.Time.Microsecond())
   271  		s = s1[:len(s)+t.Fsp+1]
   272  	}
   273  
   274  	// We skip checking error here because time formatted string can be parsed certainly.
   275  	dec := new(MyDecimal)
   276  	err = dec.FromString([]byte(s))
   277  	terror.Log(errors.Trace(err))
   278  	return dec
   279  }
   280  
   281  // Convert converts t with type tp.
   282  func (t Time) Convert(sc *stmtctx.StatementContext, tp uint8) (Time, error) {
   283  	if t.Type == tp || t.IsZero() {
   284  		return Time{Time: t.Time, Type: tp, Fsp: t.Fsp}, nil
   285  	}
   286  
   287  	t1 := Time{Time: t.Time, Type: tp, Fsp: t.Fsp}
   288  	err := t1.check(sc)
   289  	return t1, errors.Trace(err)
   290  }
   291  
   292  // ConvertToDuration converts mysql datetime, timestamp and date to mysql time type.
   293  // e.g,
   294  // 2012-12-12T10:10:10 -> 10:10:10
   295  // 2012-12-12 -> 0
   296  func (t Time) ConvertToDuration() (Duration, error) {
   297  	if t.IsZero() {
   298  		return ZeroDuration, nil
   299  	}
   300  
   301  	hour, minute, second := t.Clock()
   302  	frac := t.Time.Microsecond() * 1000
   303  
   304  	d := gotime.Duration(hour*3600+minute*60+second)*gotime.Second + gotime.Duration(frac)
   305  	// TODO: check convert validation
   306  	return Duration{Duration: d, Fsp: t.Fsp}, nil
   307  }
   308  
   309  // Compare returns an integer comparing the time instant t to o.
   310  // If t is after o, return 1, equal o, return 0, before o, return -1.
   311  func (t Time) Compare(o Time) int {
   312  	return compareTime(t.Time, o.Time)
   313  }
   314  
   315  // compareTime compare two MysqlTime.
   316  // return:
   317  //  0: if a == b
   318  //  1: if a > b
   319  // -1: if a < b
   320  func compareTime(a, b MysqlTime) int {
   321  	ta := datetimeToUint64(a)
   322  	tb := datetimeToUint64(b)
   323  
   324  	switch {
   325  	case ta < tb:
   326  		return -1
   327  	case ta > tb:
   328  		return 1
   329  	}
   330  
   331  	switch {
   332  	case a.Microsecond() < b.Microsecond():
   333  		return -1
   334  	case a.Microsecond() > b.Microsecond():
   335  		return 1
   336  	}
   337  
   338  	return 0
   339  }
   340  
   341  // CompareString is like Compare,
   342  // but parses string to Time then compares.
   343  func (t Time) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {
   344  	// use MaxFsp to parse the string
   345  	o, err := ParseTime(sc, str, t.Type, MaxFsp)
   346  	if err != nil {
   347  		return 0, errors.Trace(err)
   348  	}
   349  
   350  	return t.Compare(o), nil
   351  }
   352  
   353  // roundTime rounds the time value according to digits count specified by fsp.
   354  func roundTime(t gotime.Time, fsp int) gotime.Time {
   355  	d := gotime.Duration(math.Pow10(9 - fsp))
   356  	return t.Round(d)
   357  }
   358  
   359  // RoundFrac rounds the fraction part of a time-type value according to `fsp`.
   360  func (t Time) RoundFrac(sc *stmtctx.StatementContext, fsp int) (Time, error) {
   361  	if t.Type == mysql.TypeDate || t.IsZero() {
   362  		// date type has no fsp
   363  		return t, nil
   364  	}
   365  
   366  	fsp, err := CheckFsp(fsp)
   367  	if err != nil {
   368  		return t, errors.Trace(err)
   369  	}
   370  
   371  	if fsp == t.Fsp {
   372  		// have same fsp
   373  		return t, nil
   374  	}
   375  
   376  	var nt MysqlTime
   377  	if t1, err := t.Time.GoTime(sc.TimeZone); err == nil {
   378  		t1 = roundTime(t1, fsp)
   379  		nt = FromGoTime(t1)
   380  	} else {
   381  		// Take the hh:mm:ss part out to avoid handle month or day = 0.
   382  		hour, minute, second, microsecond := t.Time.Hour(), t.Time.Minute(), t.Time.Second(), t.Time.Microsecond()
   383  		t1 := gotime.Date(1, 1, 1, hour, minute, second, microsecond*1000, gotime.Local)
   384  		t2 := roundTime(t1, fsp)
   385  		hour, minute, second = t2.Clock()
   386  		microsecond = t2.Nanosecond() / 1000
   387  
   388  		// TODO: when hh:mm:ss overflow one day after rounding, it should be add to yy:mm:dd part,
   389  		// but mm:dd may contain 0, it makes the code complex, so we ignore it here.
   390  		if t2.Day()-1 > 0 {
   391  			return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(t.String()))
   392  		}
   393  		nt = FromDate(t.Time.Year(), t.Time.Month(), t.Time.Day(), hour, minute, second, microsecond)
   394  	}
   395  
   396  	return Time{Time: nt, Type: t.Type, Fsp: fsp}, nil
   397  }
   398  
   399  // GetFsp gets the fsp of a string.
   400  func GetFsp(s string) (fsp int) {
   401  	fsp = len(s) - strings.LastIndex(s, ".") - 1
   402  	if fsp == len(s) {
   403  		fsp = 0
   404  	} else if fsp > 6 {
   405  		fsp = 6
   406  	}
   407  	return
   408  }
   409  
   410  // RoundFrac rounds fractional seconds precision with new fsp and returns a new one.
   411  // We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,
   412  // so 2011:11:11 10:10:10.888888 round 0 -> 2011:11:11 10:10:11
   413  // and 2011:11:11 10:10:10.111111 round 0 -> 2011:11:11 10:10:10
   414  func RoundFrac(t gotime.Time, fsp int) (gotime.Time, error) {
   415  	_, err := CheckFsp(fsp)
   416  	if err != nil {
   417  		return t, errors.Trace(err)
   418  	}
   419  	return t.Round(gotime.Duration(math.Pow10(9-fsp)) * gotime.Nanosecond), nil
   420  }
   421  
   422  // ToPackedUint encodes Time to a packed uint64 value.
   423  //
   424  //    1 bit  0
   425  //   17 bits year*13+month   (year 0-9999, month 0-12)
   426  //    5 bits day             (0-31)
   427  //    5 bits hour            (0-23)
   428  //    6 bits minute          (0-59)
   429  //    6 bits second          (0-59)
   430  //   24 bits microseconds    (0-999999)
   431  //
   432  //   Total: 64 bits = 8 bytes
   433  //
   434  //   0YYYYYYY.YYYYYYYY.YYdddddh.hhhhmmmm.mmssssss.ffffffff.ffffffff.ffffffff
   435  //
   436  func (t Time) ToPackedUint() (uint64, error) {
   437  	tm := t.Time
   438  	if t.IsZero() {
   439  		return 0, nil
   440  	}
   441  	year, month, day := tm.Year(), tm.Month(), tm.Day()
   442  	hour, minute, sec := tm.Hour(), tm.Minute(), tm.Second()
   443  	ymd := uint64(((year*13 + month) << 5) | day)
   444  	hms := uint64(hour<<12 | minute<<6 | sec)
   445  	micro := uint64(tm.Microsecond())
   446  	return ((ymd<<17 | hms) << 24) | micro, nil
   447  }
   448  
   449  // FromPackedUint decodes Time from a packed uint64 value.
   450  func (t *Time) FromPackedUint(packed uint64) error {
   451  	if packed == 0 {
   452  		t.Time = ZeroTime
   453  		return nil
   454  	}
   455  	ymdhms := packed >> 24
   456  	ymd := ymdhms >> 17
   457  	day := int(ymd & (1<<5 - 1))
   458  	ym := ymd >> 5
   459  	month := int(ym % 13)
   460  	year := int(ym / 13)
   461  
   462  	hms := ymdhms & (1<<17 - 1)
   463  	second := int(hms & (1<<6 - 1))
   464  	minute := int((hms >> 6) & (1<<6 - 1))
   465  	hour := int(hms >> 12)
   466  	microsec := int(packed % (1 << 24))
   467  
   468  	t.Time = FromDate(year, month, day, hour, minute, second, microsec)
   469  
   470  	return nil
   471  }
   472  
   473  // check whether t matches valid Time format.
   474  // If allowZeroInDate is false, it returns ErrZeroDate when month or day is zero.
   475  // FIXME: See https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_in_date
   476  func (t *Time) check(sc *stmtctx.StatementContext) error {
   477  	allowZeroInDate := false
   478  	allowInvalidDate := false
   479  	// We should avoid passing sc as nil here as far as possible.
   480  	if sc != nil {
   481  		allowZeroInDate = sc.IgnoreZeroInDate
   482  		allowInvalidDate = sc.AllowInvalidDate
   483  	}
   484  	var err error
   485  	switch t.Type {
   486  	case mysql.TypeTimestamp:
   487  		err = checkTimestampType(sc, t.Time)
   488  	case mysql.TypeDatetime:
   489  		err = checkDatetimeType(t.Time, allowZeroInDate, allowInvalidDate)
   490  	case mysql.TypeDate:
   491  		err = checkDateType(t.Time, allowZeroInDate, allowInvalidDate)
   492  	}
   493  	return errors.Trace(err)
   494  }
   495  
   496  // Check if 't' is valid
   497  func (t *Time) Check(sc *stmtctx.StatementContext) error {
   498  	return t.check(sc)
   499  }
   500  
   501  // Sub subtracts t1 from t, returns a duration value.
   502  // Note that sub should not be done on different time types.
   503  func (t *Time) Sub(sc *stmtctx.StatementContext, t1 *Time) Duration {
   504  	var duration gotime.Duration
   505  	if t.Type == mysql.TypeTimestamp && t1.Type == mysql.TypeTimestamp {
   506  		a, err := t.Time.GoTime(sc.TimeZone)
   507  		terror.Log(errors.Trace(err))
   508  		b, err := t1.Time.GoTime(sc.TimeZone)
   509  		terror.Log(errors.Trace(err))
   510  		duration = a.Sub(b)
   511  	} else {
   512  		seconds, microseconds, neg := calcTimeDiff(t.Time, t1.Time, 1)
   513  		duration = gotime.Duration(seconds*1e9 + microseconds*1e3)
   514  		if neg {
   515  			duration = -duration
   516  		}
   517  	}
   518  
   519  	fsp := t.Fsp
   520  	if fsp < t1.Fsp {
   521  		fsp = t1.Fsp
   522  	}
   523  	return Duration{
   524  		Duration: duration,
   525  		Fsp:      fsp,
   526  	}
   527  }
   528  
   529  // Add adds d to t, returns the result time value.
   530  func (t *Time) Add(sc *stmtctx.StatementContext, d Duration) (Time, error) {
   531  	sign, hh, mm, ss, micro := splitDuration(d.Duration)
   532  	seconds, microseconds, _ := calcTimeDiff(t.Time, FromDate(0, 0, 0, hh, mm, ss, micro), -sign)
   533  	days := seconds / secondsIn24Hour
   534  	year, month, day := getDateFromDaynr(uint(days))
   535  	var tm MysqlTime
   536  	tm.year, tm.month, tm.day = uint16(year), uint8(month), uint8(day)
   537  	calcTimeFromSec(&tm, seconds%secondsIn24Hour, microseconds)
   538  	if t.Type == mysql.TypeDate {
   539  		tm.hour = 0
   540  		tm.minute = 0
   541  		tm.second = 0
   542  		tm.microsecond = 0
   543  	}
   544  	fsp := t.Fsp
   545  	if d.Fsp > fsp {
   546  		fsp = d.Fsp
   547  	}
   548  	ret := Time{
   549  		Time: tm,
   550  		Type: t.Type,
   551  		Fsp:  fsp,
   552  	}
   553  	return ret, ret.Check(sc)
   554  }
   555  
   556  // TimestampDiff returns t2 - t1 where t1 and t2 are date or datetime expressions.
   557  // The unit for the result (an integer) is given by the unit argument.
   558  // The legal values for unit are "YEAR" "QUARTER" "MONTH" "DAY" "HOUR" "SECOND" and so on.
   559  func TimestampDiff(unit string, t1 Time, t2 Time) int64 {
   560  	return timestampDiff(unit, t1.Time, t2.Time)
   561  }
   562  
   563  // ParseDateFormat parses a formatted date string and returns separated components.
   564  func ParseDateFormat(format string) []string {
   565  	format = strings.TrimSpace(format)
   566  
   567  	start := 0
   568  	var seps = make([]string, 0)
   569  	for i := 0; i < len(format); i++ {
   570  		// Date format must start and end with number.
   571  		if i == 0 || i == len(format)-1 {
   572  			if !unicode.IsNumber(rune(format[i])) {
   573  				return nil
   574  			}
   575  
   576  			continue
   577  		}
   578  
   579  		// Separator is a single none-number char.
   580  		if !unicode.IsNumber(rune(format[i])) {
   581  			if !unicode.IsNumber(rune(format[i-1])) {
   582  				return nil
   583  			}
   584  
   585  			seps = append(seps, format[start:i])
   586  			start = i + 1
   587  		}
   588  
   589  	}
   590  
   591  	seps = append(seps, format[start:])
   592  	return seps
   593  }
   594  
   595  // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.
   596  // The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.
   597  func splitDateTime(format string) (seps []string, fracStr string) {
   598  	if i := strings.LastIndex(format, "."); i > 0 {
   599  		fracStr = strings.TrimSpace(format[i+1:])
   600  		format = format[:i]
   601  	}
   602  
   603  	seps = ParseDateFormat(format)
   604  	return
   605  }
   606  
   607  // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html.
   608  func parseDatetime(sc *stmtctx.StatementContext, str string, fsp int, isFloat bool) (Time, error) {
   609  	// Try to split str with delimiter.
   610  	// TODO: only punctuation can be the delimiter for date parts or time parts.
   611  	// But only space and T can be the delimiter between the date and time part.
   612  	var (
   613  		year, month, day, hour, minute, second int
   614  		fracStr                                string
   615  		hhmmss                                 bool
   616  		err                                    error
   617  	)
   618  
   619  	seps, fracStr := splitDateTime(str)
   620  	var truncatedOrIncorrect bool
   621  	switch len(seps) {
   622  	case 1:
   623  		l := len(seps[0])
   624  		switch l {
   625  		case 14: // No delimiter.
   626  			// YYYYMMDDHHMMSS
   627  			_, err = fmt.Sscanf(seps[0], "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second)
   628  			hhmmss = true
   629  		case 12: // YYMMDDHHMMSS
   630  			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute, &second)
   631  			year = adjustYear(year)
   632  			hhmmss = true
   633  		case 11: // YYMMDDHHMMS
   634  			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d%1d", &year, &month, &day, &hour, &minute, &second)
   635  			year = adjustYear(year)
   636  			hhmmss = true
   637  		case 10: // YYMMDDHHMM
   638  			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%2d", &year, &month, &day, &hour, &minute)
   639  			year = adjustYear(year)
   640  		case 9: // YYMMDDHHM
   641  			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d%2d%1d", &year, &month, &day, &hour, &minute)
   642  			year = adjustYear(year)
   643  		case 8: // YYYYMMDD
   644  			_, err = fmt.Sscanf(seps[0], "%4d%2d%2d", &year, &month, &day)
   645  		case 6, 5:
   646  			// YYMMDD && YYMMD
   647  			_, err = fmt.Sscanf(seps[0], "%2d%2d%2d", &year, &month, &day)
   648  			year = adjustYear(year)
   649  		default:
   650  			return ZeroDatetime, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(str))
   651  		}
   652  		if l == 5 || l == 6 || l == 8 {
   653  			// YYMMDD or YYYYMMDD
   654  			// We must handle float => string => datetime, the difference is that fractional
   655  			// part of float type is discarded directly, while fractional part of string type
   656  			// is parsed to HH:MM:SS.
   657  			if isFloat {
   658  				// 20170118.123423 => 2017-01-18 00:00:00
   659  			} else {
   660  				// '20170118.123423' => 2017-01-18 12:34:23.234
   661  				switch len(fracStr) {
   662  				case 0:
   663  				case 1, 2:
   664  					_, err = fmt.Sscanf(fracStr, "%2d ", &hour)
   665  				case 3, 4:
   666  					_, err = fmt.Sscanf(fracStr, "%2d%2d ", &hour, &minute)
   667  				default:
   668  					_, err = fmt.Sscanf(fracStr, "%2d%2d%2d ", &hour, &minute, &second)
   669  				}
   670  				truncatedOrIncorrect = err != nil
   671  			}
   672  		}
   673  		if l == 9 || l == 10 {
   674  			if len(fracStr) == 0 {
   675  				second = 0
   676  			} else {
   677  				_, err = fmt.Sscanf(fracStr, "%2d ", &second)
   678  			}
   679  			truncatedOrIncorrect = err != nil
   680  		}
   681  		if truncatedOrIncorrect && sc != nil {
   682  			sc.AppendWarning(ErrTruncatedWrongValue.GenWithStackByArgs("datetime", str))
   683  			err = nil
   684  		}
   685  	case 3:
   686  		// YYYY-MM-DD
   687  		err = scanTimeArgs(seps, &year, &month, &day)
   688  	case 4:
   689  		// YYYY-MM-DD HH
   690  		err = scanTimeArgs(seps, &year, &month, &day, &hour)
   691  	case 5:
   692  		// YYYY-MM-DD HH-MM
   693  		err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute)
   694  	case 6:
   695  		// We don't have fractional seconds part.
   696  		// YYYY-MM-DD HH-MM-SS
   697  		err = scanTimeArgs(seps, &year, &month, &day, &hour, &minute, &second)
   698  		hhmmss = true
   699  	default:
   700  		return ZeroDatetime, errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(str))
   701  	}
   702  	if err != nil {
   703  		return ZeroDatetime, errors.Trace(err)
   704  	}
   705  
   706  	// If str is sepereated by delimiters, the first one is year, and if the year is 2 digit,
   707  	// we should adjust it.
   708  	// TODO: adjust year is very complex, now we only consider the simplest way.
   709  	if len(seps[0]) == 2 {
   710  		if year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 && second == 0 && fracStr == "" {
   711  			// Skip a special case "00-00-00".
   712  		} else {
   713  			year = adjustYear(year)
   714  		}
   715  	}
   716  
   717  	var microsecond int
   718  	var overflow bool
   719  	if hhmmss {
   720  		// If input string is "20170118.999", without hhmmss, fsp is meanless.
   721  		microsecond, overflow, err = ParseFrac(fracStr, fsp)
   722  		if err != nil {
   723  			return ZeroDatetime, errors.Trace(err)
   724  		}
   725  	}
   726  
   727  	tmp := FromDate(year, month, day, hour, minute, second, microsecond)
   728  	if overflow {
   729  		// Convert to Go time and add 1 second, to handle input like 2017-01-05 08:40:59.575601
   730  		t1, err := tmp.GoTime(gotime.Local)
   731  		if err != nil {
   732  			return ZeroDatetime, errors.Trace(err)
   733  		}
   734  		tmp = FromGoTime(t1.Add(gotime.Second))
   735  	}
   736  
   737  	nt := Time{
   738  		Time: tmp,
   739  		Type: mysql.TypeDatetime,
   740  		Fsp:  fsp}
   741  
   742  	return nt, nil
   743  }
   744  
   745  func scanTimeArgs(seps []string, args ...*int) error {
   746  	if len(seps) != len(args) {
   747  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(seps))
   748  	}
   749  
   750  	var err error
   751  	for i, s := range seps {
   752  		*args[i], err = strconv.Atoi(s)
   753  		if err != nil {
   754  			return errors.Trace(err)
   755  		}
   756  	}
   757  	return nil
   758  }
   759  
   760  // ParseYear parses a formatted string and returns a year number.
   761  func ParseYear(str string) (int16, error) {
   762  	v, err := strconv.ParseInt(str, 10, 16)
   763  	if err != nil {
   764  		return 0, errors.Trace(err)
   765  	}
   766  	y := int16(v)
   767  
   768  	if len(str) == 4 {
   769  		// Nothing to do.
   770  	} else if len(str) == 2 || len(str) == 1 {
   771  		y = int16(adjustYear(int(y)))
   772  	} else {
   773  		return 0, errors.Trace(ErrInvalidYearFormat)
   774  	}
   775  
   776  	if y < MinYear || y > MaxYear {
   777  		return 0, errors.Trace(ErrInvalidYearFormat)
   778  	}
   779  
   780  	return y, nil
   781  }
   782  
   783  // adjustYear adjusts year according to y.
   784  // See https://dev.mysql.com/doc/refman/5.7/en/two-digit-years.html
   785  func adjustYear(y int) int {
   786  	if y >= 0 && y <= 69 {
   787  		y = 2000 + y
   788  	} else if y >= 70 && y <= 99 {
   789  		y = 1900 + y
   790  	}
   791  	return y
   792  }
   793  
   794  // AdjustYear is used for adjusting year and checking its validation.
   795  func AdjustYear(y int64, shouldAdjust bool) (int64, error) {
   796  	if y == 0 && !shouldAdjust {
   797  		return y, nil
   798  	}
   799  	y = int64(adjustYear(int(y)))
   800  	if y < int64(MinYear) || y > int64(MaxYear) {
   801  		return 0, errors.Trace(ErrInvalidYear)
   802  	}
   803  
   804  	return y, nil
   805  }
   806  
   807  // Duration is the type for MySQL TIME type.
   808  type Duration struct {
   809  	gotime.Duration
   810  	// Fsp is short for Fractional Seconds Precision.
   811  	// See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
   812  	Fsp int
   813  }
   814  
   815  //Add adds d to d, returns a duration value.
   816  func (d Duration) Add(v Duration) (Duration, error) {
   817  	if &v == nil {
   818  		return d, nil
   819  	}
   820  	dsum, err := AddInt64(int64(d.Duration), int64(v.Duration))
   821  	if err != nil {
   822  		return Duration{}, errors.Trace(err)
   823  	}
   824  	if d.Fsp >= v.Fsp {
   825  		return Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil
   826  	}
   827  	return Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil
   828  }
   829  
   830  // Sub subtracts d to d, returns a duration value.
   831  func (d Duration) Sub(v Duration) (Duration, error) {
   832  	if &v == nil {
   833  		return d, nil
   834  	}
   835  	dsum, err := SubInt64(int64(d.Duration), int64(v.Duration))
   836  	if err != nil {
   837  		return Duration{}, errors.Trace(err)
   838  	}
   839  	if d.Fsp >= v.Fsp {
   840  		return Duration{Duration: gotime.Duration(dsum), Fsp: d.Fsp}, nil
   841  	}
   842  	return Duration{Duration: gotime.Duration(dsum), Fsp: v.Fsp}, nil
   843  }
   844  
   845  // String returns the time formatted using default TimeFormat and fsp.
   846  func (d Duration) String() string {
   847  	var buf bytes.Buffer
   848  
   849  	sign, hours, minutes, seconds, fraction := splitDuration(d.Duration)
   850  	if sign < 0 {
   851  		buf.WriteByte('-')
   852  	}
   853  
   854  	fmt.Fprintf(&buf, "%02d:%02d:%02d", hours, minutes, seconds)
   855  	if d.Fsp > 0 {
   856  		buf.WriteString(".")
   857  		buf.WriteString(d.formatFrac(fraction))
   858  	}
   859  
   860  	p := buf.String()
   861  
   862  	return p
   863  }
   864  
   865  func (d Duration) formatFrac(frac int) string {
   866  	s := fmt.Sprintf("%06d", frac)
   867  	return s[0:d.Fsp]
   868  }
   869  
   870  // ToNumber changes duration to number format.
   871  // e.g,
   872  // 10:10:10 -> 101010
   873  func (d Duration) ToNumber() *MyDecimal {
   874  	sign, hours, minutes, seconds, fraction := splitDuration(d.Duration)
   875  	var (
   876  		s       string
   877  		signStr string
   878  	)
   879  
   880  	if sign < 0 {
   881  		signStr = "-"
   882  	}
   883  
   884  	if d.Fsp == 0 {
   885  		s = fmt.Sprintf("%s%02d%02d%02d", signStr, hours, minutes, seconds)
   886  	} else {
   887  		s = fmt.Sprintf("%s%02d%02d%02d.%s", signStr, hours, minutes, seconds, d.formatFrac(fraction))
   888  	}
   889  
   890  	// We skip checking error here because time formatted string can be parsed certainly.
   891  	dec := new(MyDecimal)
   892  	err := dec.FromString([]byte(s))
   893  	terror.Log(errors.Trace(err))
   894  	return dec
   895  }
   896  
   897  // ConvertToTime converts duration to Time.
   898  // Tp is TypeDatetime, TypeTimestamp and TypeDate.
   899  func (d Duration) ConvertToTime(sc *stmtctx.StatementContext, tp uint8) (Time, error) {
   900  	year, month, day := gotime.Now().In(sc.TimeZone).Date()
   901  	sign, hour, minute, second, frac := splitDuration(d.Duration)
   902  	datePart := FromDate(year, int(month), day, 0, 0, 0, 0)
   903  	timePart := FromDate(0, 0, 0, hour, minute, second, frac)
   904  	mixDateAndTime(&datePart, &timePart, sign < 0)
   905  
   906  	t := Time{
   907  		Time: datePart,
   908  		Type: mysql.TypeDatetime,
   909  		Fsp:  d.Fsp,
   910  	}
   911  	return t.Convert(sc, tp)
   912  }
   913  
   914  // RoundFrac rounds fractional seconds precision with new fsp and returns a new one.
   915  // We will use the “round half up” rule, e.g, >= 0.5 -> 1, < 0.5 -> 0,
   916  // so 10:10:10.999999 round 0 -> 10:10:11
   917  // and 10:10:10.000000 round 0 -> 10:10:10
   918  func (d Duration) RoundFrac(fsp int) (Duration, error) {
   919  	fsp, err := CheckFsp(fsp)
   920  	if err != nil {
   921  		return d, errors.Trace(err)
   922  	}
   923  
   924  	if fsp == d.Fsp {
   925  		return d, nil
   926  	}
   927  
   928  	n := gotime.Date(0, 0, 0, 0, 0, 0, 0, gotime.Local)
   929  	nd := n.Add(d.Duration).Round(gotime.Duration(math.Pow10(9-fsp)) * gotime.Nanosecond).Sub(n)
   930  	return Duration{Duration: nd, Fsp: fsp}, nil
   931  }
   932  
   933  // Compare returns an integer comparing the Duration instant t to o.
   934  // If d is after o, return 1, equal o, return 0, before o, return -1.
   935  func (d Duration) Compare(o Duration) int {
   936  	if d.Duration > o.Duration {
   937  		return 1
   938  	} else if d.Duration == o.Duration {
   939  		return 0
   940  	} else {
   941  		return -1
   942  	}
   943  }
   944  
   945  // CompareString is like Compare,
   946  // but parses str to Duration then compares.
   947  func (d Duration) CompareString(sc *stmtctx.StatementContext, str string) (int, error) {
   948  	// use MaxFsp to parse the string
   949  	o, err := ParseDuration(sc, str, MaxFsp)
   950  	if err != nil {
   951  		return 0, err
   952  	}
   953  
   954  	return d.Compare(o), nil
   955  }
   956  
   957  // Hour returns current hour.
   958  // e.g, hour("11:11:11") -> 11
   959  func (d Duration) Hour() int {
   960  	_, hour, _, _, _ := splitDuration(d.Duration)
   961  	return hour
   962  }
   963  
   964  // Minute returns current minute.
   965  // e.g, hour("11:11:11") -> 11
   966  func (d Duration) Minute() int {
   967  	_, _, minute, _, _ := splitDuration(d.Duration)
   968  	return minute
   969  }
   970  
   971  // Second returns current second.
   972  // e.g, hour("11:11:11") -> 11
   973  func (d Duration) Second() int {
   974  	_, _, _, second, _ := splitDuration(d.Duration)
   975  	return second
   976  }
   977  
   978  // MicroSecond returns current microsecond.
   979  // e.g, hour("11:11:11.11") -> 110000
   980  func (d Duration) MicroSecond() int {
   981  	_, _, _, _, frac := splitDuration(d.Duration)
   982  	return frac
   983  }
   984  
   985  // ParseDuration parses the time form a formatted string with a fractional seconds part,
   986  // returns the duration type Time value.
   987  // See http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
   988  func ParseDuration(sc *stmtctx.StatementContext, str string, fsp int) (Duration, error) {
   989  	var (
   990  		day, hour, minute, second int
   991  		err                       error
   992  		sign                      = 0
   993  		dayExists                 = false
   994  		origStr                   = str
   995  	)
   996  
   997  	fsp, err = CheckFsp(fsp)
   998  	if err != nil {
   999  		return ZeroDuration, errors.Trace(err)
  1000  	}
  1001  
  1002  	if len(str) == 0 {
  1003  		return ZeroDuration, nil
  1004  	} else if str[0] == '-' {
  1005  		str = str[1:]
  1006  		sign = -1
  1007  	}
  1008  
  1009  	// Time format may has day.
  1010  	if n := strings.IndexByte(str, ' '); n >= 0 {
  1011  		if day, err = strconv.Atoi(str[:n]); err == nil {
  1012  			dayExists = true
  1013  		}
  1014  		str = str[n+1:]
  1015  	}
  1016  
  1017  	var (
  1018  		integeralPart = str
  1019  		fracPart      int
  1020  		overflow      bool
  1021  	)
  1022  	if n := strings.IndexByte(str, '.'); n >= 0 {
  1023  		// It has fractional precision parts.
  1024  		fracStr := str[n+1:]
  1025  		fracPart, overflow, err = ParseFrac(fracStr, fsp)
  1026  		if err != nil {
  1027  			return ZeroDuration, errors.Trace(err)
  1028  		}
  1029  		integeralPart = str[0:n]
  1030  	}
  1031  
  1032  	// It tries to split integeralPart with delimiter, time delimiter must be :
  1033  	seps := strings.Split(integeralPart, ":")
  1034  
  1035  	switch len(seps) {
  1036  	case 1:
  1037  		if dayExists {
  1038  			hour, err = strconv.Atoi(seps[0])
  1039  		} else {
  1040  			// No delimiter.
  1041  			switch len(integeralPart) {
  1042  			case 7: // HHHMMSS
  1043  				_, err = fmt.Sscanf(integeralPart, "%3d%2d%2d", &hour, &minute, &second)
  1044  			case 6: // HHMMSS
  1045  				_, err = fmt.Sscanf(integeralPart, "%2d%2d%2d", &hour, &minute, &second)
  1046  			case 5: // HMMSS
  1047  				_, err = fmt.Sscanf(integeralPart, "%1d%2d%2d", &hour, &minute, &second)
  1048  			case 4: // MMSS
  1049  				_, err = fmt.Sscanf(integeralPart, "%2d%2d", &minute, &second)
  1050  			case 3: // MSS
  1051  				_, err = fmt.Sscanf(integeralPart, "%1d%2d", &minute, &second)
  1052  			case 2: // SS
  1053  				_, err = fmt.Sscanf(integeralPart, "%2d", &second)
  1054  			case 1: // 0S
  1055  				_, err = fmt.Sscanf(integeralPart, "%1d", &second)
  1056  			default: // Maybe contains date.
  1057  				t, err1 := ParseDatetime(sc, str)
  1058  				if err1 != nil {
  1059  					return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
  1060  				}
  1061  				var dur Duration
  1062  				dur, err1 = t.ConvertToDuration()
  1063  				if err1 != nil {
  1064  					return ZeroDuration, errors.Trace(err)
  1065  				}
  1066  				return dur.RoundFrac(fsp)
  1067  			}
  1068  		}
  1069  	case 2:
  1070  		// HH:MM
  1071  		_, err = fmt.Sscanf(integeralPart, "%2d:%2d", &hour, &minute)
  1072  	case 3:
  1073  		// Time format maybe HH:MM:SS or HHH:MM:SS.
  1074  		// See https://dev.mysql.com/doc/refman/5.7/en/time.html
  1075  		if len(seps[0]) == 3 {
  1076  			_, err = fmt.Sscanf(integeralPart, "%3d:%2d:%2d", &hour, &minute, &second)
  1077  		} else {
  1078  			_, err = fmt.Sscanf(integeralPart, "%2d:%2d:%2d", &hour, &minute, &second)
  1079  		}
  1080  	default:
  1081  		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
  1082  	}
  1083  
  1084  	if err != nil {
  1085  		return ZeroDuration, errors.Trace(err)
  1086  	}
  1087  
  1088  	if overflow {
  1089  		second++
  1090  		fracPart = 0
  1091  	}
  1092  	// Invalid TIME values are converted to '00:00:00'.
  1093  	// See https://dev.mysql.com/doc/refman/5.7/en/time.html
  1094  	if minute >= 60 || second > 60 || (!overflow && second == 60) {
  1095  		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
  1096  	}
  1097  	d := gotime.Duration(day*24*3600+hour*3600+minute*60+second)*gotime.Second + gotime.Duration(fracPart)*gotime.Microsecond
  1098  	if sign == -1 {
  1099  		d = -d
  1100  	}
  1101  
  1102  	d, err = TruncateOverflowMySQLTime(d)
  1103  	return Duration{Duration: d, Fsp: fsp}, errors.Trace(err)
  1104  }
  1105  
  1106  // TruncateOverflowMySQLTime truncates d when it overflows, and return ErrTruncatedWrongVal.
  1107  func TruncateOverflowMySQLTime(d gotime.Duration) (gotime.Duration, error) {
  1108  	if d > MaxTime {
  1109  		return MaxTime, ErrTruncatedWrongVal.GenWithStackByArgs("time", d.String())
  1110  	} else if d < MinTime {
  1111  		return MinTime, ErrTruncatedWrongVal.GenWithStackByArgs("time", d.String())
  1112  	}
  1113  
  1114  	return d, nil
  1115  }
  1116  
  1117  func splitDuration(t gotime.Duration) (int, int, int, int, int) {
  1118  	sign := 1
  1119  	if t < 0 {
  1120  		t = -t
  1121  		sign = -1
  1122  	}
  1123  
  1124  	hours := t / gotime.Hour
  1125  	t -= hours * gotime.Hour
  1126  	minutes := t / gotime.Minute
  1127  	t -= minutes * gotime.Minute
  1128  	seconds := t / gotime.Second
  1129  	t -= seconds * gotime.Second
  1130  	fraction := t / gotime.Microsecond
  1131  
  1132  	return sign, int(hours), int(minutes), int(seconds), int(fraction)
  1133  }
  1134  
  1135  var maxDaysInMonth = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  1136  
  1137  func getTime(sc *stmtctx.StatementContext, num int64, tp byte) (Time, error) {
  1138  	s1 := num / 1000000
  1139  	s2 := num - s1*1000000
  1140  
  1141  	year := int(s1 / 10000)
  1142  	s1 %= 10000
  1143  	month := int(s1 / 100)
  1144  	day := int(s1 % 100)
  1145  
  1146  	hour := int(s2 / 10000)
  1147  	s2 %= 10000
  1148  	minute := int(s2 / 100)
  1149  	second := int(s2 % 100)
  1150  
  1151  	t := Time{
  1152  		Time: FromDate(year, month, day, hour, minute, second, 0),
  1153  		Type: tp,
  1154  		Fsp:  DefaultFsp,
  1155  	}
  1156  	err := t.check(sc)
  1157  	return t, errors.Trace(err)
  1158  }
  1159  
  1160  // parseDateTimeFromNum parses date time from num.
  1161  // See number_to_datetime function.
  1162  // https://github.com/mysql/mysql-server/blob/5.7/sql-common/my_time.c
  1163  func parseDateTimeFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {
  1164  	t := ZeroDate
  1165  	// Check zero.
  1166  	if num == 0 {
  1167  		return t, nil
  1168  	}
  1169  
  1170  	// Check datetime type.
  1171  	if num >= 10000101000000 {
  1172  		t.Type = mysql.TypeDatetime
  1173  		return getTime(sc, num, t.Type)
  1174  	}
  1175  
  1176  	// Check MMDD.
  1177  	if num < 101 {
  1178  		return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(num))
  1179  	}
  1180  
  1181  	// Adjust year
  1182  	// YYMMDD, year: 2000-2069
  1183  	if num <= (70-1)*10000+1231 {
  1184  		num = (num + 20000000) * 1000000
  1185  		return getTime(sc, num, t.Type)
  1186  	}
  1187  
  1188  	// Check YYMMDD.
  1189  	if num < 70*10000+101 {
  1190  		return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(num))
  1191  	}
  1192  
  1193  	// Adjust year
  1194  	// YYMMDD, year: 1970-1999
  1195  	if num <= 991231 {
  1196  		num = (num + 19000000) * 1000000
  1197  		return getTime(sc, num, t.Type)
  1198  	}
  1199  
  1200  	// Check YYYYMMDD.
  1201  	if num < 10000101 {
  1202  		return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(num))
  1203  	}
  1204  
  1205  	// Adjust hour/min/second.
  1206  	if num <= 99991231 {
  1207  		num = num * 1000000
  1208  		return getTime(sc, num, t.Type)
  1209  	}
  1210  
  1211  	// Check MMDDHHMMSS.
  1212  	if num < 101000000 {
  1213  		return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(num))
  1214  	}
  1215  
  1216  	// Set TypeDatetime type.
  1217  	t.Type = mysql.TypeDatetime
  1218  
  1219  	// Adjust year
  1220  	// YYMMDDHHMMSS, 2000-2069
  1221  	if num <= 69*10000000000+1231235959 {
  1222  		num = num + 20000000000000
  1223  		return getTime(sc, num, t.Type)
  1224  	}
  1225  
  1226  	// Check YYYYMMDDHHMMSS.
  1227  	if num < 70*10000000000+101000000 {
  1228  		return t, errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(num))
  1229  	}
  1230  
  1231  	// Adjust year
  1232  	// YYMMDDHHMMSS, 1970-1999
  1233  	if num <= 991231235959 {
  1234  		num = num + 19000000000000
  1235  		return getTime(sc, num, t.Type)
  1236  	}
  1237  
  1238  	return getTime(sc, num, t.Type)
  1239  }
  1240  
  1241  // ParseTime parses a formatted string with type tp and specific fsp.
  1242  // Type is TypeDatetime, TypeTimestamp and TypeDate.
  1243  // Fsp is in range [0, 6].
  1244  // MySQL supports many valid datetime format, but still has some limitation.
  1245  // If delimiter exists, the date part and time part is separated by a space or T,
  1246  // other punctuation character can be used as the delimiter between date parts or time parts.
  1247  // If no delimiter, the format must be YYYYMMDDHHMMSS or YYMMDDHHMMSS
  1248  // If we have fractional seconds part, we must use decimal points as the delimiter.
  1249  // The valid datetime range is from '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'.
  1250  // The valid timestamp range is from '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'.
  1251  // The valid date range is from '1000-01-01' to '9999-12-31'
  1252  func ParseTime(sc *stmtctx.StatementContext, str string, tp byte, fsp int) (Time, error) {
  1253  	return parseTime(sc, str, tp, fsp, false)
  1254  }
  1255  
  1256  // ParseTimeFromFloatString is similar to ParseTime, except that it's used to parse a float converted string.
  1257  func ParseTimeFromFloatString(sc *stmtctx.StatementContext, str string, tp byte, fsp int) (Time, error) {
  1258  	return parseTime(sc, str, tp, fsp, true)
  1259  }
  1260  
  1261  func parseTime(sc *stmtctx.StatementContext, str string, tp byte, fsp int, isFloat bool) (Time, error) {
  1262  	fsp, err := CheckFsp(fsp)
  1263  	if err != nil {
  1264  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1265  	}
  1266  
  1267  	t, err := parseDatetime(sc, str, fsp, isFloat)
  1268  	if err != nil {
  1269  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1270  	}
  1271  
  1272  	t.Type = tp
  1273  	if err = t.check(sc); err != nil {
  1274  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1275  	}
  1276  	return t, nil
  1277  }
  1278  
  1279  // ParseDatetime is a helper function wrapping ParseTime with datetime type and default fsp.
  1280  func ParseDatetime(sc *stmtctx.StatementContext, str string) (Time, error) {
  1281  	return ParseTime(sc, str, mysql.TypeDatetime, GetFsp(str))
  1282  }
  1283  
  1284  // ParseTimestamp is a helper function wrapping ParseTime with timestamp type and default fsp.
  1285  func ParseTimestamp(sc *stmtctx.StatementContext, str string) (Time, error) {
  1286  	return ParseTime(sc, str, mysql.TypeTimestamp, GetFsp(str))
  1287  }
  1288  
  1289  // ParseDate is a helper function wrapping ParseTime with date type.
  1290  func ParseDate(sc *stmtctx.StatementContext, str string) (Time, error) {
  1291  	// date has no fractional seconds precision
  1292  	return ParseTime(sc, str, mysql.TypeDate, MinFsp)
  1293  }
  1294  
  1295  // ParseTimeFromNum parses a formatted int64,
  1296  // returns the value which type is tp.
  1297  func ParseTimeFromNum(sc *stmtctx.StatementContext, num int64, tp byte, fsp int) (Time, error) {
  1298  	fsp, err := CheckFsp(fsp)
  1299  	if err != nil {
  1300  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1301  	}
  1302  
  1303  	t, err := parseDateTimeFromNum(sc, num)
  1304  	if err != nil {
  1305  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1306  	}
  1307  
  1308  	t.Type = tp
  1309  	t.Fsp = fsp
  1310  	if err := t.check(sc); err != nil {
  1311  		return Time{Time: ZeroTime, Type: tp}, errors.Trace(err)
  1312  	}
  1313  	return t, nil
  1314  }
  1315  
  1316  // ParseDatetimeFromNum is a helper function wrapping ParseTimeFromNum with datetime type and default fsp.
  1317  func ParseDatetimeFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {
  1318  	return ParseTimeFromNum(sc, num, mysql.TypeDatetime, DefaultFsp)
  1319  }
  1320  
  1321  // ParseTimestampFromNum is a helper function wrapping ParseTimeFromNum with timestamp type and default fsp.
  1322  func ParseTimestampFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {
  1323  	return ParseTimeFromNum(sc, num, mysql.TypeTimestamp, DefaultFsp)
  1324  }
  1325  
  1326  // ParseDateFromNum is a helper function wrapping ParseTimeFromNum with date type.
  1327  func ParseDateFromNum(sc *stmtctx.StatementContext, num int64) (Time, error) {
  1328  	// date has no fractional seconds precision
  1329  	return ParseTimeFromNum(sc, num, mysql.TypeDate, MinFsp)
  1330  }
  1331  
  1332  // TimeFromDays Converts a day number to a date.
  1333  func TimeFromDays(num int64) Time {
  1334  	if num < 0 {
  1335  		return Time{
  1336  			Time: FromDate(0, 0, 0, 0, 0, 0, 0),
  1337  			Type: mysql.TypeDate,
  1338  			Fsp:  0,
  1339  		}
  1340  	}
  1341  	year, month, day := getDateFromDaynr(uint(num))
  1342  
  1343  	return Time{
  1344  		Time: FromDate(int(year), int(month), int(day), 0, 0, 0, 0),
  1345  		Type: mysql.TypeDate,
  1346  		Fsp:  0,
  1347  	}
  1348  }
  1349  
  1350  func checkDateType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {
  1351  	year, month, day := t.Year(), t.Month(), t.Day()
  1352  	if year == 0 && month == 0 && day == 0 {
  1353  		return nil
  1354  	}
  1355  
  1356  	if !allowZeroInDate && (month == 0 || day == 0) {
  1357  		return ErrIncorrectDatetimeValue.GenWithStackByArgs(fmt.Sprintf("%04d-%02d-%02d", year, month, day))
  1358  	}
  1359  
  1360  	if err := checkDateRange(t); err != nil {
  1361  		return errors.Trace(err)
  1362  	}
  1363  
  1364  	if err := checkMonthDay(year, month, day, allowInvalidDate); err != nil {
  1365  		return errors.Trace(err)
  1366  	}
  1367  
  1368  	return nil
  1369  }
  1370  
  1371  func checkDateRange(t MysqlTime) error {
  1372  	// Oddly enough, MySQL document says date range should larger than '1000-01-01',
  1373  	// but we can insert '0001-01-01' actually.
  1374  	if t.Year() < 0 || t.Month() < 0 || t.Day() < 0 {
  1375  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(t))
  1376  	}
  1377  	if compareTime(t, MaxDatetime) > 0 {
  1378  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(t))
  1379  	}
  1380  	return nil
  1381  }
  1382  
  1383  func checkMonthDay(year, month, day int, allowInvalidDate bool) error {
  1384  	if month < 0 || month > 12 {
  1385  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(month))
  1386  	}
  1387  
  1388  	maxDay := 31
  1389  	if !allowInvalidDate {
  1390  		if month > 0 {
  1391  			maxDay = maxDaysInMonth[month-1]
  1392  		}
  1393  		if month == 2 && year%4 != 0 {
  1394  			maxDay = 28
  1395  		}
  1396  	}
  1397  
  1398  	if day < 0 || day > maxDay {
  1399  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(day))
  1400  	}
  1401  	return nil
  1402  }
  1403  
  1404  func checkTimestampType(sc *stmtctx.StatementContext, t MysqlTime) error {
  1405  	if compareTime(t, ZeroTime) == 0 {
  1406  		return nil
  1407  	}
  1408  
  1409  	if sc == nil {
  1410  		return errors.New("statementContext is required during checkTimestampType")
  1411  	}
  1412  
  1413  	var checkTime MysqlTime
  1414  	if sc.TimeZone != BoundTimezone {
  1415  		convertTime := Time{Time: t, Type: mysql.TypeTimestamp}
  1416  		err := convertTime.ConvertTimeZone(sc.TimeZone, BoundTimezone)
  1417  		if err != nil {
  1418  			return err
  1419  		}
  1420  		checkTime = convertTime.Time
  1421  	} else {
  1422  		checkTime = t
  1423  	}
  1424  	if compareTime(checkTime, MaxTimestamp.Time) > 0 || compareTime(checkTime, MinTimestamp.Time) < 0 {
  1425  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(t))
  1426  	}
  1427  
  1428  	if _, err := t.GoTime(gotime.Local); err != nil {
  1429  		return errors.Trace(err)
  1430  	}
  1431  
  1432  	return nil
  1433  }
  1434  
  1435  func checkDatetimeType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {
  1436  	if err := checkDateType(t, allowZeroInDate, allowInvalidDate); err != nil {
  1437  		return errors.Trace(err)
  1438  	}
  1439  
  1440  	hour, minute, second := t.Hour(), t.Minute(), t.Second()
  1441  	if hour < 0 || hour >= 24 {
  1442  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(hour))
  1443  	}
  1444  	if minute < 0 || minute >= 60 {
  1445  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(minute))
  1446  	}
  1447  	if second < 0 || second >= 60 {
  1448  		return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(second))
  1449  	}
  1450  
  1451  	return nil
  1452  }
  1453  
  1454  // ExtractDatetimeNum extracts time value number from datetime unit and format.
  1455  func ExtractDatetimeNum(t *Time, unit string) (int64, error) {
  1456  	switch strings.ToUpper(unit) {
  1457  	case "DAY":
  1458  		return int64(t.Time.Day()), nil
  1459  	case "WEEK":
  1460  		week := t.Time.Week(0)
  1461  		return int64(week), nil
  1462  	case "MONTH":
  1463  		// TODO: Consider time_zone variable.
  1464  		t1, err := t.Time.GoTime(gotime.Local)
  1465  		if err != nil {
  1466  			return 0, errors.Trace(err)
  1467  		}
  1468  		return int64(t1.Month()), nil
  1469  	case "QUARTER":
  1470  		m := int64(t.Time.Month())
  1471  		// 1 - 3 -> 1
  1472  		// 4 - 6 -> 2
  1473  		// 7 - 9 -> 3
  1474  		// 10 - 12 -> 4
  1475  		return (m + 2) / 3, nil
  1476  	case "YEAR":
  1477  		return int64(t.Time.Year()), nil
  1478  	case "DAY_MICROSECOND":
  1479  		h, m, s := t.Clock()
  1480  		d := t.Time.Day()
  1481  		return int64(d*1000000+h*10000+m*100+s)*1000000 + int64(t.Time.Microsecond()), nil
  1482  	case "DAY_SECOND":
  1483  		h, m, s := t.Clock()
  1484  		d := t.Time.Day()
  1485  		return int64(d)*1000000 + int64(h)*10000 + int64(m)*100 + int64(s), nil
  1486  	case "DAY_MINUTE":
  1487  		h, m, _ := t.Clock()
  1488  		d := t.Time.Day()
  1489  		return int64(d)*10000 + int64(h)*100 + int64(m), nil
  1490  	case "DAY_HOUR":
  1491  		h, _, _ := t.Clock()
  1492  		d := t.Time.Day()
  1493  		return int64(d)*100 + int64(h), nil
  1494  	case "YEAR_MONTH":
  1495  		y, m := t.Time.Year(), t.Time.Month()
  1496  		return int64(y)*100 + int64(m), nil
  1497  	default:
  1498  		return 0, errors.Errorf("invalid unit %s", unit)
  1499  	}
  1500  }
  1501  
  1502  // ExtractDurationNum extracts duration value number from duration unit and format.
  1503  func ExtractDurationNum(d *Duration, unit string) (int64, error) {
  1504  	switch strings.ToUpper(unit) {
  1505  	case "MICROSECOND":
  1506  		return int64(d.MicroSecond()), nil
  1507  	case "SECOND":
  1508  		return int64(d.Second()), nil
  1509  	case "MINUTE":
  1510  		return int64(d.Minute()), nil
  1511  	case "HOUR":
  1512  		return int64(d.Hour()), nil
  1513  	case "SECOND_MICROSECOND":
  1514  		return int64(d.Second())*1000000 + int64(d.MicroSecond()), nil
  1515  	case "MINUTE_MICROSECOND":
  1516  		return int64(d.Minute())*100000000 + int64(d.Second())*1000000 + int64(d.MicroSecond()), nil
  1517  	case "MINUTE_SECOND":
  1518  		return int64(d.Minute()*100 + d.Second()), nil
  1519  	case "HOUR_MICROSECOND":
  1520  		return int64(d.Hour())*10000000000 + int64(d.Minute())*100000000 + int64(d.Second())*1000000 + int64(d.MicroSecond()), nil
  1521  	case "HOUR_SECOND":
  1522  		return int64(d.Hour())*10000 + int64(d.Minute())*100 + int64(d.Second()), nil
  1523  	case "HOUR_MINUTE":
  1524  		return int64(d.Hour())*100 + int64(d.Minute()), nil
  1525  	default:
  1526  		return 0, errors.Errorf("invalid unit %s", unit)
  1527  	}
  1528  }
  1529  
  1530  func extractSingleTimeValue(unit string, format string) (int64, int64, int64, float64, error) {
  1531  	fv, err := strconv.ParseFloat(format, 64)
  1532  	if err != nil {
  1533  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1534  	}
  1535  	iv := int64(math.Round(fv))
  1536  
  1537  	switch strings.ToUpper(unit) {
  1538  	case "MICROSECOND":
  1539  		return 0, 0, 0, fv * float64(gotime.Microsecond), nil
  1540  	case "SECOND":
  1541  		return 0, 0, 0, fv * float64(gotime.Second), nil
  1542  	case "MINUTE":
  1543  		return 0, 0, 0, float64(iv * int64(gotime.Minute)), nil
  1544  	case "HOUR":
  1545  		return 0, 0, 0, float64(iv * int64(gotime.Hour)), nil
  1546  	case "DAY":
  1547  		return 0, 0, iv, 0, nil
  1548  	case "WEEK":
  1549  		return 0, 0, 7 * iv, 0, nil
  1550  	case "MONTH":
  1551  		return 0, iv, 0, 0, nil
  1552  	case "QUARTER":
  1553  		return 0, 3 * iv, 0, 0, nil
  1554  	case "YEAR":
  1555  		return iv, 0, 0, 0, nil
  1556  	}
  1557  
  1558  	return 0, 0, 0, 0, errors.Errorf("invalid singel timeunit - %s", unit)
  1559  }
  1560  
  1561  // extractSecondMicrosecond extracts second and microsecond from a string and its format is `SS.FFFFFF`.
  1562  func extractSecondMicrosecond(format string) (int64, int64, int64, float64, error) {
  1563  	fields := strings.Split(format, ".")
  1564  	if len(fields) != 2 {
  1565  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1566  	}
  1567  
  1568  	seconds, err := strconv.ParseFloat(fields[0], 64)
  1569  	if err != nil {
  1570  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1571  	}
  1572  
  1573  	microseconds, err := strconv.ParseFloat(alignFrac(fields[1], MaxFsp), 64)
  1574  	if err != nil {
  1575  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1576  	}
  1577  
  1578  	return 0, 0, 0, seconds*float64(gotime.Second) + microseconds*float64(gotime.Microsecond), nil
  1579  }
  1580  
  1581  // extractMinuteMicrosecond extracts minutes and microsecond from a string and its format is `MM:SS.FFFFFF`.
  1582  func extractMinuteMicrosecond(format string) (int64, int64, int64, float64, error) {
  1583  	fields := strings.Split(format, ":")
  1584  	if len(fields) != 2 {
  1585  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1586  	}
  1587  
  1588  	minutes, err := strconv.ParseFloat(fields[0], 64)
  1589  	if err != nil {
  1590  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1591  	}
  1592  
  1593  	_, _, _, value, err := extractSecondMicrosecond(fields[1])
  1594  	if err != nil {
  1595  		return 0, 0, 0, 0, errors.Trace(err)
  1596  	}
  1597  
  1598  	return 0, 0, 0, minutes*float64(gotime.Minute) + value, nil
  1599  }
  1600  
  1601  // extractMinuteSecond extracts minutes and second from a string and its format is `MM:SS`.
  1602  func extractMinuteSecond(format string) (int64, int64, int64, float64, error) {
  1603  	fields := strings.Split(format, ":")
  1604  	if len(fields) != 2 {
  1605  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1606  	}
  1607  
  1608  	minutes, err := strconv.ParseFloat(fields[0], 64)
  1609  	if err != nil {
  1610  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1611  	}
  1612  
  1613  	seconds, err := strconv.ParseFloat(fields[1], 64)
  1614  	if err != nil {
  1615  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1616  	}
  1617  
  1618  	return 0, 0, 0, minutes*float64(gotime.Minute) + seconds*float64(gotime.Second), nil
  1619  }
  1620  
  1621  // extractHourMicrosecond extracts hour and microsecond from a string and its format is `HH:MM:SS.FFFFFF`.
  1622  func extractHourMicrosecond(format string) (int64, int64, int64, float64, error) {
  1623  	fields := strings.Split(format, ":")
  1624  	if len(fields) != 3 {
  1625  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1626  	}
  1627  
  1628  	hours, err := strconv.ParseFloat(fields[0], 64)
  1629  	if err != nil {
  1630  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1631  	}
  1632  
  1633  	minutes, err := strconv.ParseFloat(fields[1], 64)
  1634  	if err != nil {
  1635  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1636  	}
  1637  
  1638  	_, _, _, value, err := extractSecondMicrosecond(fields[2])
  1639  	if err != nil {
  1640  		return 0, 0, 0, 0, errors.Trace(err)
  1641  	}
  1642  
  1643  	return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute) + value, nil
  1644  }
  1645  
  1646  // extractHourSecond extracts hour and second from a string and its format is `HH:MM:SS`.
  1647  func extractHourSecond(format string) (int64, int64, int64, float64, error) {
  1648  	fields := strings.Split(format, ":")
  1649  	if len(fields) != 3 {
  1650  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1651  	}
  1652  
  1653  	hours, err := strconv.ParseFloat(fields[0], 64)
  1654  	if err != nil {
  1655  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1656  	}
  1657  
  1658  	minutes, err := strconv.ParseFloat(fields[1], 64)
  1659  	if err != nil {
  1660  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1661  	}
  1662  
  1663  	seconds, err := strconv.ParseFloat(fields[2], 64)
  1664  	if err != nil {
  1665  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1666  	}
  1667  
  1668  	return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute) + seconds*float64(gotime.Second), nil
  1669  }
  1670  
  1671  // extractHourMinute extracts hour and minute from a string and its format is `HH:MM`.
  1672  func extractHourMinute(format string) (int64, int64, int64, float64, error) {
  1673  	fields := strings.Split(format, ":")
  1674  	if len(fields) != 2 {
  1675  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1676  	}
  1677  
  1678  	hours, err := strconv.ParseFloat(fields[0], 64)
  1679  	if err != nil {
  1680  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1681  	}
  1682  
  1683  	minutes, err := strconv.ParseFloat(fields[1], 64)
  1684  	if err != nil {
  1685  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1686  	}
  1687  
  1688  	return 0, 0, 0, hours*float64(gotime.Hour) + minutes*float64(gotime.Minute), nil
  1689  }
  1690  
  1691  // extractDayMicrosecond extracts day and microsecond from a string and its format is `DD HH:MM:SS.FFFFFF`.
  1692  func extractDayMicrosecond(format string) (int64, int64, int64, float64, error) {
  1693  	fields := strings.Split(format, " ")
  1694  	if len(fields) != 2 {
  1695  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1696  	}
  1697  
  1698  	days, err := strconv.ParseInt(fields[0], 10, 64)
  1699  	if err != nil {
  1700  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1701  	}
  1702  
  1703  	_, _, _, value, err := extractHourMicrosecond(fields[1])
  1704  	if err != nil {
  1705  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1706  	}
  1707  
  1708  	return 0, 0, days, value, nil
  1709  }
  1710  
  1711  // extractDaySecond extracts day and hour from a string and its format is `DD HH:MM:SS`.
  1712  func extractDaySecond(format string) (int64, int64, int64, float64, error) {
  1713  	fields := strings.Split(format, " ")
  1714  	if len(fields) != 2 {
  1715  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1716  	}
  1717  
  1718  	days, err := strconv.ParseInt(fields[0], 10, 64)
  1719  	if err != nil {
  1720  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1721  	}
  1722  
  1723  	_, _, _, value, err := extractHourSecond(fields[1])
  1724  	if err != nil {
  1725  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1726  	}
  1727  
  1728  	return 0, 0, days, value, nil
  1729  }
  1730  
  1731  // extractDayMinute extracts day and minute from a string and its format is `DD HH:MM`.
  1732  func extractDayMinute(format string) (int64, int64, int64, float64, error) {
  1733  	fields := strings.Split(format, " ")
  1734  	if len(fields) != 2 {
  1735  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1736  	}
  1737  
  1738  	days, err := strconv.ParseInt(fields[0], 10, 64)
  1739  	if err != nil {
  1740  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1741  	}
  1742  
  1743  	_, _, _, value, err := extractHourMinute(fields[1])
  1744  	if err != nil {
  1745  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1746  	}
  1747  
  1748  	return 0, 0, days, value, nil
  1749  }
  1750  
  1751  // extractDayHour extracts day and hour from a string and its format is `DD HH`.
  1752  func extractDayHour(format string) (int64, int64, int64, float64, error) {
  1753  	fields := strings.Split(format, " ")
  1754  	if len(fields) != 2 {
  1755  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1756  	}
  1757  
  1758  	days, err := strconv.ParseInt(fields[0], 10, 64)
  1759  	if err != nil {
  1760  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1761  	}
  1762  
  1763  	hours, err := strconv.ParseFloat(fields[1], 64)
  1764  	if err != nil {
  1765  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1766  	}
  1767  
  1768  	return 0, 0, days, hours * float64(gotime.Hour), nil
  1769  }
  1770  
  1771  // extractYearMonth extracts year and month from a string and its format is `YYYY-MM`.
  1772  func extractYearMonth(format string) (int64, int64, int64, float64, error) {
  1773  	fields := strings.Split(format, "-")
  1774  	if len(fields) != 2 {
  1775  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1776  	}
  1777  
  1778  	years, err := strconv.ParseInt(fields[0], 10, 64)
  1779  	if err != nil {
  1780  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1781  	}
  1782  
  1783  	months, err := strconv.ParseInt(fields[1], 10, 64)
  1784  	if err != nil {
  1785  		return 0, 0, 0, 0, ErrIncorrectDatetimeValue.GenWithStackByArgs(format)
  1786  	}
  1787  
  1788  	return years, months, 0, 0, nil
  1789  }
  1790  
  1791  // ExtractTimeValue extracts time value from time unit and format.
  1792  func ExtractTimeValue(unit string, format string) (int64, int64, int64, float64, error) {
  1793  	switch strings.ToUpper(unit) {
  1794  	case "MICROSECOND", "SECOND", "MINUTE", "HOUR", "DAY", "WEEK", "MONTH", "QUARTER", "YEAR":
  1795  		return extractSingleTimeValue(unit, format)
  1796  	case "SECOND_MICROSECOND":
  1797  		return extractSecondMicrosecond(format)
  1798  	case "MINUTE_MICROSECOND":
  1799  		return extractMinuteMicrosecond(format)
  1800  	case "MINUTE_SECOND":
  1801  		return extractMinuteSecond(format)
  1802  	case "HOUR_MICROSECOND":
  1803  		return extractHourMicrosecond(format)
  1804  	case "HOUR_SECOND":
  1805  		return extractHourSecond(format)
  1806  	case "HOUR_MINUTE":
  1807  		return extractHourMinute(format)
  1808  	case "DAY_MICROSECOND":
  1809  		return extractDayMicrosecond(format)
  1810  	case "DAY_SECOND":
  1811  		return extractDaySecond(format)
  1812  	case "DAY_MINUTE":
  1813  		return extractDayMinute(format)
  1814  	case "DAY_HOUR":
  1815  		return extractDayHour(format)
  1816  	case "YEAR_MONTH":
  1817  		return extractYearMonth(format)
  1818  	default:
  1819  		return 0, 0, 0, 0, errors.Errorf("invalid singel timeunit - %s", unit)
  1820  	}
  1821  }
  1822  
  1823  // IsClockUnit returns true when unit is interval unit with hour, minute or second.
  1824  func IsClockUnit(unit string) bool {
  1825  	switch strings.ToUpper(unit) {
  1826  	case "MICROSECOND", "SECOND", "MINUTE", "HOUR",
  1827  		"SECOND_MICROSECOND", "MINUTE_MICROSECOND", "MINUTE_SECOND",
  1828  		"HOUR_MICROSECOND", "HOUR_SECOND", "HOUR_MINUTE",
  1829  		"DAY_MICROSECOND", "DAY_SECOND", "DAY_MINUTE", "DAY_HOUR":
  1830  		return true
  1831  	default:
  1832  		return false
  1833  	}
  1834  }
  1835  
  1836  // IsDateFormat returns true when the specified time format could contain only date.
  1837  func IsDateFormat(format string) bool {
  1838  	format = strings.TrimSpace(format)
  1839  	seps := ParseDateFormat(format)
  1840  	length := len(format)
  1841  	switch len(seps) {
  1842  	case 1:
  1843  		if (length == 8) || (length == 6) {
  1844  			return true
  1845  		}
  1846  	case 3:
  1847  		return true
  1848  	}
  1849  	return false
  1850  }
  1851  
  1852  // ParseTimeFromInt64 parses mysql time value from int64.
  1853  func ParseTimeFromInt64(sc *stmtctx.StatementContext, num int64) (Time, error) {
  1854  	return parseDateTimeFromNum(sc, num)
  1855  }
  1856  
  1857  // DateFormat returns a textual representation of the time value formatted
  1858  // according to layout.
  1859  // See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
  1860  func (t Time) DateFormat(layout string) (string, error) {
  1861  	var buf bytes.Buffer
  1862  	inPatternMatch := false
  1863  	for _, b := range layout {
  1864  		if inPatternMatch {
  1865  			if err := t.convertDateFormat(b, &buf); err != nil {
  1866  				return "", errors.Trace(err)
  1867  			}
  1868  			inPatternMatch = false
  1869  			continue
  1870  		}
  1871  
  1872  		// It's not in pattern match now.
  1873  		if b == '%' {
  1874  			inPatternMatch = true
  1875  		} else {
  1876  			buf.WriteRune(b)
  1877  		}
  1878  	}
  1879  	return buf.String(), nil
  1880  }
  1881  
  1882  var abbrevWeekdayName = []string{
  1883  	"Sun", "Mon", "Tue",
  1884  	"Wed", "Thu", "Fri", "Sat",
  1885  }
  1886  
  1887  func (t Time) convertDateFormat(b rune, buf *bytes.Buffer) error {
  1888  	switch b {
  1889  	case 'b':
  1890  		m := t.Time.Month()
  1891  		if m == 0 || m > 12 {
  1892  			return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(m))
  1893  		}
  1894  		buf.WriteString(MonthNames[m-1][:3])
  1895  	case 'M':
  1896  		m := t.Time.Month()
  1897  		if m == 0 || m > 12 {
  1898  			return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(m))
  1899  		}
  1900  		buf.WriteString(MonthNames[m-1])
  1901  	case 'm':
  1902  		fmt.Fprintf(buf, "%02d", t.Time.Month())
  1903  	case 'c':
  1904  		fmt.Fprintf(buf, "%d", t.Time.Month())
  1905  	case 'D':
  1906  		fmt.Fprintf(buf, "%d%s", t.Time.Day(), abbrDayOfMonth(t.Time.Day()))
  1907  	case 'd':
  1908  		fmt.Fprintf(buf, "%02d", t.Time.Day())
  1909  	case 'e':
  1910  		fmt.Fprintf(buf, "%d", t.Time.Day())
  1911  	case 'j':
  1912  		fmt.Fprintf(buf, "%03d", t.Time.YearDay())
  1913  	case 'H':
  1914  		fmt.Fprintf(buf, "%02d", t.Time.Hour())
  1915  	case 'k':
  1916  		fmt.Fprintf(buf, "%d", t.Time.Hour())
  1917  	case 'h', 'I':
  1918  		t := t.Time.Hour()
  1919  		if t == 0 || t == 12 {
  1920  			fmt.Fprintf(buf, "%02d", 12)
  1921  		} else {
  1922  			fmt.Fprintf(buf, "%02d", t%12)
  1923  		}
  1924  	case 'l':
  1925  		t := t.Time.Hour()
  1926  		if t == 0 || t == 12 {
  1927  			fmt.Fprintf(buf, "%d", 12)
  1928  		} else {
  1929  			fmt.Fprintf(buf, "%d", t%12)
  1930  		}
  1931  	case 'i':
  1932  		fmt.Fprintf(buf, "%02d", t.Time.Minute())
  1933  	case 'p':
  1934  		hour := t.Time.Hour()
  1935  		if hour/12%2 == 0 {
  1936  			buf.WriteString("AM")
  1937  		} else {
  1938  			buf.WriteString("PM")
  1939  		}
  1940  	case 'r':
  1941  		h := t.Time.Hour()
  1942  		switch {
  1943  		case h == 0:
  1944  			fmt.Fprintf(buf, "%02d:%02d:%02d AM", 12, t.Time.Minute(), t.Time.Second())
  1945  		case h == 12:
  1946  			fmt.Fprintf(buf, "%02d:%02d:%02d PM", 12, t.Time.Minute(), t.Time.Second())
  1947  		case h < 12:
  1948  			fmt.Fprintf(buf, "%02d:%02d:%02d AM", h, t.Time.Minute(), t.Time.Second())
  1949  		default:
  1950  			fmt.Fprintf(buf, "%02d:%02d:%02d PM", h-12, t.Time.Minute(), t.Time.Second())
  1951  		}
  1952  	case 'T':
  1953  		fmt.Fprintf(buf, "%02d:%02d:%02d", t.Time.Hour(), t.Time.Minute(), t.Time.Second())
  1954  	case 'S', 's':
  1955  		fmt.Fprintf(buf, "%02d", t.Time.Second())
  1956  	case 'f':
  1957  		fmt.Fprintf(buf, "%06d", t.Time.Microsecond())
  1958  	case 'U':
  1959  		w := t.Time.Week(0)
  1960  		fmt.Fprintf(buf, "%02d", w)
  1961  	case 'u':
  1962  		w := t.Time.Week(1)
  1963  		fmt.Fprintf(buf, "%02d", w)
  1964  	case 'V':
  1965  		w := t.Time.Week(2)
  1966  		fmt.Fprintf(buf, "%02d", w)
  1967  	case 'v':
  1968  		_, w := t.Time.YearWeek(3)
  1969  		fmt.Fprintf(buf, "%02d", w)
  1970  	case 'a':
  1971  		weekday := t.Time.Weekday()
  1972  		buf.WriteString(abbrevWeekdayName[weekday])
  1973  	case 'W':
  1974  		buf.WriteString(t.Time.Weekday().String())
  1975  	case 'w':
  1976  		fmt.Fprintf(buf, "%d", t.Time.Weekday())
  1977  	case 'X':
  1978  		year, _ := t.Time.YearWeek(2)
  1979  		if year < 0 {
  1980  			fmt.Fprintf(buf, "%v", uint64(math.MaxUint32))
  1981  		} else {
  1982  			fmt.Fprintf(buf, "%04d", year)
  1983  		}
  1984  	case 'x':
  1985  		year, _ := t.Time.YearWeek(3)
  1986  		if year < 0 {
  1987  			fmt.Fprintf(buf, "%v", uint64(math.MaxUint32))
  1988  		} else {
  1989  			fmt.Fprintf(buf, "%04d", year)
  1990  		}
  1991  	case 'Y':
  1992  		fmt.Fprintf(buf, "%04d", t.Time.Year())
  1993  	case 'y':
  1994  		str := fmt.Sprintf("%04d", t.Time.Year())
  1995  		buf.WriteString(str[2:])
  1996  	default:
  1997  		buf.WriteRune(b)
  1998  	}
  1999  
  2000  	return nil
  2001  }
  2002  
  2003  func abbrDayOfMonth(day int) string {
  2004  	var str string
  2005  	switch day {
  2006  	case 1, 21, 31:
  2007  		str = "st"
  2008  	case 2, 22:
  2009  		str = "nd"
  2010  	case 3, 23:
  2011  		str = "rd"
  2012  	default:
  2013  		str = "th"
  2014  	}
  2015  	return str
  2016  }
  2017  
  2018  // StrToDate converts date string according to format.
  2019  // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
  2020  func (t *Time) StrToDate(sc *stmtctx.StatementContext, date, format string) bool {
  2021  	ctx := make(map[string]int)
  2022  	var tm MysqlTime
  2023  	if !strToDate(&tm, date, format, ctx) {
  2024  		t.Time = ZeroTime
  2025  		t.Type = mysql.TypeDatetime
  2026  		t.Fsp = 0
  2027  		return false
  2028  	}
  2029  	if err := mysqlTimeFix(&tm, ctx); err != nil {
  2030  		return false
  2031  	}
  2032  
  2033  	t.Time = tm
  2034  	t.Type = mysql.TypeDatetime
  2035  	return t.check(sc) == nil
  2036  }
  2037  
  2038  // mysqlTimeFix fixes the MysqlTime use the values in the context.
  2039  func mysqlTimeFix(t *MysqlTime, ctx map[string]int) error {
  2040  	// Key of the ctx is the format char, such as `%j` `%p` and so on.
  2041  	if yearOfDay, ok := ctx["%j"]; ok {
  2042  		// TODO: Implement the function that converts day of year to yy:mm:dd.
  2043  		_ = yearOfDay
  2044  	}
  2045  	if valueAMorPm, ok := ctx["%p"]; ok {
  2046  		if t.hour == 0 {
  2047  			return ErrInvalidTimeFormat.GenWithStackByArgs(t)
  2048  		}
  2049  		if t.hour == 12 {
  2050  			// 12 is a special hour.
  2051  			switch valueAMorPm {
  2052  			case constForAM:
  2053  				t.hour = 0
  2054  			case constForPM:
  2055  				t.hour = 12
  2056  			}
  2057  			return nil
  2058  		}
  2059  		if valueAMorPm == constForPM {
  2060  			t.hour += 12
  2061  		}
  2062  	}
  2063  	return nil
  2064  }
  2065  
  2066  // strToDate converts date string according to format, returns true on success,
  2067  // the value will be stored in argument t or ctx.
  2068  func strToDate(t *MysqlTime, date string, format string, ctx map[string]int) bool {
  2069  	date = skipWhiteSpace(date)
  2070  	format = skipWhiteSpace(format)
  2071  
  2072  	token, formatRemain, succ := getFormatToken(format)
  2073  	if !succ {
  2074  		return false
  2075  	}
  2076  
  2077  	if token == "" {
  2078  		// Extra characters at the end of date are ignored.
  2079  		return true
  2080  	}
  2081  
  2082  	dateRemain, succ := matchDateWithToken(t, date, token, ctx)
  2083  	if !succ {
  2084  		return false
  2085  	}
  2086  
  2087  	return strToDate(t, dateRemain, formatRemain, ctx)
  2088  }
  2089  
  2090  // getFormatToken takes one format control token from the string.
  2091  // format "%d %H %m" will get token "%d" and the remain is " %H %m".
  2092  func getFormatToken(format string) (token string, remain string, succ bool) {
  2093  	if len(format) == 0 {
  2094  		return "", "", true
  2095  	}
  2096  
  2097  	// Just one character.
  2098  	if len(format) == 1 {
  2099  		if format[0] == '%' {
  2100  			return "", "", false
  2101  		}
  2102  		return format, "", true
  2103  	}
  2104  
  2105  	// More than one character.
  2106  	if format[0] == '%' {
  2107  		return format[:2], format[2:], true
  2108  	}
  2109  
  2110  	return format[:1], format[1:], true
  2111  }
  2112  
  2113  func skipWhiteSpace(input string) string {
  2114  	for i, c := range input {
  2115  		if !unicode.IsSpace(c) {
  2116  			return input[i:]
  2117  		}
  2118  	}
  2119  	return ""
  2120  }
  2121  
  2122  var weekdayAbbrev = map[string]gotime.Weekday{
  2123  	"Sun": gotime.Sunday,
  2124  	"Mon": gotime.Monday,
  2125  	"Tue": gotime.Tuesday,
  2126  	"Wed": gotime.Wednesday,
  2127  	"Thu": gotime.Tuesday,
  2128  	"Fri": gotime.Friday,
  2129  	"Sat": gotime.Saturday,
  2130  }
  2131  
  2132  var monthAbbrev = map[string]gotime.Month{
  2133  	"Jan": gotime.January,
  2134  	"Feb": gotime.February,
  2135  	"Mar": gotime.March,
  2136  	"Apr": gotime.April,
  2137  	"May": gotime.May,
  2138  	"Jun": gotime.June,
  2139  	"Jul": gotime.July,
  2140  	"Aug": gotime.August,
  2141  	"Sep": gotime.September,
  2142  	"Oct": gotime.October,
  2143  	"Nov": gotime.November,
  2144  	"Dec": gotime.December,
  2145  }
  2146  
  2147  type dateFormatParser func(t *MysqlTime, date string, ctx map[string]int) (remain string, succ bool)
  2148  
  2149  var dateFormatParserTable = map[string]dateFormatParser{
  2150  	"%b": abbreviatedMonth,      // Abbreviated month name (Jan..Dec)
  2151  	"%c": monthNumeric,          // Month, numeric (0..12)
  2152  	"%d": dayOfMonthNumeric,     // Day of the month, numeric (0..31)
  2153  	"%e": dayOfMonthNumeric,     // Day of the month, numeric (0..31)
  2154  	"%f": microSeconds,          // Microseconds (000000..999999)
  2155  	"%h": hour24TwoDigits,       // Hour (01..12)
  2156  	"%H": hour24TwoDigits,       // Hour (01..12)
  2157  	"%I": hour24TwoDigits,       // Hour (01..12)
  2158  	"%i": minutesNumeric,        // Minutes, numeric (00..59)
  2159  	"%j": dayOfYearThreeDigits,  // Day of year (001..366)
  2160  	"%k": hour24Numeric,         // Hour (0..23)
  2161  	"%l": hour12Numeric,         // Hour (1..12)
  2162  	"%M": fullNameMonth,         // Month name (January..December)
  2163  	"%m": monthNumeric,          // Month, numeric (00..12)
  2164  	"%p": isAMOrPM,              // AM or PM
  2165  	"%r": time12Hour,            // Time, 12-hour (hh:mm:ss followed by AM or PM)
  2166  	"%s": secondsNumeric,        // Seconds (00..59)
  2167  	"%S": secondsNumeric,        // Seconds (00..59)
  2168  	"%T": time24Hour,            // Time, 24-hour (hh:mm:ss)
  2169  	"%Y": yearNumericFourDigits, // Year, numeric, four digits
  2170  	// Deprecated since MySQL 5.7.5
  2171  	"%y": yearNumericTwoDigits, // Year, numeric (two digits)
  2172  	// TODO: Add the following...
  2173  	// "%a": abbreviatedWeekday,         // Abbreviated weekday name (Sun..Sat)
  2174  	// "%D": dayOfMonthWithSuffix,       // Day of the month with English suffix (0th, 1st, 2nd, 3rd)
  2175  	// "%U": weekMode0,                  // Week (00..53), where Sunday is the first day of the week; WEEK() mode 0
  2176  	// "%u": weekMode1,                  // Week (00..53), where Monday is the first day of the week; WEEK() mode 1
  2177  	// "%V": weekMode2,                  // Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X
  2178  	// "%v": weekMode3,                  // Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
  2179  	// "%W": weekdayName,                // Weekday name (Sunday..Saturday)
  2180  	// "%w": dayOfWeek,                  // Day of the week (0=Sunday..6=Saturday)
  2181  	// "%X": yearOfWeek,                 // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
  2182  	// "%x": yearOfWeek,                 // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
  2183  }
  2184  
  2185  // GetFormatType checks the type(Duration, Date or Datetime) of a format string.
  2186  func GetFormatType(format string) (isDuration, isDate bool) {
  2187  	durationTokens := map[string]struct{}{
  2188  		"%h": {},
  2189  		"%H": {},
  2190  		"%i": {},
  2191  		"%I": {},
  2192  		"%s": {},
  2193  		"%S": {},
  2194  		"%k": {},
  2195  		"%l": {},
  2196  	}
  2197  	dateTokens := map[string]struct{}{
  2198  		"%y": {},
  2199  		"%Y": {},
  2200  		"%m": {},
  2201  		"%M": {},
  2202  		"%c": {},
  2203  		"%b": {},
  2204  		"%D": {},
  2205  		"%d": {},
  2206  		"%e": {},
  2207  	}
  2208  
  2209  	format = skipWhiteSpace(format)
  2210  	var token string
  2211  	var succ bool
  2212  	for {
  2213  		token, format, succ = getFormatToken(format)
  2214  		if len(token) == 0 {
  2215  			break
  2216  		}
  2217  		if !succ {
  2218  			isDuration, isDate = false, false
  2219  			break
  2220  		}
  2221  		if _, ok := durationTokens[token]; ok {
  2222  			isDuration = true
  2223  		} else if _, ok := dateTokens[token]; ok {
  2224  			isDate = true
  2225  		}
  2226  		if isDuration && isDate {
  2227  			break
  2228  		}
  2229  	}
  2230  	return
  2231  }
  2232  
  2233  func matchDateWithToken(t *MysqlTime, date string, token string, ctx map[string]int) (remain string, succ bool) {
  2234  	if parse, ok := dateFormatParserTable[token]; ok {
  2235  		return parse(t, date, ctx)
  2236  	}
  2237  
  2238  	if strings.HasPrefix(date, token) {
  2239  		return date[len(token):], true
  2240  	}
  2241  	return date, false
  2242  }
  2243  
  2244  func parseDigits(input string, count int) (int, bool) {
  2245  	if count <= 0 || len(input) < count {
  2246  		return 0, false
  2247  	}
  2248  
  2249  	v, err := strconv.ParseUint(input[:count], 10, 64)
  2250  	if err != nil {
  2251  		return int(v), false
  2252  	}
  2253  	return int(v), true
  2254  }
  2255  
  2256  func hour24TwoDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2257  	v, succ := parseDigits(input, 2)
  2258  	if !succ || v >= 24 {
  2259  		return input, false
  2260  	}
  2261  	t.hour = v
  2262  	return input[2:], true
  2263  }
  2264  
  2265  func secondsNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2266  	v, succ := parseDigits(input, 2)
  2267  	if !succ || v >= 60 {
  2268  		return input, false
  2269  	}
  2270  	t.second = uint8(v)
  2271  	return input[2:], true
  2272  }
  2273  
  2274  func minutesNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2275  	v, succ := parseDigits(input, 2)
  2276  	if !succ || v >= 60 {
  2277  		return input, false
  2278  	}
  2279  	t.minute = uint8(v)
  2280  	return input[2:], true
  2281  }
  2282  
  2283  const time12HourLen = len("hh:mm:ssAM")
  2284  
  2285  func time12Hour(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2286  	// hh:mm:ss AM
  2287  	if len(input) < time12HourLen {
  2288  		return input, false
  2289  	}
  2290  	hour, succ := parseDigits(input, 2)
  2291  	if !succ || hour > 12 || hour == 0 || input[2] != ':' {
  2292  		return input, false
  2293  	}
  2294  
  2295  	minute, succ := parseDigits(input[3:], 2)
  2296  	if !succ || minute > 59 || input[5] != ':' {
  2297  		return input, false
  2298  	}
  2299  
  2300  	second, succ := parseDigits(input[6:], 2)
  2301  	if !succ || second > 59 {
  2302  		return input, false
  2303  	}
  2304  
  2305  	remain := skipWhiteSpace(input[8:])
  2306  	switch {
  2307  	case strings.HasPrefix(remain, "AM"):
  2308  		t.hour = hour
  2309  	case strings.HasPrefix(remain, "PM"):
  2310  		t.hour = hour + 12
  2311  	default:
  2312  		return input, false
  2313  	}
  2314  
  2315  	t.minute = uint8(minute)
  2316  	t.second = uint8(second)
  2317  	return remain, true
  2318  }
  2319  
  2320  const time24HourLen = len("hh:mm:ss")
  2321  
  2322  func time24Hour(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2323  	// hh:mm:ss
  2324  	if len(input) < time24HourLen {
  2325  		return input, false
  2326  	}
  2327  
  2328  	hour, succ := parseDigits(input, 2)
  2329  	if !succ || hour > 23 || input[2] != ':' {
  2330  		return input, false
  2331  	}
  2332  
  2333  	minute, succ := parseDigits(input[3:], 2)
  2334  	if !succ || minute > 59 || input[5] != ':' {
  2335  		return input, false
  2336  	}
  2337  
  2338  	second, succ := parseDigits(input[6:], 2)
  2339  	if !succ || second > 59 {
  2340  		return input, false
  2341  	}
  2342  
  2343  	t.hour = hour
  2344  	t.minute = uint8(minute)
  2345  	t.second = uint8(second)
  2346  	return input[8:], true
  2347  }
  2348  
  2349  const (
  2350  	constForAM = 1 + iota
  2351  	constForPM
  2352  )
  2353  
  2354  func isAMOrPM(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2355  	if strings.HasPrefix(input, "AM") {
  2356  		ctx["%p"] = constForAM
  2357  	} else if strings.HasPrefix(input, "PM") {
  2358  		ctx["%p"] = constForPM
  2359  	} else {
  2360  		return input, false
  2361  	}
  2362  	return input[2:], true
  2363  }
  2364  
  2365  // digitRegex: it was used to scan a variable-length monthly day or month in the string. Ex:  "01" or "1" or "30"
  2366  var oneOrTwoDigitRegex = regexp.MustCompile("^[0-9]{1,2}")
  2367  
  2368  // twoDigitRegex: it was just for two digit number string. Ex: "01" or "12"
  2369  var twoDigitRegex = regexp.MustCompile("^[1-9][0-9]?")
  2370  
  2371  // parseTwoNumeric is used for pattens 0..31 0..24 0..60 and so on.
  2372  // It returns the parsed int, and remain data after parse.
  2373  func parseTwoNumeric(input string) (int, string) {
  2374  	if len(input) > 1 && input[0] == '0' {
  2375  		return 0, input[1:]
  2376  	}
  2377  	matched := twoDigitRegex.FindAllString(input, -1)
  2378  	if len(matched) == 0 {
  2379  		return 0, input
  2380  	}
  2381  
  2382  	str := matched[0]
  2383  	v, err := strconv.ParseInt(str, 10, 64)
  2384  	if err != nil {
  2385  		return 0, input
  2386  	}
  2387  	return int(v), input[len(str):]
  2388  }
  2389  
  2390  func dayOfMonthNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2391  	result := oneOrTwoDigitRegex.FindString(input) // 0..31
  2392  	length := len(result)
  2393  
  2394  	v, ok := parseDigits(input, length)
  2395  
  2396  	if !ok || v > 31 {
  2397  		return input, false
  2398  	}
  2399  	t.day = uint8(v)
  2400  	return input[length:], true
  2401  }
  2402  
  2403  func hour24Numeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2404  	result := oneOrTwoDigitRegex.FindString(input) // 0..23
  2405  	length := len(result)
  2406  
  2407  	v, ok := parseDigits(input, length)
  2408  
  2409  	if !ok || v > 23 {
  2410  		return input, false
  2411  	}
  2412  	t.hour = v
  2413  	return input[length:], true
  2414  }
  2415  
  2416  func hour12Numeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2417  	result := oneOrTwoDigitRegex.FindString(input) // 1..12
  2418  	length := len(result)
  2419  
  2420  	v, ok := parseDigits(input, length)
  2421  
  2422  	if !ok || v > 12 || v == 0 {
  2423  		return input, false
  2424  	}
  2425  	t.hour = v
  2426  	return input[length:], true
  2427  }
  2428  
  2429  func microSeconds(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2430  	if len(input) < 6 {
  2431  		return input, false
  2432  	}
  2433  	v, err := strconv.ParseUint(input[:6], 10, 64)
  2434  	if err != nil {
  2435  		return input, false
  2436  	}
  2437  	t.microsecond = uint32(v)
  2438  	return input[6:], true
  2439  }
  2440  
  2441  func yearNumericFourDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2442  	return yearNumericNDigits(t, input, ctx, 4)
  2443  }
  2444  
  2445  func yearNumericTwoDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2446  	return yearNumericNDigits(t, input, ctx, 2)
  2447  }
  2448  
  2449  func yearNumericNDigits(t *MysqlTime, input string, ctx map[string]int, n int) (string, bool) {
  2450  	effectiveCount, effectiveValue := 0, 0
  2451  	for effectiveCount+1 <= n {
  2452  		value, succeed := parseDigits(input, effectiveCount+1)
  2453  		if !succeed {
  2454  			break
  2455  		}
  2456  		effectiveCount++
  2457  		effectiveValue = value
  2458  	}
  2459  	if effectiveCount == 0 {
  2460  		return input, false
  2461  	}
  2462  	if effectiveCount <= 2 {
  2463  		effectiveValue = adjustYear(effectiveValue)
  2464  	}
  2465  	t.year = uint16(effectiveValue)
  2466  	return input[effectiveCount:], true
  2467  }
  2468  
  2469  func dayOfYearThreeDigits(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2470  	v, succ := parseDigits(input, 3)
  2471  	if !succ || v == 0 || v > 366 {
  2472  		return input, false
  2473  	}
  2474  	ctx["%j"] = v
  2475  	return input[3:], true
  2476  }
  2477  
  2478  func abbreviatedWeekday(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2479  	if len(input) >= 3 {
  2480  		dayName := input[:3]
  2481  		if _, ok := weekdayAbbrev[dayName]; ok {
  2482  			// TODO: We need refact mysql time to support this.
  2483  			return input, false
  2484  		}
  2485  	}
  2486  	return input, false
  2487  }
  2488  
  2489  func abbreviatedMonth(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2490  	if len(input) >= 3 {
  2491  		monthName := input[:3]
  2492  		if month, ok := monthAbbrev[monthName]; ok {
  2493  			t.month = uint8(month)
  2494  			return input[len(monthName):], true
  2495  		}
  2496  	}
  2497  	return input, false
  2498  }
  2499  
  2500  func fullNameMonth(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2501  	for i, month := range MonthNames {
  2502  		if strings.HasPrefix(input, month) {
  2503  			t.month = uint8(i + 1)
  2504  			return input[len(month):], true
  2505  		}
  2506  	}
  2507  	return input, false
  2508  }
  2509  
  2510  func monthNumeric(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2511  	result := oneOrTwoDigitRegex.FindString(input) // 1..12
  2512  	length := len(result)
  2513  
  2514  	v, ok := parseDigits(input, length)
  2515  
  2516  	if !ok || v > 12 {
  2517  		return input, false
  2518  	}
  2519  	t.month = uint8(v)
  2520  	return input[length:], true
  2521  }
  2522  
  2523  //  dayOfMonthWithSuffix returns different suffix according t being which day. i.e. 0 return th. 1 return st.
  2524  func dayOfMonthWithSuffix(t *MysqlTime, input string, ctx map[string]int) (string, bool) {
  2525  	month, remain := parseOrdinalNumbers(input)
  2526  	if month >= 0 {
  2527  		t.month = uint8(month)
  2528  		return remain, true
  2529  	}
  2530  	return input, false
  2531  }
  2532  
  2533  func parseOrdinalNumbers(input string) (value int, remain string) {
  2534  	for i, c := range input {
  2535  		if !unicode.IsDigit(c) {
  2536  			v, err := strconv.ParseUint(input[:i], 10, 64)
  2537  			if err != nil {
  2538  				return -1, input
  2539  			}
  2540  			value = int(v)
  2541  			break
  2542  		}
  2543  	}
  2544  	switch {
  2545  	case strings.HasPrefix(remain, "st"):
  2546  		if value == 1 {
  2547  			remain = remain[2:]
  2548  			return
  2549  		}
  2550  	case strings.HasPrefix(remain, "nd"):
  2551  		if value == 2 {
  2552  			remain = remain[2:]
  2553  			return
  2554  		}
  2555  	case strings.HasPrefix(remain, "th"):
  2556  		remain = remain[2:]
  2557  		return
  2558  	}
  2559  	return -1, input
  2560  }
  2561  
  2562  // DateFSP gets fsp from date string.
  2563  func DateFSP(date string) (fsp int) {
  2564  	i := strings.LastIndex(date, ".")
  2565  	if i != -1 {
  2566  		fsp = len(date) - i - 1
  2567  	}
  2568  	return
  2569  }