github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/mysql/time.go (about)

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