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 }