x
This commit is contained in:
636
pkg/util/time.go
Normal file
636
pkg/util/time.go
Normal file
@@ -0,0 +1,636 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var zoneStr = time.Now().Format("-0700")
|
||||
|
||||
// 时间粒度常量
|
||||
type TimeGranularity int
|
||||
|
||||
const (
|
||||
GranularityUnknown TimeGranularity = iota // 未知粒度
|
||||
GranularitySecond // 精确到秒
|
||||
GranularityMinute // 精确到分钟
|
||||
GranularityHour // 精确到小时
|
||||
GranularityDay // 精确到天
|
||||
GranularityMonth // 精确到月
|
||||
GranularityQuarter // 精确到季度
|
||||
GranularityYear // 精确到年
|
||||
)
|
||||
|
||||
// timeOf 内部函数,解析各种格式的时间点,并返回时间粒度
|
||||
// 支持以下格式:
|
||||
// 1. 时间戳(秒): 1609459200 (GranularitySecond)
|
||||
// 2. 标准日期: 20060102, 2006-01-02 (GranularityDay)
|
||||
// 3. 带时间的日期: 20060102/15:04, 2006-01-02/15:04 (GranularityMinute)
|
||||
// 4. 完整时间: 20060102150405 (GranularitySecond)
|
||||
// 5. RFC3339: 2006-01-02T15:04:05Z07:00 (GranularitySecond)
|
||||
// 6. 相对时间: 5h-ago, 3d-ago, 1w-ago, 1m-ago, 1y-ago (根据单位确定粒度)
|
||||
// 7. 自然语言: now (GranularitySecond), today, yesterday (GranularityDay)
|
||||
// 8. 年份: 2006 (GranularityYear)
|
||||
// 9. 月份: 200601, 2006-01 (GranularityMonth)
|
||||
// 10. 季度: 2006Q1, 2006Q2, 2006Q3, 2006Q4 (GranularityQuarter)
|
||||
// 11. 年月日时分: 200601021504 (GranularityMinute)
|
||||
func timeOf(str string) (t time.Time, g TimeGranularity, ok bool) {
|
||||
if str == "" {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
// 处理自然语言时间
|
||||
switch strings.ToLower(str) {
|
||||
case "now":
|
||||
return time.Now(), GranularitySecond, true
|
||||
case "today":
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), GranularityDay, true
|
||||
case "yesterday":
|
||||
now := time.Now().AddDate(0, 0, -1)
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), GranularityDay, true
|
||||
case "this-week":
|
||||
now := time.Now()
|
||||
weekday := int(now.Weekday())
|
||||
if weekday == 0 { // 周日
|
||||
weekday = 7
|
||||
}
|
||||
// 本周一
|
||||
monday := now.AddDate(0, 0, -(weekday - 1))
|
||||
return time.Date(monday.Year(), monday.Month(), monday.Day(), 0, 0, 0, 0, now.Location()), GranularityDay, true
|
||||
case "last-week":
|
||||
now := time.Now()
|
||||
weekday := int(now.Weekday())
|
||||
if weekday == 0 { // 周日
|
||||
weekday = 7
|
||||
}
|
||||
// 上周一
|
||||
lastMonday := now.AddDate(0, 0, -(weekday-1)-7)
|
||||
return time.Date(lastMonday.Year(), lastMonday.Month(), lastMonday.Day(), 0, 0, 0, 0, now.Location()), GranularityDay, true
|
||||
case "this-month":
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()), GranularityMonth, true
|
||||
case "last-month":
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), now.Month()-1, 1, 0, 0, 0, 0, now.Location()), GranularityMonth, true
|
||||
case "this-year":
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()), GranularityYear, true
|
||||
case "last-year":
|
||||
now := time.Now()
|
||||
return time.Date(now.Year()-1, 1, 1, 0, 0, 0, 0, now.Location()), GranularityYear, true
|
||||
case "all":
|
||||
// 返回零值时间
|
||||
return time.Time{}, GranularityYear, true
|
||||
}
|
||||
|
||||
// 处理相对时间: 5h-ago, 3d-ago, 1w-ago, 1m-ago, 1y-ago
|
||||
if strings.HasSuffix(str, "-ago") {
|
||||
str = strings.TrimSuffix(str, "-ago")
|
||||
|
||||
// 特殊处理 0d-ago 为当天开始
|
||||
if str == "0d" {
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), GranularityDay, true
|
||||
}
|
||||
|
||||
// 解析数字和单位
|
||||
re := regexp.MustCompile(`^(\d+)([hdwmy])$`)
|
||||
matches := re.FindStringSubmatch(str)
|
||||
if len(matches) == 3 {
|
||||
num, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 确保数字是正数
|
||||
if num <= 0 {
|
||||
// 对于0d-ago已经特殊处理,其他0或负数都是无效的
|
||||
if num == 0 && matches[2] != "d" {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var resultTime time.Time
|
||||
var granularity TimeGranularity
|
||||
|
||||
switch matches[2] {
|
||||
case "h": // 小时
|
||||
resultTime = now.Add(-time.Duration(num) * time.Hour)
|
||||
granularity = GranularityHour
|
||||
case "d": // 天
|
||||
resultTime = now.AddDate(0, 0, -num)
|
||||
granularity = GranularityDay
|
||||
case "w": // 周
|
||||
resultTime = now.AddDate(0, 0, -num*7)
|
||||
granularity = GranularityDay
|
||||
case "m": // 月
|
||||
resultTime = now.AddDate(0, -num, 0)
|
||||
granularity = GranularityMonth
|
||||
case "y": // 年
|
||||
resultTime = now.AddDate(-num, 0, 0)
|
||||
granularity = GranularityYear
|
||||
default:
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
return resultTime, granularity, true
|
||||
}
|
||||
|
||||
// 尝试标准 duration 解析
|
||||
dur, err := time.ParseDuration(str)
|
||||
if err == nil {
|
||||
// 根据duration单位确定粒度
|
||||
hours := dur.Hours()
|
||||
if hours < 1 {
|
||||
return time.Now().Add(-dur), GranularitySecond, true
|
||||
} else if hours < 24 {
|
||||
return time.Now().Add(-dur), GranularityHour, true
|
||||
} else {
|
||||
return time.Now().Add(-dur), GranularityDay, true
|
||||
}
|
||||
}
|
||||
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 处理季度: 2006Q1, 2006Q2, 2006Q3, 2006Q4
|
||||
if matched, _ := regexp.MatchString(`^\d{4}Q[1-4]$`, str); matched {
|
||||
re := regexp.MustCompile(`^(\d{4})Q([1-4])$`)
|
||||
matches := re.FindStringSubmatch(str)
|
||||
if len(matches) == 3 {
|
||||
year, _ := strconv.Atoi(matches[1])
|
||||
quarter, _ := strconv.Atoi(matches[2])
|
||||
|
||||
// 验证年份范围
|
||||
if year < 1970 || year > 9999 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 计算季度的开始月份
|
||||
startMonth := time.Month((quarter-1)*3 + 1)
|
||||
|
||||
return time.Date(year, startMonth, 1, 0, 0, 0, 0, time.Local), GranularityQuarter, true
|
||||
}
|
||||
}
|
||||
|
||||
// 处理年份: 2006
|
||||
if len(str) == 4 && isDigitsOnly(str) {
|
||||
year, err := strconv.Atoi(str)
|
||||
if err == nil && year >= 1970 && year <= 9999 {
|
||||
return time.Date(year, 1, 1, 0, 0, 0, 0, time.Local), GranularityYear, true
|
||||
}
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 处理月份: 200601 或 2006-01
|
||||
if (len(str) == 6 && isDigitsOnly(str)) || (len(str) == 7 && strings.Count(str, "-") == 1) {
|
||||
var year, month int
|
||||
var err error
|
||||
|
||||
if len(str) == 6 && isDigitsOnly(str) {
|
||||
year, err = strconv.Atoi(str[0:4])
|
||||
if err != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
month, err = strconv.Atoi(str[4:6])
|
||||
if err != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
} else { // 2006-01
|
||||
parts := strings.Split(str, "-")
|
||||
if len(parts) != 2 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
year, err = strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
month, err = strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
}
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
return time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.Local), GranularityMonth, true
|
||||
}
|
||||
|
||||
// 处理日期格式: 20060102 或 2006-01-02
|
||||
if len(str) == 8 && isDigitsOnly(str) {
|
||||
// 验证年月日
|
||||
year, _ := strconv.Atoi(str[0:4])
|
||||
month, _ := strconv.Atoi(str[4:6])
|
||||
day, _ := strconv.Atoi(str[6:8])
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 进一步验证日期是否有效
|
||||
if !isValidDate(year, month, day) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 直接构造时间
|
||||
result := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
|
||||
return result, GranularityDay, true
|
||||
} else if len(str) == 10 && strings.Count(str, "-") == 2 {
|
||||
// 验证年月日
|
||||
parts := strings.Split(str, "-")
|
||||
if len(parts) != 3 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
year, err1 := strconv.Atoi(parts[0])
|
||||
month, err2 := strconv.Atoi(parts[1])
|
||||
day, err3 := strconv.Atoi(parts[2])
|
||||
|
||||
if err1 != nil || err2 != nil || err3 != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 进一步验证日期是否有效
|
||||
if !isValidDate(year, month, day) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 直接构造时间
|
||||
result := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
|
||||
return result, GranularityDay, true
|
||||
}
|
||||
|
||||
// 处理年月日时分: 200601021504
|
||||
if len(str) == 12 && isDigitsOnly(str) {
|
||||
year, _ := strconv.Atoi(str[0:4])
|
||||
month, _ := strconv.Atoi(str[4:6])
|
||||
day, _ := strconv.Atoi(str[6:8])
|
||||
hour, _ := strconv.Atoi(str[8:10])
|
||||
minute, _ := strconv.Atoi(str[10:12])
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hour < 0 || hour > 23 || minute < 0 || minute > 59 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 进一步验证日期是否有效
|
||||
if !isValidDate(year, month, day) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 直接构造时间
|
||||
result := time.Date(year, time.Month(month), day, hour, minute, 0, 0, time.Local)
|
||||
return result, GranularityMinute, true
|
||||
}
|
||||
|
||||
// 处理带时间的日期: 20060102/15:04 或 2006-01-02/15:04
|
||||
if strings.Contains(str, "/") {
|
||||
parts := strings.Split(str, "/")
|
||||
if len(parts) != 2 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
datePart := parts[0]
|
||||
timePart := parts[1]
|
||||
|
||||
// 验证日期部分
|
||||
var year, month, day int
|
||||
var err1, err2, err3 error
|
||||
|
||||
if len(datePart) == 8 && isDigitsOnly(datePart) {
|
||||
year, err1 = strconv.Atoi(datePart[0:4])
|
||||
month, err2 = strconv.Atoi(datePart[4:6])
|
||||
day, err3 = strconv.Atoi(datePart[6:8])
|
||||
} else if len(datePart) == 10 && strings.Count(datePart, "-") == 2 {
|
||||
dateParts := strings.Split(datePart, "-")
|
||||
if len(dateParts) != 3 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
year, err1 = strconv.Atoi(dateParts[0])
|
||||
month, err2 = strconv.Atoi(dateParts[1])
|
||||
day, err3 = strconv.Atoi(dateParts[2])
|
||||
} else {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
if err1 != nil || err2 != nil || err3 != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 进一步验证日期是否有效
|
||||
if !isValidDate(year, month, day) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 验证时间部分
|
||||
if !regexp.MustCompile(`^\d{2}:\d{2}$`).MatchString(timePart) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
timeParts := strings.Split(timePart, ":")
|
||||
hour, err1 := strconv.Atoi(timeParts[0])
|
||||
minute, err2 := strconv.Atoi(timeParts[1])
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
if hour < 0 || hour > 23 || minute < 0 || minute > 59 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 直接构造时间
|
||||
result := time.Date(year, time.Month(month), day, hour, minute, 0, 0, time.Local)
|
||||
return result, GranularityMinute, true
|
||||
}
|
||||
|
||||
// 处理完整时间: 20060102150405
|
||||
if len(str) == 14 && isDigitsOnly(str) {
|
||||
year, _ := strconv.Atoi(str[0:4])
|
||||
month, _ := strconv.Atoi(str[4:6])
|
||||
day, _ := strconv.Atoi(str[6:8])
|
||||
hour, _ := strconv.Atoi(str[8:10])
|
||||
minute, _ := strconv.Atoi(str[10:12])
|
||||
second, _ := strconv.Atoi(str[12:14])
|
||||
|
||||
if year < 1970 || year > 9999 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59 {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 进一步验证日期是否有效
|
||||
if !isValidDate(year, month, day) {
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 直接构造时间
|
||||
result := time.Date(year, time.Month(month), day, hour, minute, second, 0, time.Local)
|
||||
return result, GranularitySecond, true
|
||||
}
|
||||
|
||||
// 处理时间戳(秒)
|
||||
if isDigitsOnly(str) {
|
||||
n, err := strconv.ParseInt(str, 10, 64)
|
||||
if err == nil {
|
||||
// 检查是否是合理的时间戳范围
|
||||
if n >= 1000000000 && n <= 253402300799 { // 2001年到2286年的秒级时间戳
|
||||
return time.Unix(n, 0), GranularitySecond, true
|
||||
}
|
||||
}
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// 处理 RFC3339: 2006-01-02T15:04:05Z07:00
|
||||
if strings.Contains(str, "T") && (strings.Contains(str, "Z") || strings.Contains(str, "+") || strings.Contains(str, "-")) {
|
||||
t, err := time.Parse(time.RFC3339, str)
|
||||
if err != nil {
|
||||
// 尝试不带秒的格式
|
||||
t, err = time.Parse("2006-01-02T15:04Z07:00", str)
|
||||
}
|
||||
if err == nil {
|
||||
return t, GranularitySecond, true
|
||||
}
|
||||
}
|
||||
|
||||
// 排除所有其他不支持的格式
|
||||
return time.Time{}, GranularityUnknown, false
|
||||
}
|
||||
|
||||
// TimeOf 解析各种格式的时间点
|
||||
// 支持以下格式:
|
||||
// 1. 时间戳(秒): 1609459200
|
||||
// 2. 标准日期: 20060102, 2006-01-02
|
||||
// 3. 带时间的日期: 20060102/15:04, 2006-01-02/15:04
|
||||
// 4. 完整时间: 20060102150405
|
||||
// 5. RFC3339: 2006-01-02T15:04:05Z07:00
|
||||
// 6. 相对时间: 5h-ago, 3d-ago, 1w-ago, 1m-ago, 1y-ago (小时、天、周、月、年)
|
||||
// 7. 自然语言: now, today, yesterday
|
||||
// 8. 年份: 2006
|
||||
// 9. 月份: 200601, 2006-01
|
||||
// 10. 季度: 2006Q1, 2006Q2, 2006Q3, 2006Q4
|
||||
// 11. 年月日时分: 200601021504
|
||||
func TimeOf(str string) (t time.Time, ok bool) {
|
||||
t, _, ok = timeOf(str)
|
||||
return
|
||||
}
|
||||
|
||||
// TimeRangeOf 解析各种格式的时间范围
|
||||
// 支持以下格式:
|
||||
// 1. 单个时间点: 根据时间粒度确定合适的时间范围
|
||||
// - 精确到秒/分钟/小时: 扩展为当天范围
|
||||
// - 精确到天: 当天 00:00:00 ~ 23:59:59
|
||||
// - 精确到月: 当月第一天 ~ 最后一天
|
||||
// - 精确到季度: 季度第一天 ~ 最后一天
|
||||
// - 精确到年: 当年第一天 ~ 最后一天
|
||||
//
|
||||
// 2. 时间区间: 2006-01-01~2006-01-31, 2006-01-01,2006-01-31, 2006-01-01 to 2006-01-31
|
||||
// 3. 相对时间: last-7d, last-30d, last-3m, last-1y (最近7天、30天、3个月、1年)
|
||||
// 4. 特定时间段: today, yesterday, this-week, last-week, this-month, last-month, this-year, last-year
|
||||
// 5. all: 表示所有时间
|
||||
func TimeRangeOf(str string) (start, end time.Time, ok bool) {
|
||||
if str == "" {
|
||||
return time.Time{}, time.Time{}, false
|
||||
}
|
||||
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
// 处理 all 特殊情况
|
||||
if strings.ToLower(str) == "all" {
|
||||
start = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
end = time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC)
|
||||
return start, end, true
|
||||
}
|
||||
|
||||
// 处理相对时间范围: last-7d, last-30d, last-3m, last-1y
|
||||
if matched, _ := regexp.MatchString(`^last-\d+[dwmy]$`, str); matched {
|
||||
re := regexp.MustCompile(`^last-(\d+)([dwmy])$`)
|
||||
matches := re.FindStringSubmatch(str)
|
||||
if len(matches) == 3 {
|
||||
num, err := strconv.Atoi(matches[1])
|
||||
if err != nil || num <= 0 {
|
||||
return time.Time{}, time.Time{}, false
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
end = time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 999999999, now.Location())
|
||||
|
||||
switch matches[2] {
|
||||
case "d": // 天
|
||||
start = now.AddDate(0, 0, -num)
|
||||
start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location())
|
||||
return start, end, true
|
||||
case "w": // 周
|
||||
start = now.AddDate(0, 0, -num*7)
|
||||
start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location())
|
||||
return start, end, true
|
||||
case "m": // 月
|
||||
start = now.AddDate(0, -num, 0)
|
||||
start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location())
|
||||
return start, end, true
|
||||
case "y": // 年
|
||||
start = now.AddDate(-num, 0, 0)
|
||||
start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location())
|
||||
return start, end, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理时间区间: 2006-01-01~2006-01-31, 2006-01-01,2006-01-31, 2006-01-01 to 2006-01-31
|
||||
separators := []string{"~", ",", " to "}
|
||||
for _, sep := range separators {
|
||||
if strings.Contains(str, sep) {
|
||||
parts := strings.Split(str, sep)
|
||||
if len(parts) == 2 {
|
||||
startTime, startGran, startOk := timeOf(strings.TrimSpace(parts[0]))
|
||||
endTime, endGran, endOk := timeOf(strings.TrimSpace(parts[1]))
|
||||
|
||||
if startOk && endOk {
|
||||
// 根据粒度调整时间范围
|
||||
start = adjustStartTime(startTime, startGran)
|
||||
end = adjustEndTime(endTime, endGran)
|
||||
|
||||
// 确保开始时间早于结束时间
|
||||
if start.After(end) {
|
||||
// 正确交换开始和结束时间
|
||||
start, end = adjustStartTime(endTime, endGran), adjustEndTime(startTime, startGran)
|
||||
}
|
||||
|
||||
return start, end, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单个时间点,根据粒度确定合适的时间范围
|
||||
t, g, ok := timeOf(str)
|
||||
if ok {
|
||||
switch g {
|
||||
case GranularitySecond, GranularityMinute, GranularityHour:
|
||||
// 精确到秒/分钟/小时的时间点,扩展为当天范围
|
||||
start = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
end = time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityDay:
|
||||
// 精确到天的时间点
|
||||
start = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
end = time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityMonth:
|
||||
// 精确到月的时间点
|
||||
start = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
||||
end = time.Date(t.Year(), t.Month()+1, 0, 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityQuarter:
|
||||
// 精确到季度的时间点
|
||||
quarter := (t.Month()-1)/3 + 1
|
||||
startMonth := time.Month((int(quarter)-1)*3 + 1)
|
||||
endMonth := startMonth + 2
|
||||
start = time.Date(t.Year(), startMonth, 1, 0, 0, 0, 0, t.Location())
|
||||
end = time.Date(t.Year(), endMonth+1, 0, 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityYear:
|
||||
// 精确到年的时间点
|
||||
start = time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
|
||||
end = time.Date(t.Year(), 12, 31, 23, 59, 59, 999999999, t.Location())
|
||||
}
|
||||
return start, end, true
|
||||
}
|
||||
|
||||
return time.Time{}, time.Time{}, false
|
||||
}
|
||||
|
||||
// adjustStartTime 根据时间粒度调整开始时间
|
||||
func adjustStartTime(t time.Time, g TimeGranularity) time.Time {
|
||||
switch g {
|
||||
case GranularitySecond, GranularityMinute, GranularityHour:
|
||||
// 对于精确到秒/分钟/小时的时间,保持原样
|
||||
return t
|
||||
case GranularityDay:
|
||||
// 精确到天,设置为当天开始
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
case GranularityMonth:
|
||||
// 精确到月,设置为当月第一天
|
||||
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
||||
case GranularityQuarter:
|
||||
// 精确到季度,设置为季度第一天
|
||||
quarter := (t.Month()-1)/3 + 1
|
||||
startMonth := time.Month((int(quarter)-1)*3 + 1)
|
||||
return time.Date(t.Year(), startMonth, 1, 0, 0, 0, 0, t.Location())
|
||||
case GranularityYear:
|
||||
// 精确到年,设置为当年第一天
|
||||
return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
|
||||
default:
|
||||
// 未知粒度,默认为当天开始
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
}
|
||||
|
||||
// adjustEndTime 根据时间粒度调整结束时间
|
||||
func adjustEndTime(t time.Time, g TimeGranularity) time.Time {
|
||||
switch g {
|
||||
case GranularitySecond, GranularityMinute, GranularityHour:
|
||||
// 对于精确到秒/分钟/小时的时间,设置为当天结束
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityDay:
|
||||
// 精确到天,设置为当天结束
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityMonth:
|
||||
// 精确到月,设置为当月最后一天
|
||||
return time.Date(t.Year(), t.Month()+1, 0, 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityQuarter:
|
||||
// 精确到季度,设置为季度最后一天
|
||||
quarter := (t.Month()-1)/3 + 1
|
||||
startMonth := time.Month((int(quarter)-1)*3 + 1)
|
||||
endMonth := startMonth + 2
|
||||
return time.Date(t.Year(), endMonth+1, 0, 23, 59, 59, 999999999, t.Location())
|
||||
case GranularityYear:
|
||||
// 精确到年,设置为当年最后一天
|
||||
return time.Date(t.Year(), 12, 31, 23, 59, 59, 999999999, t.Location())
|
||||
default:
|
||||
// 未知粒度,默认为当天结束
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, t.Location())
|
||||
}
|
||||
}
|
||||
|
||||
// isDigitsOnly 检查字符串是否只包含数字
|
||||
func isDigitsOnly(s string) bool {
|
||||
for _, c := range s {
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(s) > 0
|
||||
}
|
||||
|
||||
// isValidDate 检查日期是否有效
|
||||
func isValidDate(year, month, day int) bool {
|
||||
// 检查月份的天数
|
||||
daysInMonth := 31
|
||||
|
||||
switch month {
|
||||
case 4, 6, 9, 11:
|
||||
daysInMonth = 30
|
||||
case 2:
|
||||
// 闰年判断
|
||||
if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
|
||||
daysInMonth = 29
|
||||
} else {
|
||||
daysInMonth = 28
|
||||
}
|
||||
}
|
||||
|
||||
return day <= daysInMonth
|
||||
}
|
||||
Reference in New Issue
Block a user