调整项目结构,factory只负责暴露方法,不实现业务细节
This commit is contained in:
358
tools/datetime.go
Normal file
358
tools/datetime.go
Normal 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
173
tools/money.go
Normal 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
26
tools/version.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user