Go语言中的日期时间

436 阅读4分钟

前言

如果你使用过GO语言,那么你一定会注意到,他的时间格式化跟别的语言有所不同,在与其他语言通过api交互的过程中,还可能会报错。

时间格式化

将时间格式化为字符串

t1 := time.Now()
fmt.Println(t1.Format("2006-01-02 15:04:05"))

将字符串格式化为时间

t2, err := time.Parse("2006-01-02 15:04:05", "2023-02-15 14:30:00")
// 2023-02-15 14:30:00 +0000 UTC
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
   fmt.Println("LoadLocation error:", err)
   return
}
t3, err := time.ParseInLocation("2006-01-02 15:04:05", "2023-02-15 14:30:00", loc)
// 2023-02-15 14:30:00 +0800 CST

常用时间格式

yyyy-MM-ddTHH:mm:ss.SSSZ
T使用用来分割日期和时间的;Z表示UTC统一时间,代表着时区为UTC+0,如果需要修改时差的话,把Z换成时差,比如+08:00; SSS表示毫秒数,通常用不到;

UTC表示世界协调时间(Coordinated Universal Time),UTC时间与北京时间相差8小时 (世界协调时间 UTC +00:00 相当于北京 UTC +8:00),以下是一些不同时区的具体时间表示

2019-10-12T07:20:50.52Z (UTC+0) 
2019-10-12T07:20:50.52+00:00 (UTC+0)  
2019-10-12T14:20:50.52+08:00 (UTC+8)  
2019-10-12T03:20:50.52-04:00 (UTC-4)

除了UTC,还有其他的时间标准,比如GMT、AST、CST等,都可与UTC进行转换

GO中时间格式化标准格式 2006-01-02 15:04:05
如何快速记忆:01 02 03 04 05,24小时制的话03就用15代替;老外常用的格式是 Mon Jan 2 15:04:05 2006 -0700 MST 对应着0 1 2 3 4 5 6 7

接收JavaScript的日期时间

正常情况下,传递给后端 yyyy-MM-dd HH:mm:ss 这种格式,会报错,因为在序列化的时候默认用的是RFC3339Nano标准格式,在time.go和format.go中有如下定义

// time.go
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t Time) MarshalJSON() ([]byte, error) {
   if y := t.Year(); y < 0 || y >= 10000 {
      // RFC 3339 is clear that years are 4 digits exactly.
      // See golang.org/issue/4556#c15 for more discussion.
      return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
   }

   b := make([]byte, 0, len(RFC3339Nano)+2)
   b = append(b, '"')
   b = t.AppendFormat(b, RFC3339Nano)
   b = append(b, '"')
   return b, nil
}
// format.go
const (
    // ...
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
)

要怎么解决呢

方式一,前端直接通过系统函数,将时间格式化为ISO 8601(RFC 3339)格式的时间,然后传递给后端

datetime.toISOString() // "2023-02-15T23:59:59.386Z" 

方式二,前端传递"yyyy-MM-dd HH:mm:ss"格式的时间字符串,后端按字符串来接收,然后再转换为time.Time类型使用

import moment from 'moment';

const date = new Date();
const formattedDate = moment(date).format('YYYY-MM-DD HH:mm:ss');
console.log(formattedDate); // 2023-02-15 16:45:30

在上面的代码中,我们使用了第三方库momentjs,当然也可以用date-fns.org或者dayjs;还可以直接通过时间对象的函数,获取年、月、日,然后拼接起来

function formatDate(date) {
  const year = date.getFullYear().toString().padStart(4, '0');
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
  const day = date.getDate().toString().padStart(2, '0');
  const hours = date.getHours().toString().padStart(2, '0');
  const minutes = date.getMinutes().toString().padStart(2, '0');
  const seconds = date.getSeconds().toString().padStart(2, '0');
  
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

const date = new Date();
const formattedDate = formatDate(date);

console.log(formattedDate); // 2023-02-15 16:45:30

关于ISO 8601 和 RFC 3339

对于时间的表示格式,ISO对其进行了标准化,就是现在常见的ISO 8601标准。 在使用的过程中,你大可不必细究其中的区别。你需要知道是,RFC3339是从ISO 8601派生的一组标准,有着一些细小的区别。比如 RFC 3339可以不用带"T",具体可以查看