github.com/matrixorigin/matrixone@v1.2.0/pkg/container/types/date.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 types
    16  
    17  import (
    18  	"fmt"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  )
    25  
    26  const (
    27  	daysPer400Years = 365*400 + 97
    28  	daysPer100Years = 365*100 + 24
    29  	daysPer4Years   = 365*4 + 1
    30  )
    31  
    32  type Weekday uint8
    33  
    34  const (
    35  	Sunday Weekday = iota
    36  	Monday
    37  	Tuesday
    38  	Wednesday
    39  	Thursday
    40  	Friday
    41  	Saturday
    42  )
    43  
    44  // String returns the English name of the day ("Sunday", "Monday", ...).
    45  func (d Weekday) String() string {
    46  	if d <= Saturday {
    47  		return longDayNames[d]
    48  	}
    49  	return "%Weekday(" + strconv.FormatUint(uint64(d), 10) + ")"
    50  }
    51  
    52  var unixEpochMicroSecs = int64(DatetimeFromClock(1970, 1, 1, 0, 0, 0, 0))
    53  var unixEpochDays = int32(DateFromCalendar(1970, 1, 1))
    54  
    55  var (
    56  	leapYearMonthDays = []uint8{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    57  	flatYearMonthDays = []uint8{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    58  )
    59  
    60  const (
    61  	MaxDateYear    = 9999
    62  	MinDateYear    = 1
    63  	MaxMonthInYear = 12
    64  	MinMonthInYear = 1
    65  )
    66  
    67  type TimeType int32
    68  
    69  const (
    70  	DateType      = 0
    71  	DateTimeType  = 1
    72  	TimeStampType = 2
    73  )
    74  
    75  func isDigit(c byte) bool {
    76  	return '0' <= c && c <= '9'
    77  }
    78  
    79  func isAllDigit(s string) bool {
    80  	for i := range s {
    81  		if !isDigit(s[i]) {
    82  			return false
    83  		}
    84  	}
    85  	return true
    86  }
    87  
    88  func toNumber(s string) (result int64) {
    89  	for _, c := range s {
    90  		result = 10*result + int64(c-'0')
    91  	}
    92  	return
    93  }
    94  
    95  // rewrite ParseDateCast, don't use regexp, that's too slow
    96  // the format we need to support:
    97  // 1.yyyy-mm-dd hh:mm:ss.ms or yyyy-mm-dd hh:mm: or yyyy-mm-dd hh:mm
    98  // 2.yyyy-mm-dd
    99  // 3.yyyymmdd
   100  func ParseDateCast(s string) (Date, error) {
   101  	var y, m, d, hh, mm, ss strings.Builder
   102  	s = strings.TrimSpace(s)
   103  	if len(s) < 7 && isAllDigit(s) {
   104  		return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   105  	}
   106  	// a special we need to process
   107  	// we need to support 2220919,so we need to add a '0' to extend
   108  	if len(s) == 7 && isAllDigit(s) {
   109  		var b strings.Builder
   110  		b.WriteByte('0')
   111  		b.WriteString(s)
   112  		s = b.String()
   113  	}
   114  	// for the third type, process here
   115  	if len(s) == 8 && isAllDigit(s) {
   116  		y.WriteString(s[:4])
   117  		m.WriteString(s[4:6])
   118  		d.WriteString(s[6:8])
   119  	} else {
   120  		const (
   121  			start uint8 = iota
   122  			yearState
   123  			monthState
   124  			dayState
   125  			hourState
   126  			minuteState
   127  			secondState
   128  			msState
   129  			end
   130  		)
   131  		// state is used to flag the state of the DAG, we process 1,2 below
   132  		var state = start
   133  		for i := 0; i < len(s); i++ {
   134  			switch state {
   135  			case start:
   136  				if !isDigit(s[i]) {
   137  					return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   138  				}
   139  				state = yearState
   140  				y.WriteByte(s[i])
   141  				if y.Len() >= 5 {
   142  					return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   143  				}
   144  			case yearState:
   145  				if isDigit(s[i]) {
   146  					y.WriteByte(s[i])
   147  				} else if s[i] == '-' {
   148  					state = monthState
   149  					if y.Len() == 0 {
   150  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   151  					}
   152  				} else {
   153  					return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   154  				}
   155  			case monthState:
   156  				if isDigit(s[i]) {
   157  					m.WriteByte(s[i])
   158  					if m.Len() >= 3 {
   159  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   160  					}
   161  				} else if s[i] == '-' {
   162  					// Can't go into dayState, because the Month is empty
   163  					if m.Len() == 0 {
   164  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   165  					} else {
   166  						state = dayState
   167  					}
   168  				}
   169  			case dayState:
   170  				if isDigit(s[i]) {
   171  					d.WriteByte(s[i])
   172  					if d.Len() >= 3 {
   173  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   174  					}
   175  				} else {
   176  					if s[i] == ' ' {
   177  						if d.Len() == 0 {
   178  							return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   179  						}
   180  						state = hourState
   181  					} else {
   182  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   183  					}
   184  				}
   185  				if i == len(s)-1 {
   186  					state = end
   187  				}
   188  			case hourState:
   189  				// we need to support '2022-09-01                   23:11:12.3'
   190  				// not only '2022-09-01 23:11:12.3'
   191  				if s[i] == ' ' {
   192  					continue
   193  				} else {
   194  					if isDigit(s[i]) {
   195  						hh.WriteByte(s[i])
   196  						if hh.Len() >= 3 {
   197  							return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   198  						}
   199  					} else {
   200  						if s[i] == ':' {
   201  							if hh.Len() == 0 {
   202  								return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   203  							}
   204  							state = minuteState
   205  						} else {
   206  							return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   207  						}
   208  					}
   209  				}
   210  			case minuteState:
   211  				if isDigit(s[i]) {
   212  					mm.WriteByte(s[i])
   213  					if mm.Len() >= 3 {
   214  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   215  					}
   216  					if i == len(s)-1 { // we need to support '2022-09-01 23:11'
   217  						s = s + ":00"
   218  					}
   219  				} else if s[i] == ':' {
   220  					// Can't go into secondState, because the Minute is empty
   221  					if mm.Len() == 0 {
   222  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   223  					}
   224  					if i == len(s)-1 { // we need to support '2022-09-01 23:11:'
   225  						s = s + "00"
   226  					}
   227  					state = secondState
   228  				}
   229  			case secondState:
   230  				if isDigit(s[i]) {
   231  					ss.WriteByte(s[i])
   232  					if ss.Len() >= 3 {
   233  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   234  					}
   235  				} else {
   236  					if s[i] == '.' {
   237  						if ss.Len() == 0 {
   238  							return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   239  						}
   240  						state = msState
   241  					} else {
   242  						return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   243  					}
   244  				}
   245  				if i == len(s)-1 {
   246  					state = end
   247  				}
   248  			case msState:
   249  				if isAllDigit(s[i:]) {
   250  					state = end
   251  					// break out loop
   252  					i = len(s)
   253  				} else {
   254  					return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   255  				}
   256  			}
   257  		}
   258  		if state != end {
   259  			return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   260  		}
   261  	}
   262  	year := toNumber(y.String())
   263  	month := toNumber(m.String())
   264  	day := toNumber(d.String())
   265  	if ValidDate(int32(year), uint8(month), uint8(day)) {
   266  		return DateFromCalendar(int32(year), uint8(month), uint8(day)), nil
   267  	}
   268  	return -1, moerr.NewInvalidArgNoCtx("parsedate", s)
   269  }
   270  
   271  // date[0001-01-01 to 9999-12-31]
   272  func ValidDate(year int32, month, day uint8) bool {
   273  	if year >= MinDateYear && year <= MaxDateYear {
   274  		if MinMonthInYear <= month && month <= MaxMonthInYear {
   275  			if day > 0 {
   276  				if isLeap(year) {
   277  					return day <= leapYearMonthDays[month-1]
   278  				} else {
   279  					return day <= flatYearMonthDays[month-1]
   280  				}
   281  			}
   282  		}
   283  	}
   284  	return false
   285  }
   286  
   287  func (d Date) String() string {
   288  	y, m, day, _ := d.Calendar(true)
   289  	return fmt.Sprintf("%04d-%02d-%02d", y, m, day)
   290  }
   291  
   292  // Today Holds number of days since January 1, year 1 in Gregorian calendar
   293  func Today(loc *time.Location) Date {
   294  	return Now(loc).ToDate()
   295  }
   296  
   297  const dayInfoTableMinYear = 1924
   298  const dayInfoTableMaxYear = 2099
   299  const dayInfoTableYears = dayInfoTableMaxYear - dayInfoTableMinYear + 1
   300  const dayInfoTableSize = dayInfoTableYears*365 + (dayInfoTableMaxYear-dayInfoTableMinYear)/4 + 1
   301  const dayNumOfTableEpoch = 702360 // the day number of "1924-01-01"
   302  
   303  type dayInfo struct {
   304  	year uint16
   305  	//month uint8
   306  	//week  uint8
   307  }
   308  
   309  var dayInfoTable [dayInfoTableSize]dayInfo
   310  
   311  // this init function takes a bit of build time
   312  func init() {
   313  	yearNow := uint16(1924)
   314  	i := int32(0)
   315  	for yearIndex := 0; yearIndex < dayInfoTableYears; yearIndex++ {
   316  		if yearIndex%4 == 0 { // this is a leap year
   317  			for j := 0; j < 366; j++ {
   318  				dayInfoTable[i].year = yearNow
   319  				i++
   320  			}
   321  		} else {
   322  			for j := 0; j < 365; j++ {
   323  				dayInfoTable[i].year = yearNow
   324  				i++
   325  			}
   326  		}
   327  		yearNow++
   328  	}
   329  }
   330  
   331  // Year takes a date and returns an uint16 number as the year of this date
   332  func (d Date) Year() uint16 {
   333  	dayNum := int32(d)
   334  	insideDayInfoTable := dayNum >= dayNumOfTableEpoch && dayNum < dayNumOfTableEpoch+dayInfoTableSize
   335  	if insideDayInfoTable {
   336  		return dayInfoTable[dayNum-dayNumOfTableEpoch].year
   337  	}
   338  	// Account for 400 year cycles.
   339  	n := d / daysPer400Years
   340  	y := 400 * n
   341  	d -= daysPer400Years * n
   342  
   343  	// Cut off 100-year cycles.
   344  	// The last cycle has one extra leap year, so on the last day
   345  	// of that year, day / daysPer100Years will be 4 instead of 3.
   346  	// Cut it back down to 3 by subtracting n>>2.
   347  	n = d / daysPer100Years
   348  	n -= n >> 2
   349  	y += 100 * n
   350  	d -= daysPer100Years * n
   351  
   352  	// Cut off 4-year cycles.
   353  	// The last cycle has a missing leap year, which does not
   354  	// affect the computation.
   355  	n = d / daysPer4Years
   356  	y += 4 * n
   357  	d -= daysPer4Years * n
   358  
   359  	// Cut off years within a 4-year cycle.
   360  	// The last year is a leap year, so on the last day of that year,
   361  	// day / 365 will be 4 instead of 3. Cut it back down to 3
   362  	// by subtracting n>>2.
   363  	n = d / 365
   364  	n -= n >> 2
   365  	y += n
   366  
   367  	year := uint16(y) + 1
   368  
   369  	return year
   370  }
   371  
   372  func (d Date) YearMonth() uint32 {
   373  	year, month, _, _ := d.Calendar(true)
   374  	yearStr := fmt.Sprintf("%04d", year)
   375  	monthStr := fmt.Sprintf("%02d", month)
   376  	result, _ := strconv.ParseUint(yearStr+monthStr, 10, 32)
   377  	return uint32(result)
   378  }
   379  
   380  func (d Date) YearMonthStr() string {
   381  	year, month, _, _ := d.Calendar(true)
   382  	yearStr := fmt.Sprintf("%04d", year)
   383  	monthStr := fmt.Sprintf("%02d", month)
   384  	return yearStr + monthStr
   385  }
   386  
   387  var monthToQuarter = map[uint8]uint32{
   388  	1:  1,
   389  	2:  1,
   390  	3:  1,
   391  	4:  2,
   392  	5:  2,
   393  	6:  2,
   394  	7:  3,
   395  	8:  3,
   396  	9:  3,
   397  	10: 4,
   398  	11: 4,
   399  	12: 4,
   400  }
   401  
   402  func (d Date) Quarter() uint32 {
   403  	_, month, _, _ := d.Calendar(true)
   404  	return monthToQuarter[month]
   405  }
   406  
   407  func (d Date) Calendar(full bool) (year int32, month, day uint8, yday uint16) {
   408  	// Account for 400 year cycles.
   409  	n := d / daysPer400Years
   410  	y := 400 * n
   411  	d -= daysPer400Years * n
   412  
   413  	// Cut off 100-year cycles.
   414  	// The last cycle has one extra leap year, so on the last day
   415  	// of that year, day / daysPer100Years will be 4 instead of 3.
   416  	// Cut it back down to 3 by subtracting n>>2.
   417  	n = d / daysPer100Years
   418  	n -= n >> 2
   419  	y += 100 * n
   420  	d -= daysPer100Years * n
   421  
   422  	// Cut off 4-year cycles.
   423  	// The last cycle has a missing leap year, which does not
   424  	// affect the computation.
   425  	n = d / daysPer4Years
   426  	y += 4 * n
   427  	d -= daysPer4Years * n
   428  
   429  	// Cut off years within a 4-year cycle.
   430  	// The last year is a leap year, so on the last day of that year,
   431  	// day / 365 will be 4 instead of 3. Cut it back down to 3
   432  	// by subtracting n>>2.
   433  	n = d / 365
   434  	n -= n >> 2
   435  	y += n
   436  	d -= 365 * n
   437  
   438  	year = int32(y) + 1
   439  	yday = uint16(d + 1)
   440  
   441  	if !full {
   442  		return
   443  	}
   444  
   445  	if isLeap(year) {
   446  		// Leap year
   447  		switch {
   448  		case d > 31+29-1:
   449  			// After leap day; pretend it wasn't there.
   450  			d--
   451  		case d == 31+29-1:
   452  			// Leap day.
   453  			month = 2
   454  			day = 29
   455  			return
   456  		}
   457  	}
   458  
   459  	// Estimate month on assumption that every month has 31 days.
   460  	// The estimate may be too low by at most one month, so adjust.
   461  	month = uint8(d / 31)
   462  	end := daysBefore[month+1]
   463  	var begin uint16
   464  	if uint16(d) >= end {
   465  		month++
   466  		begin = end
   467  	} else {
   468  		begin = daysBefore[month]
   469  	}
   470  
   471  	month++ // because January is 1
   472  	day = uint8(uint16(d) - begin + 1)
   473  	return year, month, day, yday
   474  }
   475  
   476  // daysBefore[m] counts the number of days in a non-leap year
   477  // before month m begins. There is an entry for m=12, counting
   478  // the number of days before January of next year (365).
   479  
   480  var daysBefore = [...]uint16{
   481  	0,
   482  	31,
   483  	31 + 28,
   484  	31 + 28 + 31,
   485  	31 + 28 + 31 + 30,
   486  	31 + 28 + 31 + 30 + 31,
   487  	31 + 28 + 31 + 30 + 31 + 30,
   488  	31 + 28 + 31 + 30 + 31 + 30 + 31,
   489  	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
   490  	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
   491  	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
   492  	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
   493  	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
   494  }
   495  
   496  func DateFromCalendar(year int32, month, day uint8) Date {
   497  	// Compute days since the absolute epoch.
   498  	d := daysSinceEpoch(year - 1)
   499  
   500  	// Add in days before this month.
   501  	d += int32(daysBefore[month-1])
   502  	if isLeap(year) && month >= 3 {
   503  		d++ // February 29
   504  	}
   505  
   506  	// Add in days before today.
   507  	d += int32(day - 1)
   508  
   509  	return Date(d)
   510  }
   511  
   512  func daysSinceEpoch(year int32) int32 {
   513  	// Add in days from 400-year cycles.
   514  	n := year / 400
   515  	year -= 400 * n
   516  	d := daysPer400Years * n
   517  
   518  	// Add in 100-year cycles.
   519  	n = year / 100
   520  	year -= 100 * n
   521  	d += daysPer100Years * n
   522  
   523  	// Add in 4-year cycles.
   524  	n = year / 4
   525  	year -= 4 * n
   526  	d += daysPer4Years * n
   527  
   528  	// Add in non-leap years.
   529  	n = year
   530  	d += 365 * n
   531  
   532  	return d
   533  }
   534  
   535  // DayOfWeek return the day of the week counting from Sunday
   536  func (d Date) DayOfWeek() Weekday {
   537  	// January 1, year 1 in Gregorian calendar, was a Monday.
   538  	return Weekday((d + 1) % 7)
   539  }
   540  
   541  // DayOfWeek2 return the day of the week counting from Monday
   542  func (d Date) DayOfWeek2() Weekday {
   543  	// January 1, year 1 in Gregorian calendar, was a Monday.
   544  	return Weekday(d % 7)
   545  }
   546  
   547  // DayOfYear return day of year (001..366)
   548  func (d Date) DayOfYear() uint16 {
   549  	_, _, _, yday := d.Calendar(false)
   550  	return yday
   551  }
   552  
   553  func (d Date) WeekOfYear() (year int32, week uint8) {
   554  	// According to the rule that the first calendar week of a calendar year is
   555  	// the week including the first Thursday of that year, and that the last one is
   556  	// the week immediately preceding the first calendar week of the next calendar year.
   557  	// See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details.
   558  
   559  	// weeks start with Monday
   560  	// Monday Tuesday Wednesday Thursday Friday Saturday Sunday
   561  	// 1      2       3         4        5      6        7
   562  	// +3     +2      +1        0        -1     -2       -3
   563  	// the offset to Thursday
   564  	delta := 4 - int32(d.DayOfWeek())
   565  	// handle Sunday
   566  	if delta == 4 {
   567  		delta = -3
   568  	}
   569  	// find the Thursday of the calendar week
   570  	d = Date(int32(d) + delta)
   571  	year, _, _, yday := d.Calendar(false)
   572  	return year, uint8((yday-1)/7 + 1)
   573  }
   574  
   575  func (d Date) WeekOfYear2() uint8 {
   576  	// According to the rule that the first calendar week of a calendar year is
   577  	// the week including the first Thursday of that year, and that the last one is
   578  	// the week immediately preceding the first calendar week of the next calendar year.
   579  	// See https://www.iso.org/obp/ui#iso:std:iso:8601:-1:ed-1:v1:en:term:3.1.1.23 for details.
   580  
   581  	// weeks start with Monday
   582  	// Monday Tuesday Wednesday Thursday Friday Saturday Sunday
   583  	// 1      2       3         4        5      6        7
   584  	// +3     +2      +1        0        -1     -2       -3
   585  	// the offset to Thursday
   586  	delta := 4 - int32(d.DayOfWeek())
   587  	// handle Sunday
   588  	if delta == 4 {
   589  		delta = -3
   590  	}
   591  	// find the Thursday of the calendar week
   592  	d = Date(int32(d) + delta)
   593  	_, _, _, yday := d.Calendar(false)
   594  	return uint8((yday-1)/7 + 1)
   595  }
   596  
   597  type WeekBehaviour uint
   598  
   599  const (
   600  	// WeekMondayFirst: set Monday as first day of week; otherwise Sunday is first day of week
   601  	WeekMondayFirst WeekBehaviour = 1
   602  
   603  	// WeekYear: If set, Week is in range 1-53, otherwise Week is in range 0-53.
   604  	//	Week 0 is returned for the the last week of the previous year (for
   605  	// a date at start of january) In this case one can get 53 for the
   606  	// first week of next year.  This flag ensures that the week is
   607  	// relevant for the given year. Note that this flag is only
   608  	// releveant if WEEK_JANUARY is not set.
   609  	WeekYear = 2
   610  
   611  	//WeekFirstWeekday: If not set, Weeks are numbered according to ISO 8601:1988.
   612  	// If set, the week that contains the first 'first-day-of-week' is week 1.
   613  	// ISO 8601:1988 means that if the week containing January 1 has
   614  	// four or more days in the new year, then it is week 1;
   615  	// Otherwise it is the last week of the previous year, and the next week is week 1.
   616  	WeekFirstWeekday = 4
   617  )
   618  
   619  func (v WeekBehaviour) bitAnd(flag WeekBehaviour) bool {
   620  	return (v & flag) != 0
   621  }
   622  
   623  func weekMode(mode int) WeekBehaviour {
   624  	weekFormat := WeekBehaviour(mode & 7)
   625  	if (weekFormat & WeekMondayFirst) == 0 {
   626  		weekFormat ^= WeekFirstWeekday
   627  	}
   628  	return weekFormat
   629  }
   630  
   631  // Week (00..53), where Sunday is the first day of the week; WEEK() mode 0
   632  // Week (00..53), where Monday is the first day of the week; WEEK() mode 1
   633  func (d Date) Week(mode int) int {
   634  	if d.Month() == 0 || d.Day() == 0 {
   635  		return 0
   636  	}
   637  	_, week := calcWeek(d, weekMode(mode))
   638  	return week
   639  }
   640  
   641  // YearWeek returns year and week.
   642  func (d Date) YearWeek(mode int) (year int, week int) {
   643  	behavior := weekMode(mode) | WeekYear
   644  	return calcWeek(d, behavior)
   645  }
   646  
   647  // calcWeek calculates week and year for the date.
   648  func calcWeek(d Date, wb WeekBehaviour) (year int, week int) {
   649  	var days int
   650  	ty, tm, td := int(d.Year()), int(d.Month()), int(d.Day())
   651  	daynr := calcDaynr(ty, tm, td)
   652  	firstDaynr := calcDaynr(ty, 1, 1)
   653  	mondayFirst := wb.bitAnd(WeekMondayFirst)
   654  	weekYear := wb.bitAnd(WeekYear)
   655  	firstWeekday := wb.bitAnd(WeekFirstWeekday)
   656  
   657  	weekday := calcWeekday(firstDaynr, !mondayFirst)
   658  
   659  	year = ty
   660  
   661  	if tm == 1 && td <= 7-weekday {
   662  		if !weekYear &&
   663  			((firstWeekday && weekday != 0) || (!firstWeekday && weekday >= 4)) {
   664  			week = 0
   665  			return
   666  		}
   667  		weekYear = true
   668  		year--
   669  		days = calcDaysInYear(year)
   670  		firstDaynr -= days
   671  		weekday = (weekday + 53*7 - days) % 7
   672  	}
   673  
   674  	if (firstWeekday && weekday != 0) ||
   675  		(!firstWeekday && weekday >= 4) {
   676  		days = daynr - (firstDaynr + 7 - weekday)
   677  	} else {
   678  		days = daynr - (firstDaynr - weekday)
   679  	}
   680  
   681  	if weekYear && days >= 52*7 {
   682  		weekday = (weekday + calcDaysInYear(year)) % 7
   683  		if (!firstWeekday && weekday < 4) ||
   684  			(firstWeekday && weekday == 0) {
   685  			year++
   686  			week = 1
   687  			return
   688  		}
   689  	}
   690  	week = days/7 + 1
   691  	return
   692  }
   693  
   694  // calcWeekday calculates weekday from daynr, returns 0 for Monday, 1 for Tuesday
   695  func calcWeekday(daynr int, sundayFirstDayOfWeek bool) int {
   696  	daynr += 5
   697  	if sundayFirstDayOfWeek {
   698  		daynr++
   699  	}
   700  	return daynr % 7
   701  }
   702  
   703  // Calculate nr of day since year 0 in new date-system (from 1615).
   704  func calcDaynr(year, month, day int) int {
   705  	if year == 0 && month == 0 {
   706  		return 0
   707  	}
   708  
   709  	delsum := 365*year + 31*(month-1) + day
   710  	if month <= 2 {
   711  		year--
   712  	} else {
   713  		delsum -= (month*4 + 23) / 10
   714  	}
   715  	temp := ((year/100 + 1) * 3) / 4
   716  	return delsum + year/4 - temp
   717  }
   718  
   719  // calcDaysInYear calculates days in one year, it works with 0 <= year <= 99.
   720  func calcDaysInYear(year int) int {
   721  	if (year&3) == 0 && (year%100 != 0 || (year%400 == 0 && (year != 0))) {
   722  		return 366
   723  	}
   724  	return 365
   725  }
   726  
   727  func isLeap(year int32) bool {
   728  	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
   729  }
   730  
   731  func (d Date) ToDatetime() Datetime {
   732  	return Datetime(int64(d) * SecsPerDay * MicroSecsPerSec)
   733  }
   734  
   735  func (d Date) ToTime() Time {
   736  	return Time(0)
   737  }
   738  
   739  func (d Date) ToTimestamp(loc *time.Location) Timestamp {
   740  	year, mon, day, _ := d.Calendar(true)
   741  	t := time.Date(int(year), time.Month(mon), int(day), 0, 0, 0, 0, loc)
   742  	return Timestamp(t.UnixMicro() + unixEpochMicroSecs)
   743  }
   744  
   745  func (d Date) Month() uint8 {
   746  	_, month, _, _ := d.Calendar(true)
   747  	return month
   748  }
   749  
   750  func LastDay(year int32, month uint8) uint8 {
   751  	if isLeap(year) {
   752  		return leapYearMonthDays[month-1]
   753  	}
   754  	return flatYearMonthDays[month-1]
   755  }
   756  
   757  func (d Date) Day() uint8 {
   758  	_, _, day, _ := d.Calendar(true)
   759  	return day
   760  }
   761  
   762  func (d Date) DaysSinceUnixEpoch() int32 {
   763  	return int32(d) - unixEpochDays
   764  }
   765  
   766  func GetUnixEpochSecs() int64 {
   767  	return unixEpochMicroSecs
   768  }