276 lines
6.9 KiB
Go
276 lines
6.9 KiB
Go
package engine
|
||
|
||
import (
|
||
"time"
|
||
)
|
||
|
||
// ========== 日期表达式操作符 ==========
|
||
|
||
// year 年份
|
||
func (e *AggregationEngine) year(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Year()
|
||
}
|
||
|
||
// month 月份 (1-12)
|
||
func (e *AggregationEngine) month(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return int(t.Month())
|
||
}
|
||
|
||
// dayOfMonth 日期 (1-31)
|
||
func (e *AggregationEngine) dayOfMonth(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Day()
|
||
}
|
||
|
||
// dayOfWeek 星期几 (0-6, 0 表示周日)
|
||
func (e *AggregationEngine) dayOfWeek(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return int(t.Weekday())
|
||
}
|
||
|
||
// hour 小时 (0-23)
|
||
func (e *AggregationEngine) hour(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Hour()
|
||
}
|
||
|
||
// minute 分钟 (0-59)
|
||
func (e *AggregationEngine) minute(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Minute()
|
||
}
|
||
|
||
// second 秒 (0-59)
|
||
func (e *AggregationEngine) second(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Second()
|
||
}
|
||
|
||
// millisecond 毫秒 (0-999)
|
||
func (e *AggregationEngine) millisecond(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.Nanosecond() / 1e6
|
||
}
|
||
|
||
// dateToString 日期格式化
|
||
func (e *AggregationEngine) dateToString(operand interface{}, data map[string]interface{}) string {
|
||
spec, ok := operand.(map[string]interface{})
|
||
if !ok {
|
||
return ""
|
||
}
|
||
|
||
dateVal := e.evaluateExpression(data, spec["date"])
|
||
t := e.toTime(dateVal)
|
||
|
||
format, _ := spec["format"].(string)
|
||
if format == "" {
|
||
format = "%Y-%m-%dT%H:%M:%SZ"
|
||
}
|
||
|
||
// MongoDB 格式转 Go 格式
|
||
goFormat := mongoDateFormatToGo(format)
|
||
return t.Format(goFormat)
|
||
}
|
||
|
||
// now 当前时间
|
||
func (e *AggregationEngine) now() time.Time {
|
||
return time.Now().UTC()
|
||
}
|
||
|
||
// toDate 转换为日期
|
||
func (e *AggregationEngine) toDate(operand interface{}, data map[string]interface{}) time.Time {
|
||
val := e.evaluateExpression(data, operand)
|
||
return e.toTime(val)
|
||
}
|
||
|
||
// dateAdd 日期相加
|
||
func (e *AggregationEngine) dateAdd(operand interface{}, data map[string]interface{}) time.Time {
|
||
spec, ok := operand.(map[string]interface{})
|
||
if !ok {
|
||
return time.Time{}
|
||
}
|
||
|
||
startDate := e.toTime(e.evaluateExpression(data, spec["startDate"]))
|
||
unit, _ := spec["unit"].(string)
|
||
amount := int(toFloat64(spec["amount"]))
|
||
|
||
switch unit {
|
||
case "year":
|
||
return startDate.AddDate(amount, 0, 0)
|
||
case "month":
|
||
return startDate.AddDate(0, amount, 0)
|
||
case "week":
|
||
return startDate.AddDate(0, 0, amount*7)
|
||
case "day":
|
||
return startDate.AddDate(0, 0, amount)
|
||
case "hour":
|
||
return startDate.Add(time.Duration(amount) * time.Hour)
|
||
case "minute":
|
||
return startDate.Add(time.Duration(amount) * time.Minute)
|
||
case "second":
|
||
return startDate.Add(time.Duration(amount) * time.Second)
|
||
default:
|
||
return startDate
|
||
}
|
||
}
|
||
|
||
// dateDiff 日期差值
|
||
func (e *AggregationEngine) dateDiff(operand interface{}, data map[string]interface{}) int64 {
|
||
spec, ok := operand.(map[string]interface{})
|
||
if !ok {
|
||
return 0
|
||
}
|
||
|
||
startDate := e.toTime(e.evaluateExpression(data, spec["startDate"]))
|
||
endDate := e.toTime(e.evaluateExpression(data, spec["endDate"]))
|
||
unit, _ := spec["unit"].(string)
|
||
|
||
switch unit {
|
||
case "year":
|
||
return int64(endDate.Year() - startDate.Year())
|
||
case "month":
|
||
months := (endDate.Year()-startDate.Year())*12 + int(endDate.Month()) - int(startDate.Month())
|
||
return int64(months)
|
||
case "week":
|
||
diff := endDate.Sub(startDate)
|
||
return int64(diff.Hours() / (24 * 7))
|
||
case "day":
|
||
diff := endDate.Sub(startDate)
|
||
return int64(diff.Hours() / 24)
|
||
case "hour":
|
||
diff := endDate.Sub(startDate)
|
||
return int64(diff.Hours())
|
||
case "minute":
|
||
diff := endDate.Sub(startDate)
|
||
return int64(diff.Minutes())
|
||
case "second":
|
||
diff := endDate.Sub(startDate)
|
||
return int64(diff.Seconds())
|
||
default:
|
||
return 0
|
||
}
|
||
}
|
||
|
||
// toTime 将值转换为 time.Time
|
||
func (e *AggregationEngine) toTime(value interface{}) time.Time {
|
||
switch v := value.(type) {
|
||
case time.Time:
|
||
return v
|
||
case string:
|
||
// 尝试解析 ISO 8601 格式
|
||
if t, err := time.Parse(time.RFC3339, v); err == nil {
|
||
return t
|
||
}
|
||
// 尝试其他常见格式
|
||
formats := []string{
|
||
"2006-01-02",
|
||
"2006-01-02 15:04:05",
|
||
"2006/01/02",
|
||
"01/02/2006",
|
||
}
|
||
for _, format := range formats {
|
||
if t, err := time.Parse(format, v); err == nil {
|
||
return t
|
||
}
|
||
}
|
||
case int64:
|
||
// 假设是毫秒时间戳
|
||
return time.UnixMilli(v)
|
||
case float64:
|
||
// 假设是毫秒时间戳
|
||
return time.UnixMilli(int64(v))
|
||
}
|
||
return time.Now()
|
||
}
|
||
|
||
// mongoDateFormatToGo MongoDB 日期格式转 Go 格式
|
||
func mongoDateFormatToGo(mongoFormat string) string {
|
||
replacements := map[string]string{
|
||
"%Y": "2006",
|
||
"%y": "06",
|
||
"%m": "01",
|
||
"%d": "02",
|
||
"%H": "15",
|
||
"%M": "04",
|
||
"%S": "05",
|
||
"%L": "000", // 毫秒
|
||
"%z": "-0700",
|
||
"%Z": "MST",
|
||
"%A": "Monday",
|
||
"%a": "Mon",
|
||
"%B": "January",
|
||
"%b": "Jan",
|
||
"%j": "002", // 一年中的第几天
|
||
"%U": "", // 周数(不支持)
|
||
"%W": "", // 周数(不支持)
|
||
"%w": "", // 星期几(不支持)
|
||
}
|
||
|
||
result := mongoFormat
|
||
for mongo, goFmt := range replacements {
|
||
result = replaceAllSubstrings(result, mongo, goFmt)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// replaceAllSubstrings 替换所有子串
|
||
func replaceAllSubstrings(s, old, new string) string {
|
||
result := ""
|
||
for {
|
||
i := indexOf(s, old)
|
||
if i == -1 {
|
||
result += s
|
||
break
|
||
}
|
||
result += s[:i] + new
|
||
s = s[i+len(old):]
|
||
}
|
||
return result
|
||
}
|
||
|
||
// indexOf 查找子串位置
|
||
func indexOf(s, substr string) int {
|
||
for i := 0; i <= len(s)-len(substr); i++ {
|
||
if s[i:i+len(substr)] == substr {
|
||
return i
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
|
||
// isoWeek ISO 周数
|
||
func (e *AggregationEngine) isoWeek(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
_, week := t.ISOWeek()
|
||
return week
|
||
}
|
||
|
||
// isoWeekYear ISO 周年
|
||
func (e *AggregationEngine) isoWeekYear(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
year, _ := t.ISOWeek()
|
||
return year
|
||
}
|
||
|
||
// dayOfYear 一年中的第几天
|
||
func (e *AggregationEngine) dayOfYear(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return t.YearDay()
|
||
}
|
||
|
||
// week 一年中的第几周
|
||
func (e *AggregationEngine) week(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
_, week := t.ISOWeek()
|
||
return week
|
||
}
|
||
|
||
// isoDayOfWeek ISO 星期几(1-7)
|
||
func (e *AggregationEngine) isoDayOfWeek(operand interface{}, data map[string]interface{}) int {
|
||
t := e.toTime(e.evaluateExpression(data, operand))
|
||
return int(t.Weekday()) + 1
|
||
}
|