gomog/internal/engine/date_ops.go

276 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}