github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/function/builtin/binary/generalTime.go (about)

     1  // Copyright 2021 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package binary
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"unicode"
    21  )
    22  
    23  // GeneralTime is the internal struct type for Time.
    24  type GeneralTime struct {
    25  	year        uint16
    26  	month       uint8
    27  	day         uint8
    28  	hour        uint8
    29  	minute      uint8
    30  	second      uint8
    31  	microsecond uint32
    32  }
    33  
    34  func NewGeneralTime() *GeneralTime {
    35  	return &GeneralTime{}
    36  }
    37  
    38  func FromDate(year int, month int, day int, hour int, minute int, second int, microsecond int) GeneralTime {
    39  	return GeneralTime{
    40  		year:        uint16(year),
    41  		month:       uint8(month),
    42  		day:         uint8(day),
    43  		hour:        uint8(hour),
    44  		minute:      uint8(minute),
    45  		second:      uint8(second),
    46  		microsecond: uint32(microsecond),
    47  	}
    48  }
    49  
    50  // Reset GeneralTime to initialization state
    51  func (t GeneralTime) ResetTime() {
    52  	t.year = 0
    53  	t.month = 0
    54  	t.day = 0
    55  	t.hour = 0
    56  	t.minute = 0
    57  	t.second = 0
    58  	t.microsecond = 0
    59  	return
    60  }
    61  
    62  // String implements fmt.Stringer.
    63  func (t GeneralTime) String() string {
    64  	return fmt.Sprintf("{%d %d %d %d %d %d %d}", t.getYear(), t.getMonth(), t.getDay(), t.getHour(), t.getMinute(), t.getSecond(), t.getMicrosecond())
    65  }
    66  
    67  func (t GeneralTime) getYear() uint16 {
    68  	return t.year
    69  }
    70  
    71  func (t *GeneralTime) setYear(year uint16) {
    72  	t.year = year
    73  }
    74  
    75  func (t GeneralTime) getMonth() uint8 {
    76  	return t.month
    77  }
    78  
    79  func (t *GeneralTime) setMonth(month uint8) {
    80  	t.month = month
    81  }
    82  
    83  func (t GeneralTime) getDay() uint8 {
    84  	return t.day
    85  }
    86  
    87  func (t *GeneralTime) setDay(day uint8) {
    88  	t.day = day
    89  }
    90  
    91  func (t GeneralTime) getHour() uint8 {
    92  	return t.hour
    93  }
    94  
    95  func (t *GeneralTime) setHour(hour uint8) {
    96  	t.hour = hour
    97  }
    98  
    99  func (t GeneralTime) getMinute() uint8 {
   100  	return t.minute
   101  }
   102  
   103  func (t *GeneralTime) setMinute(minute uint8) {
   104  	t.minute = minute
   105  }
   106  
   107  // Minute returns the minute value.
   108  func (t GeneralTime) Minute() int {
   109  	return int(t.getMinute())
   110  }
   111  
   112  func (t GeneralTime) getSecond() uint8 {
   113  	return t.second
   114  }
   115  
   116  func (t *GeneralTime) setSecond(second uint8) {
   117  	t.second = second
   118  }
   119  
   120  func (t GeneralTime) getMicrosecond() uint32 {
   121  	return t.microsecond
   122  }
   123  
   124  func (t *GeneralTime) setMicrosecond(microsecond uint32) {
   125  	t.microsecond = microsecond
   126  }
   127  
   128  // The month represents one month of the year (January=1,...).
   129  type Month int
   130  
   131  const (
   132  	January Month = 1 + iota
   133  	February
   134  	March
   135  	April
   136  	May
   137  	June
   138  	July
   139  	August
   140  	September
   141  	October
   142  	November
   143  	December
   144  )
   145  
   146  var monthAbbrev = map[string]Month{
   147  	"jan": January,
   148  	"feb": February,
   149  	"mar": March,
   150  	"apr": April,
   151  	"may": May,
   152  	"jun": June,
   153  	"jul": July,
   154  	"aug": August,
   155  	"sep": September,
   156  	"oct": October,
   157  	"nov": November,
   158  	"dec": December,
   159  }
   160  
   161  type dateFormatParser func(t *GeneralTime, date string, ctx map[string]int) (remain string, succ bool)
   162  
   163  var dateFormatParserTable = map[string]dateFormatParser{
   164  	"%b": abbreviatedMonth,      // Abbreviated month name (Jan..Dec)
   165  	"%c": monthNumeric,          // Month, numeric (0..12)
   166  	"%d": dayOfMonthNumeric,     // Day of the month, numeric (0..31)
   167  	"%e": dayOfMonthNumeric,     // Day of the month, numeric (0..31)
   168  	"%f": microSeconds,          // Microseconds (000000..999999)
   169  	"%h": hour12Numeric,         // Hour (01..12)
   170  	"%H": hour24Numeric,         // Hour (00..23)
   171  	"%I": hour12Numeric,         // Hour (01..12)
   172  	"%i": minutesNumeric,        // Minutes, numeric (00..59)
   173  	"%j": dayOfYearNumeric,      // Day of year (001..366)
   174  	"%k": hour24Numeric,         // Hour (0..23)
   175  	"%l": hour12Numeric,         // Hour (1..12)
   176  	"%M": fullNameMonth,         // Month name (January..December)
   177  	"%m": monthNumeric,          // Month, numeric (00..12)
   178  	"%p": isAMOrPM,              // AM or PM
   179  	"%r": time12Hour,            // Time, 12-hour (hh:mm:ss followed by AM or PM)
   180  	"%s": secondsNumeric,        // Seconds (00..59)
   181  	"%S": secondsNumeric,        // Seconds (00..59)
   182  	"%T": time24Hour,            // Time, 24-hour (hh:mm:ss)
   183  	"%Y": yearNumericFourDigits, // Year, numeric, four digits
   184  	"%#": skipAllNums,           // Skip all numbers
   185  	"%.": skipAllPunct,          // Skip all punctation characters
   186  	"%@": skipAllAlpha,          // Skip all alpha characters
   187  	"%y": yearNumericTwoDigits,  // Year, numeric (two digits)
   188  	// "%a": abbreviatedWeekday,         // Abbreviated weekday name (Sun..Sat)
   189  	// "%D": dayOfMonthWithSuffix,       // Day of the month with English suffix (0th, 1st, 2nd, 3rd)
   190  	// "%U": weekMode0,                  // Week (00..53), where Sunday is the first day of the week; WEEK() mode 0
   191  	// "%u": weekMode1,                  // Week (00..53), where Monday is the first day of the week; WEEK() mode 1
   192  	// "%V": weekMode2,                  // Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X
   193  	// "%v": weekMode3,                  // Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
   194  	// "%W": weekdayName,                // Weekday name (Sunday..Saturday)
   195  	// "%w": dayOfWeek,                  // Day of the week (0=Sunday..6=Saturday)
   196  	// "%X": yearOfWeek,                 // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
   197  	// "%x": yearOfWeek,                 // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
   198  }
   199  
   200  func matchDateWithToken(t *GeneralTime, date string, token string, ctx map[string]int) (remain string, succ bool) {
   201  	if parse, ok := dateFormatParserTable[token]; ok {
   202  		return parse(t, date, ctx)
   203  	}
   204  
   205  	if strings.HasPrefix(date, token) {
   206  		return date[len(token):], true
   207  	}
   208  	return date, false
   209  }
   210  
   211  // Try to parse digits with number of `limit` starting from `input`
   212  // Return <number, n chars to step forward> if success.
   213  // Return <_, 0> if fail.
   214  func parseNDigits(input string, limit int) (number int, step int) {
   215  	if limit <= 0 {
   216  		return 0, 0
   217  	}
   218  
   219  	var num uint64 = 0
   220  	step = 0
   221  	for ; step < len(input) && step < limit && '0' <= input[step] && input[step] <= '9'; step++ {
   222  		num = num*10 + uint64(input[step]-'0')
   223  	}
   224  	return int(num), step
   225  }
   226  
   227  // Seconds (00..59)
   228  func secondsNumeric(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   229  	v, step := parseNDigits(input, 2)
   230  	if step <= 0 || v >= 60 {
   231  		return input, false
   232  	}
   233  	t.setSecond(uint8(v))
   234  	return input[step:], true
   235  }
   236  
   237  // Minutes, numeric (00..59)
   238  func minutesNumeric(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   239  	v, step := parseNDigits(input, 2)
   240  	if step <= 0 || v >= 60 {
   241  		return input, false
   242  	}
   243  	t.setMinute(uint8(v))
   244  	return input[step:], true
   245  }
   246  
   247  type parseState int32
   248  
   249  const (
   250  	parseStateNormal    parseState = 1
   251  	parseStateFail      parseState = 2
   252  	parseStateEndOfLine parseState = 3
   253  )
   254  
   255  func parseSep(input string) (string, parseState) {
   256  	input = trimWhiteSpace(input)
   257  	if len(input) == 0 {
   258  		return input, parseStateEndOfLine
   259  	}
   260  	if input[0] != ':' {
   261  		return input, parseStateFail
   262  	}
   263  	if input = trimWhiteSpace(input[1:]); len(input) == 0 {
   264  		return input, parseStateEndOfLine
   265  	}
   266  	return input, parseStateNormal
   267  }
   268  
   269  // Time, 12-hour (hh:mm:ss followed by AM or PM)
   270  func time12Hour(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   271  	tryParse := func(input string) (string, parseState) {
   272  		// hh:mm:ss AM
   273  		/// Note that we should update `t` as soon as possible, or we
   274  		/// can not get correct result for incomplete input like "12:13"
   275  		/// that is shorter than "hh:mm:ss"
   276  		hour, step := parseNDigits(input, 2) // 1..12
   277  		if step <= 0 || hour > 12 || hour == 0 {
   278  			return input, parseStateFail
   279  		}
   280  		// Handle special case: 12:34:56 AM -> 00:34:56
   281  		// For PM, we will add 12 it later
   282  		if hour == 12 {
   283  			hour = 0
   284  		}
   285  		t.setHour(uint8(hour))
   286  
   287  		// ':'
   288  		var state parseState
   289  		if input, state = parseSep(input[step:]); state != parseStateNormal {
   290  			return input, state
   291  		}
   292  
   293  		minute, step := parseNDigits(input, 2) // 0..59
   294  		if step <= 0 || minute > 59 {
   295  			return input, parseStateFail
   296  		}
   297  		t.setMinute(uint8(minute))
   298  
   299  		// ':'
   300  		if input, state = parseSep(input[step:]); state != parseStateNormal {
   301  			return input, state
   302  		}
   303  
   304  		second, step := parseNDigits(input, 2) // 0..59
   305  		if step <= 0 || second > 59 {
   306  			return input, parseStateFail
   307  		}
   308  		t.setSecond(uint8(second))
   309  
   310  		input = trimWhiteSpace(input[step:])
   311  		if len(input) == 0 {
   312  			// No "AM"/"PM" suffix, it is ok
   313  			return input, parseStateEndOfLine
   314  		} else if len(input) < 2 {
   315  			// some broken char, fail
   316  			return input, parseStateFail
   317  		}
   318  
   319  		switch {
   320  		case hasCaseInsensitivePrefix(input, "AM"):
   321  			t.setHour(uint8(hour))
   322  		case hasCaseInsensitivePrefix(input, "PM"):
   323  			t.setHour(uint8(hour + 12))
   324  		default:
   325  			return input, parseStateFail
   326  		}
   327  
   328  		return input[2:], parseStateNormal
   329  	}
   330  
   331  	remain, state := tryParse(input)
   332  	if state == parseStateFail {
   333  		return input, false
   334  	}
   335  	return remain, true
   336  }
   337  
   338  // Time, 24-hour (hh:mm:ss)
   339  func time24Hour(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   340  	tryParse := func(input string) (string, parseState) {
   341  		// hh:mm:ss
   342  		/// Note that we should update `t` as soon as possible, or we
   343  		/// can not get correct result for incomplete input like "12:13"
   344  		/// that is shorter than "hh:mm:ss"
   345  		hour, step := parseNDigits(input, 2) // 0..23
   346  		if step <= 0 || hour > 23 {
   347  			return input, parseStateFail
   348  		}
   349  		t.setHour(uint8(hour))
   350  
   351  		// ':'
   352  		var state parseState
   353  		if input, state = parseSep(input[step:]); state != parseStateNormal {
   354  			return input, state
   355  		}
   356  
   357  		minute, step := parseNDigits(input, 2) // 0..59
   358  		if step <= 0 || minute > 59 {
   359  			return input, parseStateFail
   360  		}
   361  		t.setMinute(uint8(minute))
   362  
   363  		// ':'
   364  		if input, state = parseSep(input[step:]); state != parseStateNormal {
   365  			return input, state
   366  		}
   367  
   368  		second, step := parseNDigits(input, 2) // 0..59
   369  		if step <= 0 || second > 59 {
   370  			return input, parseStateFail
   371  		}
   372  		t.setSecond(uint8(second))
   373  		return input[step:], parseStateNormal
   374  	}
   375  
   376  	remain, state := tryParse(input)
   377  	if state == parseStateFail {
   378  		return input, false
   379  	}
   380  	return remain, true
   381  }
   382  
   383  const (
   384  	timeOfAM = 1 + iota
   385  	timeOfPM
   386  )
   387  
   388  // judege AM or PM
   389  func isAMOrPM(_ *GeneralTime, input string, ctx map[string]int) (string, bool) {
   390  	if len(input) < 2 {
   391  		return input, false
   392  	}
   393  
   394  	s := strings.ToLower(input[:2])
   395  	switch s {
   396  	case "am":
   397  		ctx["%p"] = timeOfAM
   398  	case "pm":
   399  		ctx["%p"] = timeOfPM
   400  	default:
   401  		return input, false
   402  	}
   403  	return input[2:], true
   404  }
   405  
   406  // Day of the month, numeric (0..31)
   407  func dayOfMonthNumeric(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   408  	v, step := parseNDigits(input, 2) // 0..31
   409  	if step <= 0 || v > 31 {
   410  		return input, false
   411  	}
   412  	t.setDay(uint8(v))
   413  	return input[step:], true
   414  }
   415  
   416  // Hour (00..23)
   417  func hour24Numeric(t *GeneralTime, input string, ctx map[string]int) (string, bool) {
   418  	v, step := parseNDigits(input, 2) // 0..23
   419  	if step <= 0 || v > 23 {
   420  		return input, false
   421  	}
   422  	t.setHour(uint8(v))
   423  	ctx["%H"] = v
   424  	return input[step:], true
   425  }
   426  
   427  // Hour result (01..12)
   428  func hour12Numeric(t *GeneralTime, input string, ctx map[string]int) (string, bool) {
   429  	v, step := parseNDigits(input, 2) // 1..12
   430  	if step <= 0 || v > 12 || v == 0 {
   431  		return input, false
   432  	}
   433  	t.setHour(uint8(v))
   434  	ctx["%h"] = v
   435  	return input[step:], true
   436  }
   437  
   438  // Microseconds (000000..999999)
   439  func microSeconds(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   440  	v, step := parseNDigits(input, 6)
   441  	if step <= 0 {
   442  		t.setMicrosecond(0)
   443  		return input, true
   444  	}
   445  	for i := step; i < 6; i++ {
   446  		v *= 10
   447  	}
   448  	t.setMicrosecond(uint32(v))
   449  	return input[step:], true
   450  }
   451  
   452  // Year, numeric, four digits
   453  func yearNumericFourDigits(t *GeneralTime, input string, ctx map[string]int) (string, bool) {
   454  	return yearNumericNDigits(t, input, ctx, 4)
   455  }
   456  
   457  // Year, numeric (two digits)
   458  func yearNumericTwoDigits(t *GeneralTime, input string, ctx map[string]int) (string, bool) {
   459  	return yearNumericNDigits(t, input, ctx, 2)
   460  }
   461  
   462  func yearNumericNDigits(t *GeneralTime, input string, _ map[string]int, n int) (string, bool) {
   463  	year, step := parseNDigits(input, n)
   464  	if step <= 0 {
   465  		return input, false
   466  	} else if step <= 2 {
   467  		year = adjustYear(year)
   468  	}
   469  	t.setYear(uint16(year))
   470  	return input[step:], true
   471  }
   472  
   473  // adjustYear adjusts year according to y.
   474  // link to: https://dev.mysql.com/doc/refman/8.0/en/two-digit-years.html
   475  func adjustYear(y int) int {
   476  	if y >= 0 && y <= 69 {
   477  		y = 2000 + y
   478  	} else if y >= 70 && y <= 99 {
   479  		y = 1900 + y
   480  	}
   481  	return y
   482  }
   483  
   484  // Day of year (001..366)
   485  func dayOfYearNumeric(_ *GeneralTime, input string, ctx map[string]int) (string, bool) {
   486  	// MySQL declares that "%j" should be "Day of year (001..366)". But actually,
   487  	// it accepts a number that is up to three digits, which range is [1, 999].
   488  	v, step := parseNDigits(input, 3)
   489  	if step <= 0 || v == 0 {
   490  		return input, false
   491  	}
   492  	ctx["%j"] = v
   493  	return input[step:], true
   494  }
   495  
   496  // Abbreviated month name (Jan..Dec)
   497  func abbreviatedMonth(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   498  	if len(input) >= 3 {
   499  		monthName := strings.ToLower(input[:3])
   500  		if month, ok := monthAbbrev[monthName]; ok {
   501  			t.setMonth(uint8(month))
   502  			return input[len(monthName):], true
   503  		}
   504  	}
   505  	return input, false
   506  }
   507  
   508  func hasCaseInsensitivePrefix(input, prefix string) bool {
   509  	if len(input) < len(prefix) {
   510  		return false
   511  	}
   512  	return strings.EqualFold(input[:len(prefix)], prefix)
   513  }
   514  
   515  // Month name (January..December)
   516  func fullNameMonth(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   517  	for i, month := range MonthNames {
   518  		if hasCaseInsensitivePrefix(input, month) {
   519  			t.setMonth(uint8(i + 1))
   520  			return input[len(month):], true
   521  		}
   522  	}
   523  	return input, false
   524  }
   525  
   526  // Month, numeric (0..12)
   527  func monthNumeric(t *GeneralTime, input string, _ map[string]int) (string, bool) {
   528  	v, step := parseNDigits(input, 2) // 1..12
   529  	if step <= 0 || v > 12 {
   530  		return input, false
   531  	}
   532  	t.setMonth(uint8(v))
   533  	return input[step:], true
   534  }
   535  
   536  // DateFSP gets fsp from date string.
   537  func DateFSP(date string) (fsp int) {
   538  	i := strings.LastIndex(date, ".")
   539  	if i != -1 {
   540  		fsp = len(date) - i - 1
   541  	}
   542  	return
   543  }
   544  
   545  // Skip all numbers
   546  func skipAllNums(_ *GeneralTime, input string, _ map[string]int) (string, bool) {
   547  	retIdx := 0
   548  	for i, ch := range input {
   549  		if unicode.IsNumber(ch) {
   550  			retIdx = i + 1
   551  		} else {
   552  			break
   553  		}
   554  	}
   555  	return input[retIdx:], true
   556  }
   557  
   558  // Skip all punctation characters
   559  func skipAllPunct(_ *GeneralTime, input string, _ map[string]int) (string, bool) {
   560  	retIdx := 0
   561  	for i, ch := range input {
   562  		if unicode.IsPunct(ch) {
   563  			retIdx = i + 1
   564  		} else {
   565  			break
   566  		}
   567  	}
   568  	return input[retIdx:], true
   569  }
   570  
   571  // Skip all alpha characters
   572  func skipAllAlpha(_ *GeneralTime, input string, _ map[string]int) (string, bool) {
   573  	retIdx := 0
   574  	for i, ch := range input {
   575  		if unicode.IsLetter(ch) {
   576  			retIdx = i + 1
   577  		} else {
   578  			break
   579  		}
   580  	}
   581  	return input[retIdx:], true
   582  }