From ca9dedaf82541283831701296fc244f08bb8ae29 Mon Sep 17 00:00:00 2001 From: 4566704 <4566704@qq.com> Date: Sun, 20 Sep 2026 12:20:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(timex):=20=E8=87=AA=20go-hua/common=20?= =?UTF-8?q?=E8=BF=81=E5=85=A5=E6=97=B6=E9=97=B4=E6=97=A5=E6=9C=9F=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=B9=B6=E7=8B=AC=E7=AB=8B=E6=88=90=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - NT/UTC 时间戳互转、时间字符串转毫秒时间戳、指定年月天数 - 附单元测试、examples/timex 例程与包 README --- examples/timex/main.go | 23 +++++++++++++++ timex/README.md | 30 +++++++++++++++++++ timex/timex.go | 67 ++++++++++++++++++++++++++++++++++++++++++ timex/timex_test.go | 44 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 examples/timex/main.go create mode 100644 timex/README.md create mode 100644 timex/timex.go create mode 100644 timex/timex_test.go diff --git a/examples/timex/main.go b/examples/timex/main.go new file mode 100644 index 0000000..e28e42b --- /dev/null +++ b/examples/timex/main.go @@ -0,0 +1,23 @@ +// timex 包示例:时间日期工具(NT/UTC 时间戳互转、时间字符串转毫秒时间戳、月份天数) +package main + +import ( + "fmt" + + "git.zeroonesoft.cn/golib/zogo/timex" +) + +func main() { + // Windows NT 时间戳与 Unix 时间戳互转 + nt := timex.UtcToNt(1000000000) + fmt.Println("Unix 转 NT:", nt) + fmt.Println("NT 转 Unix:", timex.NtToUtc(nt)) + + // 时间字符串转毫秒时间戳 + ts, err := timex.TimeStrToTimestamp("2026-08-29 12:00:00") + fmt.Println("时间字符串转毫秒时间戳:", ts, "错误:", err) + + // 查询指定年月有多少天 + fmt.Println("2026年2月天数:", timex.GetYearMonthToDay(2026, 2)) + fmt.Println("2024年2月天数:", timex.GetYearMonthToDay(2024, 2)) +} diff --git a/timex/README.md b/timex/README.md new file mode 100644 index 0000000..ec2045b --- /dev/null +++ b/timex/README.md @@ -0,0 +1,30 @@ +# timex + +时间与日期工具:Windows NT 时间戳与 Unix 时间戳互转、时间字符串转毫秒时间戳、 +查询指定年月的天数。 + +> 迁移自 go-hua/common(原 time.go / date.go)。 + +## 用法 + +```go +import "git.zeroonesoft.cn/golib/zogo/timex" + +// Windows NT 时间戳(100 纳秒,1601 纪元)与 Unix 秒级时间戳互转 +nt := timex.UtcToNt(1000000000) +unix := timex.NtToUtc(nt) + +// 时间字符串 → 毫秒时间戳(本地时区,格式 2006-01-02 15:04:05) +ts, err := timex.TimeStrToTimestamp("2026-08-29 12:00:00") + +// 指定年月有多少天(自动处理闰年) +timex.GetYearMonthToDay(2024, 2) // 29 +``` + +完整可运行例程:[examples/timex/main.go](../examples/timex/main.go) + +## 注意 + +- `NtToUtc/UtcToNt` 为秒级精度整数运算(NT 侧按 1e7 折算),无溢出保护。 +- `TimeStrToTimestamp` 只接受 `2006-01-02 15:04:05` 一种格式,其他格式自行用 + 标准库 `time.ParseInLocation`。 diff --git a/timex/timex.go b/timex/timex.go new file mode 100644 index 0000000..58a6b9a --- /dev/null +++ b/timex/timex.go @@ -0,0 +1,67 @@ +// Package timex 时间与日期工具:Windows NT 时间戳与 Unix 时间戳互转、 +// 时间字符串转毫秒时间戳、查询指定年月的天数。 +package timex + +import ( + "time" +) + +// NtToUtc Windows NT timestamp to Unix UTC timestamp +func NtToUtc(ntTimestamp uint64) uint64 { + unixTimestamp := (ntTimestamp - 11644473600000000) / 1000000 + return unixTimestamp +} + +// UtcToNt Unix UTC timestamp to Windows NT timestamp +func UtcToNt(unixTime uint64) uint64 { + ntTimestamp := unixTime*1000000 + 11644473600000000 + return ntTimestamp +} + +// 时间字符串转时间戳 +func TimeStrToTimestamp(timeStr string) (int64, error) { + layout := "2006-01-02 15:04:05" + t, err := time.ParseInLocation(layout, timeStr, time.Local) + if err != nil { + return 0, err + } + // 获取时间戳(单位是秒),并转换为毫秒 + millisecondTimestamp := t.UnixMilli() + return millisecondTimestamp, nil +} + +// GetYearMonthToDay 查询指定年份指定月份有多少天 +// @params year int 指定年份 +// @params month int 指定月份 +func GetYearMonthToDay(year int, month int) int { + // 有31天的月份 + day31 := map[int]bool{ + 1: true, + 3: true, + 5: true, + 7: true, + 8: true, + 10: true, + 12: true, + } + if day31[month] { + return 31 + } + // 有30天的月份 + day30 := map[int]bool{ + 4: true, + 6: true, + 9: true, + 11: true, + } + if day30[month] { + return 30 + } + // 计算是平年还是闰年 + if (year%4 == 0 && year%100 != 0) || year%400 == 0 { + // 得出2月的天数 + return 29 + } + // 得出2月的天数 + return 28 +} diff --git a/timex/timex_test.go b/timex/timex_test.go new file mode 100644 index 0000000..6dc1267 --- /dev/null +++ b/timex/timex_test.go @@ -0,0 +1,44 @@ +package timex + +import "testing" + +func TestGetYearMonthToDay(t *testing.T) { + cases := []struct { + year, month, want int + }{ + {2024, 2, 29}, // 闰年 + {2023, 2, 28}, // 平年 + {2000, 2, 29}, // 400 整除 + {1900, 2, 28}, // 100 整除非 400 + {2026, 1, 31}, + {2026, 4, 30}, + } + for _, c := range cases { + if got := GetYearMonthToDay(c.year, c.month); got != c.want { + t.Errorf("GetYearMonthToDay(%d,%d) = %d, want %d", c.year, c.month, got, c.want) + } + } +} + +func TestNtUtcConvert(t *testing.T) { + nt := UtcToNt(1000000000) + if got := NtToUtc(nt); got != 1000000000 { + t.Errorf("NT/UTC 往返 = %d, want 1000000000", got) + } +} + +func TestTimeStrToTimestamp(t *testing.T) { + ts, err := TimeStrToTimestamp("2026-08-29 12:00:00") + if err != nil { + t.Fatalf("TimeStrToTimestamp: %v", err) + } + if ts <= 0 { + t.Errorf("时间戳应为正数: %d", ts) + } + if ts%1000 != 0 { + t.Errorf("毫秒时间戳应为整秒: %d", ts) + } + if _, err := TimeStrToTimestamp("bad"); err == nil { + t.Error("非法格式应返回错误") + } +}