Files
gf/g/os/gtime/gtime.go

222 lines
7.1 KiB
Go
Raw Normal View History

// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// 时间管理
package gtime
import (
"time"
"regexp"
"strings"
"strconv"
"errors"
)
const (
// 常用时间格式正则匹配,支持的标准时间格式:
// "2017-12-14 04:51:34 +0805 LMT",
// "2017-12-14 04:51:34 +0805 LMT",
// "2006-01-02T15:04:05Z07:00",
// "2014-01-17T01:19:15+08:00",
// "2018-02-09T20:46:17.897Z",
// "2018-02-09 20:46:17.897",
// "2018-02-09T20:46:17Z",
// "2018-02-09 20:46:17",
// "2018-02-09",
// 日期连接符号支持'-'或者'/'
TIME_REAGEX_PATTERN = `(\d{2,4}[-/]\d{2}[-/]\d{2})[\sT]{0,1}(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
)
var (
// 使用正则判断会比直接使用ParseInLocation挨个轮训判断要快很多
timeRegex, _ = regexp.Compile(TIME_REAGEX_PATTERN)
)
// 类似与js中的SetTimeout一段时间后执行回调函数
func SetTimeout(t time.Duration, callback func()) {
go func() {
time.Sleep(t)
callback()
}()
}
// 类似与js中的SetInterval每隔一段时间后执行回调函数当回调函数返回true那么继续执行否则终止执行该方法是异步的
// 注意:由于采用的是循环而不是递归操作,因此间隔时间将会以上一次回调函数执行完成的时间来计算
func SetInterval(t time.Duration, callback func() bool) {
go func() {
for {
time.Sleep(t)
if !callback() {
break
}
}
}()
}
// 设置当前进程全局的默认时区,如: Asia/Shanghai
2018-07-19 15:33:17 +08:00
func SetTimeZone(zone string) error {
location, err := time.LoadLocation(zone)
if err == nil {
time.Local = location
}
return err
}
// 获取当前的纳秒数
func Nanosecond() int64 {
return time.Now().UnixNano()
}
// 获取当前的微秒数
func Microsecond() int64 {
return time.Now().UnixNano()/1e3
}
// 获取当前的毫秒数
func Millisecond() int64 {
return time.Now().UnixNano()/1e6
}
// 获取当前的秒数(时间戳)
func Second() int64 {
return time.Now().UnixNano()/1e9
}
// 获得当前的日期(例如2006-01-02)
func Date() string {
return time.Now().Format("2006-01-02")
}
// 获得当前的时间(例如2006-01-02 15:04:05)
func Datetime() string {
return time.Now().Format("2006-01-02 15:04:05")
}
// 字符串转换为时间对象
2018-07-11 17:06:47 +08:00
func StrToTime(str string) (time.Time, error) {
var result time.Time
var local = time.Local
if match := timeRegex.FindStringSubmatch(str); len(match) > 0 {
var year, month, day, hour, min, sec, nsec int
var array []string
// 日期(支持'-'或'/'连接符号)
array = strings.Split(match[1], "-")
if len(array) < 3 {
array = strings.Split(match[1], "/")
}
if len(array) >= 3 {
// 年是否为缩写,如果是,那么需要补上前缀
year, _ = strconv.Atoi(array[0])
if year < 100 {
year = int(time.Now().Year()/100)*100 + year
}
month, _ = strconv.Atoi(array[1])
day, _ = strconv.Atoi(array[2])
}
// 时间
if len(match[2]) > 0 {
array = strings.Split(match[2], ":")
hour, _ = strconv.Atoi(array[0])
if len(array) >= 2 {
min, _ = strconv.Atoi(array[1])
}
if len(array) >= 3 {
sec, _ = strconv.Atoi(array[2])
}
}
// 纳秒,检查并执行位补齐
if len(match[3]) > 0 {
nsec, _ = strconv.Atoi(match[3])
for i := 0; i < 9 - len(match[3]); i++ {
nsec *= 10
}
}
// 如果字符串中有时区信息(具体时间信息)那么执行时区转换将时区转成UTC
if match[4] != "" && match[6] == "" {
match[6] = "000000"
}
// 如果offset有值优先处理offset否则处理后面的时区名称
if match[6] != "" {
zone := strings.Replace(match[6], ":", "", -1)
zone = strings.TrimLeft(zone, "+-")
zone += strings.Repeat("0", 6 - len(zone))
h, _ := strconv.Atoi(zone[0 : 2])
m, _ := strconv.Atoi(zone[2 : 4])
s, _ := strconv.Atoi(zone[4 : 6])
// 判断字符串输入的时区是否和当前程序时区相等(使用offset判断)不相等则将对象统一转换为UTC时区
// 当前程序时区Offset(秒)
_, localOffset := time.Now().Zone()
if (h * 3600 + m * 60 + s) != localOffset {
local = time.UTC
// UTC时差转换
operation := match[5]
if operation != "+" && operation != "-" {
operation = "-"
}
switch operation {
case "+":
if h > 0 {
hour -= h
}
if m > 0 {
min -= m
}
if s > 0 {
sec -= s
}
case "-":
if h > 0 {
hour += h
}
if m > 0 {
min += m
}
if s > 0 {
sec += s
}
}
}
}
// 生成UTC时间对象
result = time.Date(year, time.Month(month), day, hour, min, sec, nsec, local)
return result, nil
}
return result, errors.New("unsupported time format")
}
2018-07-11 13:51:03 +08:00
// 时区转换
func ConvertZone(strTime string, toZone string, fromZone...string) (time.Time, error) {
t, err := StrToTime(strTime)
if err != nil {
return time.Time{}, err
}
if len(fromZone) > 0 {
if l, err := time.LoadLocation(fromZone[0]); err != nil {
return time.Time{}, err
} else {
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), l)
}
}
if l, err := time.LoadLocation(toZone); err != nil {
return time.Time{}, err
} else {
return t.In(l), nil
}
}
2018-07-11 17:06:47 +08:00
// 字符串转换为时间对象指定字符串时间格式format格式形如Y-m-d H:i:s
func StrToTimeFormat(str string, format string) (time.Time, error) {
return StrToTimeLayout(str, formatToStdLayout(format))
}
// 字符串转换为时间对象通过标准库layout格式进行解析layout格式形如2006-01-02 15:04:05
2018-07-11 13:51:03 +08:00
func StrToTimeLayout(str string, layout string) (time.Time, error) {
if t, err := time.ParseInLocation(layout, str, time.Local); err == nil {
return t, nil
} else {
return time.Time{}, err
}
}