359 lines
9.5 KiB
Go
359 lines
9.5 KiB
Go
package datetime
|
||
|
||
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...)
|
||
}
|