270 lines
6.7 KiB
Go
270 lines
6.7 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
|
|
}
|