调整项目结构,factory只负责暴露方法,不实现业务细节

This commit is contained in:
2025-12-07 00:04:01 +08:00
parent b66f345281
commit 339920a940
23 changed files with 2165 additions and 1231 deletions

358
tools/datetime.go Normal file
View File

@@ -0,0 +1,358 @@
package tools
import (
"fmt"
"time"
)
// TimeZone 时区常量
const (
UTC = "UTC"
AsiaShanghai = "Asia/Shanghai"
AmericaNewYork = "America/New_York"
EuropeLondon = "Europe/London"
AsiaTokyo = "Asia/Tokyo"
)
// DefaultTimeZone 默认时区
var DefaultTimeZone = UTC
// SetDefaultTimeZone 设置默认时区
func SetDefaultTimeZone(timezone string) error {
_, err := time.LoadLocation(timezone)
if err != nil {
return fmt.Errorf("invalid timezone: %w", err)
}
DefaultTimeZone = timezone
return nil
}
// GetLocation 获取时区Location对象
func GetLocation(timezone string) (*time.Location, error) {
if timezone == "" {
timezone = DefaultTimeZone
}
return time.LoadLocation(timezone)
}
// Now 获取当前时间(使用指定时区)
func Now(timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
// 如果时区无效使用UTC
loc, _ = time.LoadLocation(UTC)
}
return time.Now().In(loc)
}
// Parse 解析时间字符串
// layout: 时间格式,如 "2006-01-02 15:04:05"
// value: 时间字符串
// timezone: 时区,如果为空则使用默认时区
func Parse(layout, value string, timezone ...string) (time.Time, error) {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
return time.Time{}, fmt.Errorf("invalid timezone: %w", err)
}
t, err := time.ParseInLocation(layout, value, loc)
if err != nil {
return time.Time{}, fmt.Errorf("failed to parse time: %w", err)
}
return t, nil
}
// Format 格式化时间
// t: 时间对象
// layout: 时间格式,如 "2006-01-02 15:04:05"
// timezone: 时区,如果为空则使用时间对象本身的时区
func Format(t time.Time, layout string, timezone ...string) string {
if len(timezone) > 0 && timezone[0] != "" {
loc, err := GetLocation(timezone[0])
if err == nil {
t = t.In(loc)
}
}
return t.Format(layout)
}
// ToTimezone 将时间转换到指定时区
func ToTimezone(t time.Time, timezone string) (time.Time, error) {
loc, err := GetLocation(timezone)
if err != nil {
return time.Time{}, fmt.Errorf("invalid timezone: %w", err)
}
return t.In(loc), nil
}
// CommonLayouts 常用时间格式
var CommonLayouts = struct {
DateTime string
DateTimeSec string
Date string
Time string
TimeSec string
ISO8601 string
RFC3339 string
RFC3339Nano string
Unix string
}{
DateTime: "2006-01-02 15:04",
DateTimeSec: "2006-01-02 15:04:05",
Date: "2006-01-02",
Time: "15:04",
TimeSec: "15:04:05",
ISO8601: "2006-01-02T15:04:05Z07:00",
RFC3339: time.RFC3339,
RFC3339Nano: time.RFC3339Nano,
Unix: "unix",
}
// FormatDateTime 格式化日期时间2006-01-02 15:04:05
func FormatDateTime(t time.Time, timezone ...string) string {
return Format(t, CommonLayouts.DateTimeSec, timezone...)
}
// FormatDate 格式化日期2006-01-02
func FormatDate(t time.Time, timezone ...string) string {
return Format(t, CommonLayouts.Date, timezone...)
}
// FormatTime 格式化时间15:04:05
func FormatTime(t time.Time, timezone ...string) string {
return Format(t, CommonLayouts.TimeSec, timezone...)
}
// ParseDateTime 解析日期时间字符串2006-01-02 15:04:05
func ParseDateTime(value string, timezone ...string) (time.Time, error) {
return Parse(CommonLayouts.DateTimeSec, value, timezone...)
}
// ParseDate 解析日期字符串2006-01-02
func ParseDate(value string, timezone ...string) (time.Time, error) {
return Parse(CommonLayouts.Date, value, timezone...)
}
// ToUnix 转换为Unix时间戳
func ToUnix(t time.Time) int64 {
return t.Unix()
}
// FromUnix 从Unix时间戳创建时间
func FromUnix(sec int64, timezone ...string) time.Time {
t := time.Unix(sec, 0)
if len(timezone) > 0 && timezone[0] != "" {
loc, err := GetLocation(timezone[0])
if err == nil {
t = t.In(loc)
}
}
return t
}
// ToUnixMilli 转换为Unix毫秒时间戳
func ToUnixMilli(t time.Time) int64 {
return t.UnixMilli()
}
// FromUnixMilli 从Unix毫秒时间戳创建时间
func FromUnixMilli(msec int64, timezone ...string) time.Time {
t := time.UnixMilli(msec)
if len(timezone) > 0 && timezone[0] != "" {
loc, err := GetLocation(timezone[0])
if err == nil {
t = t.In(loc)
}
}
return t
}
// AddDays 添加天数
func AddDays(t time.Time, days int) time.Time {
return t.AddDate(0, 0, days)
}
// AddMonths 添加月数
func AddMonths(t time.Time, months int) time.Time {
return t.AddDate(0, months, 0)
}
// AddYears 添加年数
func AddYears(t time.Time, years int) time.Time {
return t.AddDate(years, 0, 0)
}
// StartOfDay 获取一天的开始时间00:00:00
func StartOfDay(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, month, day := t.Date()
return time.Date(year, month, day, 0, 0, 0, 0, loc)
}
// EndOfDay 获取一天的结束时间23:59:59.999999999
func EndOfDay(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, month, day := t.Date()
return time.Date(year, month, day, 23, 59, 59, 999999999, loc)
}
// StartOfMonth 获取月份的开始时间
func StartOfMonth(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, month, _ := t.Date()
return time.Date(year, month, 1, 0, 0, 0, 0, loc)
}
// EndOfMonth 获取月份的结束时间
func EndOfMonth(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, month, _ := t.Date()
// 获取下个月的第一天然后减去1纳秒
nextMonth := time.Date(year, month+1, 1, 0, 0, 0, 0, loc)
return nextMonth.Add(-time.Nanosecond)
}
// StartOfYear 获取年份的开始时间
func StartOfYear(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, _, _ := t.Date()
return time.Date(year, 1, 1, 0, 0, 0, 0, loc)
}
// EndOfYear 获取年份的结束时间
func EndOfYear(t time.Time, timezone ...string) time.Time {
tz := DefaultTimeZone
if len(timezone) > 0 && timezone[0] != "" {
tz = timezone[0]
}
loc, err := GetLocation(tz)
if err != nil {
loc, _ = time.LoadLocation(UTC)
}
t = t.In(loc)
year, _, _ := t.Date()
return time.Date(year, 12, 31, 23, 59, 59, 999999999, loc)
}
// DiffDays 计算两个时间之间的天数差
func DiffDays(t1, t2 time.Time) int {
return int(t2.Sub(t1).Hours() / 24)
}
// DiffHours 计算两个时间之间的小时差
func DiffHours(t1, t2 time.Time) int64 {
return int64(t2.Sub(t1).Hours())
}
// DiffMinutes 计算两个时间之间的分钟差
func DiffMinutes(t1, t2 time.Time) int64 {
return int64(t2.Sub(t1).Minutes())
}
// DiffSeconds 计算两个时间之间的秒数差
func DiffSeconds(t1, t2 time.Time) int64 {
return int64(t2.Sub(t1).Seconds())
}
// ToUTC 将时间转换为UTC时间
// t: 时间对象(可以是任意时区)
// 返回: UTC时间
func ToUTC(t time.Time) time.Time {
return t.UTC()
}
// ToUTCFromTimezone 从指定时区转换为UTC时间
// t: 时间对象(会被视为指定时区的时间)
// timezone: 源时区
// 返回: UTC时间
// 注意此方法假设时间对象t表示的是指定时区的本地时间然后转换为UTC
func ToUTCFromTimezone(t time.Time, timezone string) (time.Time, error) {
loc, err := GetLocation(timezone)
if err != nil {
return time.Time{}, fmt.Errorf("invalid timezone: %w", err)
}
// 将时间视为指定时区的本地时间然后转换为UTC
// 首先将时间转换到指定时区然后转换为UTC
localTime := time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), loc)
return localTime.UTC(), nil
}
// ParseToUTC 解析时间字符串并转换为UTC时间
// layout: 时间格式,如 "2006-01-02 15:04:05"
// value: 时间字符串
// timezone: 源时区,如果为空则使用默认时区
// 返回: UTC时间
func ParseToUTC(layout, value string, timezone ...string) (time.Time, error) {
t, err := Parse(layout, value, timezone...)
if err != nil {
return time.Time{}, err
}
return t.UTC(), nil
}
// ParseDateTimeToUTC 解析日期时间字符串并转换为UTC时间便捷方法
// value: 时间字符串(格式: 2006-01-02 15:04:05
// timezone: 源时区,如果为空则使用默认时区
// 返回: UTC时间
func ParseDateTimeToUTC(value string, timezone ...string) (time.Time, error) {
return ParseToUTC(CommonLayouts.DateTimeSec, value, timezone...)
}
// ParseDateToUTC 解析日期字符串并转换为UTC时间便捷方法
// value: 日期字符串(格式: 2006-01-02
// timezone: 源时区,如果为空则使用默认时区
// 返回: UTC时间当天的00:00:00 UTC时间
func ParseDateToUTC(value string, timezone ...string) (time.Time, error) {
return ParseToUTC(CommonLayouts.Date, value, timezone...)
}

173
tools/money.go Normal file
View File

@@ -0,0 +1,173 @@
package tools
import (
"fmt"
"math"
)
// MoneyCalculator 金额计算工具(以分为单位)
type MoneyCalculator struct{}
// NewMoneyCalculator 创建金额计算器
func NewMoneyCalculator() *MoneyCalculator {
return &MoneyCalculator{}
}
// YuanToCents 元转分
func (m *MoneyCalculator) YuanToCents(yuan float64) int64 {
return int64(math.Round(yuan * 100))
}
// CentsToYuan 分转元
func (m *MoneyCalculator) CentsToYuan(cents int64) float64 {
return float64(cents) / 100
}
// FormatYuan 格式化显示金额分转元保留2位小数
func (m *MoneyCalculator) FormatYuan(cents int64) string {
return fmt.Sprintf("%.2f", m.CentsToYuan(cents))
}
// Add 金额相加
func (m *MoneyCalculator) Add(amount1, amount2 int64) int64 {
return amount1 + amount2
}
// Subtract 金额相减
func (m *MoneyCalculator) Subtract(amount1, amount2 int64) int64 {
return amount1 - amount2
}
// Multiply 金额乘法(金额 * 数量)
func (m *MoneyCalculator) Multiply(amount int64, quantity int) int64 {
return amount * int64(quantity)
}
// MultiplyFloat 金额乘法(金额 * 浮点数,如折扣)
func (m *MoneyCalculator) MultiplyFloat(amount int64, rate float64) int64 {
return int64(math.Round(float64(amount) * rate))
}
// Divide 金额除法(平均分配)
func (m *MoneyCalculator) Divide(amount int64, count int) int64 {
if count <= 0 {
return 0
}
return amount / int64(count)
}
// CalculateDiscount 计算折扣金额
func (m *MoneyCalculator) CalculateDiscount(originalAmount int64, discountRate float64) int64 {
if discountRate <= 0 || discountRate >= 1 {
return 0
}
return int64(math.Round(float64(originalAmount) * discountRate))
}
// CalculatePercentage 计算百分比金额
func (m *MoneyCalculator) CalculatePercentage(amount int64, percentage float64) int64 {
return int64(math.Round(float64(amount) * percentage / 100))
}
// Max 取最大金额
func (m *MoneyCalculator) Max(amounts ...int64) int64 {
if len(amounts) == 0 {
return 0
}
max := amounts[0]
for _, amount := range amounts[1:] {
if amount > max {
max = amount
}
}
return max
}
// Min 取最小金额
func (m *MoneyCalculator) Min(amounts ...int64) int64 {
if len(amounts) == 0 {
return 0
}
min := amounts[0]
for _, amount := range amounts[1:] {
if amount < min {
min = amount
}
}
return min
}
// IsPositive 判断是否为正数
func (m *MoneyCalculator) IsPositive(amount int64) bool {
return amount > 0
}
// IsZero 判断是否为零
func (m *MoneyCalculator) IsZero(amount int64) bool {
return amount == 0
}
// IsNegative 判断是否为负数
func (m *MoneyCalculator) IsNegative(amount int64) bool {
return amount < 0
}
// Equal 判断金额是否相等
func (m *MoneyCalculator) Equal(amount1, amount2 int64) bool {
return amount1 == amount2
}
// Greater 判断第一个金额是否大于第二个
func (m *MoneyCalculator) Greater(amount1, amount2 int64) bool {
return amount1 > amount2
}
// Less 判断第一个金额是否小于第二个
func (m *MoneyCalculator) Less(amount1, amount2 int64) bool {
return amount1 < amount2
}
// Sum 计算金额总和
func (m *MoneyCalculator) Sum(amounts ...int64) int64 {
var total int64
for _, amount := range amounts {
total += amount
}
return total
}
// SplitAmount 金额分摊(处理分摊不均的情况)
func (m *MoneyCalculator) SplitAmount(totalAmount int64, count int) []int64 {
if count <= 0 {
return []int64{}
}
baseAmount := totalAmount / int64(count)
remainder := totalAmount % int64(count)
amounts := make([]int64, count)
for i := 0; i < count; i++ {
amounts[i] = baseAmount
if int64(i) < remainder {
amounts[i]++
}
}
return amounts
}
// 全局金额计算器实例
var Money = NewMoneyCalculator()
// 便捷函数
func YuanToCents(yuan float64) int64 {
return Money.YuanToCents(yuan)
}
func CentsToYuan(cents int64) float64 {
return Money.CentsToYuan(cents)
}
func FormatYuan(cents int64) string {
return Money.FormatYuan(cents)
}

26
tools/version.go Normal file
View File

@@ -0,0 +1,26 @@
package tools
import (
"os"
)
// Version 版本号 - 在这里修改版本号(默认值)
const DefaultVersion = "1.0.1"
// GetVersion 获取版本号
// 优先从环境变量 DOCKER_TAG 或 VERSION 中读取
// 如果没有设置环境变量,则使用默认版本号
func GetVersion() string {
// 优先从 Docker 标签环境变量读取
if dockerTag := os.Getenv("DOCKER_TAG"); dockerTag != "" {
return dockerTag
}
// 从通用版本环境变量读取
if version := os.Getenv("VERSION"); version != "" {
return version
}
// 使用默认版本号
return DefaultVersion
}