1005 lines
22 KiB
Go
1005 lines
22 KiB
Go
package util
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestTimeOf(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
input string
|
||
wantTime time.Time
|
||
wantOk bool
|
||
}{
|
||
// 空输入
|
||
{
|
||
name: "empty string",
|
||
input: "",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "whitespace only",
|
||
input: " ",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 自然语言时间
|
||
{
|
||
name: "now",
|
||
input: "now",
|
||
wantOk: true, // 不检查具体时间,因为会随运行时间变化
|
||
},
|
||
{
|
||
name: "today",
|
||
input: "today",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "yesterday",
|
||
input: "yesterday",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-week",
|
||
input: "this-week",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-week",
|
||
input: "last-week",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-month",
|
||
input: "this-month",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-month",
|
||
input: "last-month",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-year",
|
||
input: "this-year",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-year",
|
||
input: "last-year",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "all",
|
||
input: "all",
|
||
wantOk: true,
|
||
},
|
||
|
||
// 相对时间
|
||
{
|
||
name: "1h-ago",
|
||
input: "1h-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "24h-ago",
|
||
input: "24h-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1d-ago",
|
||
input: "1d-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "7d-ago",
|
||
input: "7d-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1w-ago",
|
||
input: "1w-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1m-ago",
|
||
input: "1m-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1y-ago",
|
||
input: "1y-ago",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "invalid-ago",
|
||
input: "invalid-ago",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "0d-ago",
|
||
input: "0d-ago",
|
||
wantOk: true, // 应该是今天
|
||
},
|
||
{
|
||
name: "-1d-ago",
|
||
input: "-1d-ago",
|
||
wantTime: time.Time{},
|
||
wantOk: false, // 负数应该无效
|
||
},
|
||
|
||
// 季度
|
||
{
|
||
name: "2020Q1",
|
||
input: "2020Q1",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020Q2",
|
||
input: "2020Q2",
|
||
wantTime: time.Date(2020, 4, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020Q3",
|
||
input: "2020Q3",
|
||
wantTime: time.Date(2020, 7, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020Q4",
|
||
input: "2020Q4",
|
||
wantTime: time.Date(2020, 10, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020Q5", // 无效季度
|
||
input: "2020Q5",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "1969Q1", // 早于1970年
|
||
input: "1969Q1",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "10000Q1", // 超过9999年
|
||
input: "10000Q1",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 年份
|
||
{
|
||
name: "2020",
|
||
input: "2020",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1970", // 最早有效年份
|
||
input: "1970",
|
||
wantTime: time.Date(1970, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "9999", // 最晚有效年份
|
||
input: "9999",
|
||
wantTime: time.Date(9999, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1969", // 早于1970年
|
||
input: "1969",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "10000", // 超过9999年
|
||
input: "10000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "202", // 不是4位数字
|
||
input: "202",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 月份
|
||
{
|
||
name: "202001",
|
||
input: "202001",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "202012",
|
||
input: "202012",
|
||
wantTime: time.Date(2020, 12, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01",
|
||
input: "2020-01",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-12",
|
||
input: "2020-12",
|
||
wantTime: time.Date(2020, 12, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "202013", // 无效月份
|
||
input: "202013",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-13", // 无效月份
|
||
input: "2020-13",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-00", // 无效月份
|
||
input: "2020-00",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "196912", // 早于1970年
|
||
input: "196912",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "1969-12", // 早于1970年
|
||
input: "1969-12",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 日期格式
|
||
{
|
||
name: "20200101",
|
||
input: "20200101",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20201231",
|
||
input: "20201231",
|
||
wantTime: time.Date(2020, 12, 31, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01",
|
||
input: "2020-01-01",
|
||
wantTime: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-12-31",
|
||
input: "2020-12-31",
|
||
wantTime: time.Date(2020, 12, 31, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200229", // 闰年2月29日
|
||
input: "20200229",
|
||
wantTime: time.Date(2020, 2, 29, 0, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20190229", // 非闰年2月29日
|
||
input: "20190229",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200230", // 无效日期
|
||
input: "20200230",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-02-30", // 无效日期
|
||
input: "2020-02-30",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200000", // 无效日期
|
||
input: "20200000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200132", // 无效日期
|
||
input: "20200132",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "19691231", // 早于1970年
|
||
input: "19691231",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "1969-12-31", // 早于1970年
|
||
input: "1969-12-31",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 带时间的日期
|
||
{
|
||
name: "20200101/12:34",
|
||
input: "20200101/12:34",
|
||
wantTime: time.Date(2020, 1, 1, 12, 34, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01/12:34",
|
||
input: "2020-01-01/12:34",
|
||
wantTime: time.Date(2020, 1, 1, 12, 34, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200101/24:00", // 无效时间
|
||
input: "20200101/24:00",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200101/12:60", // 无效时间
|
||
input: "20200101/12:60",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200101/12:34:56", // 不支持的格式
|
||
input: "20200101/12:34:56",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200101/12-34", // 不支持的格式
|
||
input: "20200101/12-34",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "19691231/12:34", // 早于1970年
|
||
input: "19691231/12:34",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 完整时间
|
||
{
|
||
name: "20200101120000",
|
||
input: "20200101120000",
|
||
wantTime: time.Date(2020, 1, 1, 12, 0, 0, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20201231235959",
|
||
input: "20201231235959",
|
||
wantTime: time.Date(2020, 12, 31, 23, 59, 59, 0, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200101240000", // 无效时间
|
||
input: "20200101240000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200101126000", // 无效时间
|
||
input: "20200101126000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20200101120060", // 无效时间
|
||
input: "20200101120060",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020010112000", // 长度不对
|
||
input: "2020010112000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "202001011200000", // 长度不对
|
||
input: "202001011200000",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "19691231235959", // 早于1970年
|
||
input: "19691231235959",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 时间戳(秒)
|
||
{
|
||
name: "1577836800", // 2020-01-01 00:00:00
|
||
input: "1577836800",
|
||
wantTime: time.Unix(1577836800, 0),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1609459199", // 2020-12-31 23:59:59
|
||
input: "1609459199",
|
||
wantTime: time.Unix(1609459199, 0),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "999999999", // 小于1000000000
|
||
input: "999999999",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "253402300800", // 大于253402300799
|
||
input: "253402300800",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "abc", // 非数字
|
||
input: "abc",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// RFC3339
|
||
{
|
||
name: "2020-01-01T12:00:00Z",
|
||
input: "2020-01-01T12:00:00Z",
|
||
wantTime: time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01T12:00:00+08:00",
|
||
input: "2020-01-01T12:00:00+08:00",
|
||
wantTime: time.Date(2020, 1, 1, 12, 0, 0, 0, time.FixedZone("", 8*60*60)),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01T12:00Z",
|
||
input: "2020-01-01T12:00Z",
|
||
wantTime: time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01T12:00:00", // 缺少时区
|
||
input: "2020-01-01T12:00:00",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-01-01 12:00:00Z", // 格式不对
|
||
input: "2020-01-01 12:00:00Z",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 边界情况和特殊情况
|
||
{
|
||
name: "99999", // 不是有效的时间戳
|
||
input: "99999",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020/01/01", // 不支持的格式
|
||
input: "2020/01/01",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "01/01/2020", // 不支持的格式
|
||
input: "01/01/2020",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-1-1", // 不支持的格式
|
||
input: "2020-1-1",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "20201-01-01", // 不支持的格式
|
||
input: "20201-01-01",
|
||
wantTime: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
gotTime, gotOk := TimeOf(tt.input)
|
||
|
||
if tt.wantOk != gotOk {
|
||
t.Errorf("TimeOf() ok = %v, want %v", gotOk, tt.wantOk)
|
||
return
|
||
}
|
||
|
||
if !tt.wantOk {
|
||
return // 不需要检查时间值
|
||
}
|
||
|
||
if tt.input == "now" || strings.HasSuffix(tt.input, "-ago") ||
|
||
tt.input == "today" || tt.input == "yesterday" ||
|
||
tt.input == "this-week" || tt.input == "last-week" ||
|
||
tt.input == "this-month" || tt.input == "last-month" ||
|
||
tt.input == "this-year" || tt.input == "last-year" {
|
||
// 对于相对时间,不检查具体值
|
||
return
|
||
}
|
||
|
||
if !tt.wantTime.Equal(gotTime) {
|
||
t.Errorf("TimeOf() = %v, want %v", gotTime, tt.wantTime)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestTimeRangeOf(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
input string
|
||
wantStart time.Time
|
||
wantEnd time.Time
|
||
wantOk bool
|
||
}{
|
||
// 空输入
|
||
{
|
||
name: "empty string",
|
||
input: "",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "whitespace only",
|
||
input: " ",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// all 特殊情况
|
||
{
|
||
name: "all",
|
||
input: "all",
|
||
wantStart: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
|
||
wantEnd: time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "ALL (uppercase)",
|
||
input: "ALL",
|
||
wantStart: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
|
||
wantEnd: time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC),
|
||
wantOk: true,
|
||
},
|
||
|
||
// 相对时间范围
|
||
{
|
||
name: "last-1d",
|
||
input: "last-1d",
|
||
wantOk: true, // 不检查具体时间,因为会随运行时间变化
|
||
},
|
||
{
|
||
name: "last-7d",
|
||
input: "last-7d",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-30d",
|
||
input: "last-30d",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-1w",
|
||
input: "last-1w",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-4w",
|
||
input: "last-4w",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-1m",
|
||
input: "last-1m",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-3m",
|
||
input: "last-3m",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-1y",
|
||
input: "last-1y",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-0d", // 无效输入
|
||
input: "last-0d",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "last--1d", // 无效输入
|
||
input: "last--1d",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "last-1x", // 无效输入
|
||
input: "last-1x",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 时间区间
|
||
{
|
||
name: "2020-01-01~2020-01-31",
|
||
input: "2020-01-01~2020-01-31",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01,2020-01-31",
|
||
input: "2020-01-01,2020-01-31",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01 to 2020-01-31",
|
||
input: "2020-01-01 to 2020-01-31",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200101~20200131",
|
||
input: "20200101~20200131",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-31~2020-01-01", // 开始时间晚于结束时间
|
||
input: "2020-01-31~2020-01-01",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true, // 应该自动交换
|
||
},
|
||
{
|
||
name: "2020-01-01~invalid", // 结束时间无效
|
||
input: "2020-01-01~invalid",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "invalid~2020-01-31", // 开始时间无效
|
||
input: "invalid~2020-01-31",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-01-01~2020-02-30", // 结束时间无效日期
|
||
input: "2020-01-01~2020-02-30",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-01-01~", // 缺少结束时间
|
||
input: "2020-01-01~",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "~2020-01-31", // 缺少开始时间
|
||
input: "~2020-01-31",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
|
||
// 单个时间点,根据粒度确定范围
|
||
{
|
||
name: "2020-01-01", // 精确到天
|
||
input: "2020-01-01",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200101", // 精确到天
|
||
input: "20200101",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01", // 精确到月
|
||
input: "2020-01",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "202001", // 精确到月
|
||
input: "202001",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020Q1", // 精确到季度
|
||
input: "2020Q1",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 3, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020", // 精确到年
|
||
input: "2020",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 12, 31, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01/12:34", // 精确到分钟
|
||
input: "2020-01-01/12:34",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "20200101120000", // 精确到秒
|
||
input: "20200101120000",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "1577836800", // 时间戳 2020-01-01 00:00:00
|
||
input: "1577836800",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2020-01-01T12:00:00Z", // RFC3339
|
||
input: "2020-01-01T12:00:00Z",
|
||
wantStart: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
|
||
wantEnd: time.Date(2020, 1, 1, 23, 59, 59, 999999999, time.UTC),
|
||
wantOk: true,
|
||
},
|
||
|
||
// 自然语言时间
|
||
{
|
||
name: "today",
|
||
input: "today",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "yesterday",
|
||
input: "yesterday",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-week",
|
||
input: "this-week",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-week",
|
||
input: "last-week",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-month",
|
||
input: "this-month",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-month",
|
||
input: "last-month",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "this-year",
|
||
input: "this-year",
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "last-year",
|
||
input: "last-year",
|
||
wantOk: true,
|
||
},
|
||
|
||
// 边界情况和特殊情况
|
||
{
|
||
name: "invalid", // 无效输入
|
||
input: "invalid",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-02-29", // 闰年2月29日
|
||
input: "2020-02-29",
|
||
wantStart: time.Date(2020, 2, 29, 0, 0, 0, 0, time.Local),
|
||
wantEnd: time.Date(2020, 2, 29, 23, 59, 59, 999999999, time.Local),
|
||
wantOk: true,
|
||
},
|
||
{
|
||
name: "2019-02-29", // 非闰年2月29日
|
||
input: "2019-02-29",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
{
|
||
name: "2020-04-31", // 无效日期
|
||
input: "2020-04-31",
|
||
wantStart: time.Time{},
|
||
wantEnd: time.Time{},
|
||
wantOk: false,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
gotStart, gotEnd, gotOk := TimeRangeOf(tt.input)
|
||
|
||
if tt.wantOk != gotOk {
|
||
t.Errorf("TimeRangeOf() ok = %v, want %v", gotOk, tt.wantOk)
|
||
return
|
||
}
|
||
|
||
if !tt.wantOk {
|
||
return // 不需要检查时间值
|
||
}
|
||
|
||
if tt.input == "today" || tt.input == "yesterday" ||
|
||
tt.input == "this-week" || tt.input == "last-week" ||
|
||
tt.input == "this-month" || tt.input == "last-month" ||
|
||
tt.input == "this-year" || tt.input == "last-year" ||
|
||
strings.HasPrefix(tt.input, "last-") {
|
||
// 对于相对时间,不检查具体值
|
||
return
|
||
}
|
||
|
||
if !tt.wantStart.Equal(gotStart) {
|
||
t.Errorf("TimeRangeOf() start = %v, want %v", gotStart, tt.wantStart)
|
||
}
|
||
|
||
if !tt.wantEnd.Equal(gotEnd) {
|
||
t.Errorf("TimeRangeOf() end = %v, want %v", gotEnd, tt.wantEnd)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// 测试边界情况
|
||
func TestTimeOfEdgeCases(t *testing.T) {
|
||
// 测试非常长的数字字符串
|
||
longDigits := "99999999999999999999999999999999999999"
|
||
_, ok := TimeOf(longDigits)
|
||
if ok {
|
||
t.Errorf("TimeOf(%s) should return false for very long digit string", longDigits)
|
||
}
|
||
|
||
// 测试非常长的字符串
|
||
longString := strings.Repeat("a", 10000)
|
||
_, ok = TimeOf(longString)
|
||
if ok {
|
||
t.Errorf("TimeOf(%s) should return false for very long string", "very_long_string")
|
||
}
|
||
|
||
// 测试特殊字符
|
||
specialChars := "!@#$%^&*()"
|
||
_, ok = TimeOf(specialChars)
|
||
if ok {
|
||
t.Errorf("TimeOf(%s) should return false for special characters", specialChars)
|
||
}
|
||
|
||
// 测试SQL注入类字符串
|
||
sqlInjection := "2020-01-01' OR '1'='1"
|
||
_, ok = TimeOf(sqlInjection)
|
||
if ok {
|
||
t.Errorf("TimeOf(%s) should return false for SQL injection attempt", sqlInjection)
|
||
}
|
||
}
|
||
|
||
// 测试时区处理
|
||
func TestTimeOfTimezones(t *testing.T) {
|
||
// RFC3339格式的时区处理
|
||
utcTime, ok := TimeOf("2020-01-01T12:00:00Z")
|
||
if !ok {
|
||
t.Fatalf("TimeOf(2020-01-01T12:00:00Z) failed")
|
||
}
|
||
|
||
estTime, ok := TimeOf("2020-01-01T12:00:00-05:00")
|
||
if !ok {
|
||
t.Fatalf("TimeOf(2020-01-01T12:00:00-05:00) failed")
|
||
}
|
||
|
||
// UTC比EST时区快5小时,所以相同时钟时间的UTC应该比EST早5小时
|
||
// 转换为UTC后比较
|
||
utcInUTC := utcTime.UTC()
|
||
estInUTC := estTime.UTC()
|
||
|
||
// EST时区是-5小时,所以相同时钟时间的EST转为UTC后应该比UTC的时钟时间多5小时
|
||
hourDiff := estInUTC.Hour() - utcInUTC.Hour()
|
||
if hourDiff != 5 {
|
||
t.Errorf("Expected 5 hour difference between UTC and EST, got %v", hourDiff)
|
||
}
|
||
}
|
||
|
||
// 测试闰年处理
|
||
func TestLeapYearHandling(t *testing.T) {
|
||
// 测试闰年2月29日
|
||
leapDay, ok := TimeOf("20200229")
|
||
if !ok {
|
||
t.Fatalf("TimeOf(20200229) failed for leap year")
|
||
}
|
||
if leapDay.Day() != 29 || leapDay.Month() != 2 || leapDay.Year() != 2020 {
|
||
t.Errorf("Expected 2020-02-29, got %v", leapDay)
|
||
}
|
||
|
||
// 测试非闰年2月29日
|
||
_, ok = TimeOf("20190229")
|
||
if ok {
|
||
t.Errorf("TimeOf(20190229) should fail for non-leap year")
|
||
}
|
||
|
||
// 测试世纪闰年规则 (2000是闰年,2100不是)
|
||
_, ok = TimeOf("20000229")
|
||
if !ok {
|
||
t.Errorf("TimeOf(20000229) should succeed for century leap year")
|
||
}
|
||
|
||
_, ok = TimeOf("21000229")
|
||
if ok {
|
||
t.Errorf("TimeOf(21000229) should fail for non-leap century year")
|
||
}
|
||
}
|