gomog/internal/engine/date_ops.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
}