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