datetime_functions.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package engine
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
  7. )
  8. // ===============================
  9. // DATE/TIME CONSTANTS
  10. // ===============================
  11. // CurrentDate returns the current date as a string in YYYY-MM-DD format
  12. func (e *SQLEngine) CurrentDate() (*schema_pb.Value, error) {
  13. now := time.Now()
  14. dateStr := now.Format("2006-01-02")
  15. return &schema_pb.Value{
  16. Kind: &schema_pb.Value_StringValue{StringValue: dateStr},
  17. }, nil
  18. }
  19. // CurrentTimestamp returns the current timestamp
  20. func (e *SQLEngine) CurrentTimestamp() (*schema_pb.Value, error) {
  21. now := time.Now()
  22. // Return as TimestampValue with microseconds
  23. timestampMicros := now.UnixMicro()
  24. return &schema_pb.Value{
  25. Kind: &schema_pb.Value_TimestampValue{
  26. TimestampValue: &schema_pb.TimestampValue{
  27. TimestampMicros: timestampMicros,
  28. },
  29. },
  30. }, nil
  31. }
  32. // CurrentTime returns the current time as a string in HH:MM:SS format
  33. func (e *SQLEngine) CurrentTime() (*schema_pb.Value, error) {
  34. now := time.Now()
  35. timeStr := now.Format("15:04:05")
  36. return &schema_pb.Value{
  37. Kind: &schema_pb.Value_StringValue{StringValue: timeStr},
  38. }, nil
  39. }
  40. // Now is an alias for CurrentTimestamp (common SQL function name)
  41. func (e *SQLEngine) Now() (*schema_pb.Value, error) {
  42. return e.CurrentTimestamp()
  43. }
  44. // ===============================
  45. // EXTRACT FUNCTION
  46. // ===============================
  47. // DatePart represents the part of a date/time to extract
  48. type DatePart string
  49. const (
  50. PartYear DatePart = "YEAR"
  51. PartMonth DatePart = "MONTH"
  52. PartDay DatePart = "DAY"
  53. PartHour DatePart = "HOUR"
  54. PartMinute DatePart = "MINUTE"
  55. PartSecond DatePart = "SECOND"
  56. PartWeek DatePart = "WEEK"
  57. PartDayOfYear DatePart = "DOY"
  58. PartDayOfWeek DatePart = "DOW"
  59. PartQuarter DatePart = "QUARTER"
  60. PartEpoch DatePart = "EPOCH"
  61. )
  62. // Extract extracts a specific part from a date/time value
  63. func (e *SQLEngine) Extract(part DatePart, value *schema_pb.Value) (*schema_pb.Value, error) {
  64. if value == nil {
  65. return nil, fmt.Errorf("EXTRACT function requires non-null value")
  66. }
  67. // Convert value to time
  68. t, err := e.valueToTime(value)
  69. if err != nil {
  70. return nil, fmt.Errorf("EXTRACT function time conversion error: %v", err)
  71. }
  72. var result int64
  73. switch strings.ToUpper(string(part)) {
  74. case string(PartYear):
  75. result = int64(t.Year())
  76. case string(PartMonth):
  77. result = int64(t.Month())
  78. case string(PartDay):
  79. result = int64(t.Day())
  80. case string(PartHour):
  81. result = int64(t.Hour())
  82. case string(PartMinute):
  83. result = int64(t.Minute())
  84. case string(PartSecond):
  85. result = int64(t.Second())
  86. case string(PartWeek):
  87. _, week := t.ISOWeek()
  88. result = int64(week)
  89. case string(PartDayOfYear):
  90. result = int64(t.YearDay())
  91. case string(PartDayOfWeek):
  92. result = int64(t.Weekday())
  93. case string(PartQuarter):
  94. month := t.Month()
  95. result = int64((month-1)/3 + 1)
  96. case string(PartEpoch):
  97. result = t.Unix()
  98. default:
  99. return nil, fmt.Errorf("unsupported date part: %s", part)
  100. }
  101. return &schema_pb.Value{
  102. Kind: &schema_pb.Value_Int64Value{Int64Value: result},
  103. }, nil
  104. }
  105. // ===============================
  106. // DATE_TRUNC FUNCTION
  107. // ===============================
  108. // DateTrunc truncates a date/time to the specified precision
  109. func (e *SQLEngine) DateTrunc(precision string, value *schema_pb.Value) (*schema_pb.Value, error) {
  110. if value == nil {
  111. return nil, fmt.Errorf("DATE_TRUNC function requires non-null value")
  112. }
  113. // Convert value to time
  114. t, err := e.valueToTime(value)
  115. if err != nil {
  116. return nil, fmt.Errorf("DATE_TRUNC function time conversion error: %v", err)
  117. }
  118. var truncated time.Time
  119. switch strings.ToLower(precision) {
  120. case "microsecond", "microseconds":
  121. // No truncation needed for microsecond precision
  122. truncated = t
  123. case "millisecond", "milliseconds":
  124. truncated = t.Truncate(time.Millisecond)
  125. case "second", "seconds":
  126. truncated = t.Truncate(time.Second)
  127. case "minute", "minutes":
  128. truncated = t.Truncate(time.Minute)
  129. case "hour", "hours":
  130. truncated = t.Truncate(time.Hour)
  131. case "day", "days":
  132. truncated = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
  133. case "week", "weeks":
  134. // Truncate to beginning of week (Monday)
  135. days := int(t.Weekday())
  136. if days == 0 { // Sunday = 0, adjust to make Monday = 0
  137. days = 6
  138. } else {
  139. days = days - 1
  140. }
  141. truncated = time.Date(t.Year(), t.Month(), t.Day()-days, 0, 0, 0, 0, t.Location())
  142. case "month", "months":
  143. truncated = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
  144. case "quarter", "quarters":
  145. month := t.Month()
  146. quarterMonth := ((int(month)-1)/3)*3 + 1
  147. truncated = time.Date(t.Year(), time.Month(quarterMonth), 1, 0, 0, 0, 0, t.Location())
  148. case "year", "years":
  149. truncated = time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
  150. case "decade", "decades":
  151. year := (t.Year() / 10) * 10
  152. truncated = time.Date(year, 1, 1, 0, 0, 0, 0, t.Location())
  153. case "century", "centuries":
  154. year := ((t.Year()-1)/100)*100 + 1
  155. truncated = time.Date(year, 1, 1, 0, 0, 0, 0, t.Location())
  156. case "millennium", "millennia":
  157. year := ((t.Year()-1)/1000)*1000 + 1
  158. truncated = time.Date(year, 1, 1, 0, 0, 0, 0, t.Location())
  159. default:
  160. return nil, fmt.Errorf("unsupported date truncation precision: %s", precision)
  161. }
  162. // Return as TimestampValue
  163. return &schema_pb.Value{
  164. Kind: &schema_pb.Value_TimestampValue{
  165. TimestampValue: &schema_pb.TimestampValue{
  166. TimestampMicros: truncated.UnixMicro(),
  167. },
  168. },
  169. }, nil
  170. }