业务场景中使用到的API或者RPC接口定义都采用的是thrift,因此时间的传递格式是i64类型的秒级时间戳。一般会选择统一逻辑对RPC的请求转换成数据库的model,时间类型的转换则是通过 time.Unix(sec,0) 方式转换的,时间是可以为0值。 不久前做一个数据发布录入功能,里面有一个发布时间字段,通过上面的方式转换成model的time.Time类型之后,统一判断如果发布时间是0值( t.IsZero() )则重新赋值为当前系统时间即 time.Now()

按照上面方式写好代码测试发现,数据库存在了很多发布时间是0。调试发现:

var sec int64
t:=time.Unix(sec,0)
fmt.Println(t.IsZero()) // false

time.Unix(0,0).IsZero() 的结果是false。

首先想到的是看下IsZero的实现,如下:

// IsZero reports whether t represents the zero time instant,
// January 1, year 1, 00:00:00 UTC.
func (t Time) IsZero() bool {
	return t.sec() == 0 && t.nsec() == 0

从这里看好像是没问题的,因为time.Unix传入的两个参数都是0即sec=0nsec=0,但是为什么返回false呢?于是怀疑sec()或者nsec()方法有问题,于是跟进并没有发现问题。

// nsec returns the time's nanoseconds.
func (t *Time) nsec() int32 {
	return int32(t.wall & nsecMask)
// sec returns the time's seconds since Jan 1 year 1.
func (t *Time) sec() int64 {
	if t.wall&hasMonotonic != 0 {
		return wallToInternal + int64(t.wall<<1>>(nsecShift+1))
	return t.ext

既然取的时候没问题,那就应该是设值的时候有问题了。然后查看time.Unix(sec,nsec)实现如下:

// Unix returns the local Time corresponding to the given Unix time,
// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
// It is valid to pass nsec outside the range [0, 999999999].
// Not all sec values have a corresponding time value. One such
// value is 1<<63-1 (the largest int64 value).
func Unix(sec int64, nsec int64) Time {
	if nsec < 0 || nsec >= 1e9 {
		n := nsec / 1e9
		sec += n
		nsec -= n * 1e9
		if nsec < 0 {
			nsec += 1e9
			sec--
	return unixTime(sec, int32(nsec))
func unixTime(sec int64, nsec int32) Time {
	return Time{uint64(nsec), sec + unixToInternal, Local}
//	unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay

终于发现了问题,也就是time.Unix入参secnsec认为是从1970-01-01 08:00:00开始计算的,也就是后面加上的unixToInternal,代表的就是从时间0值0001-01-01 00:00:001970-01-01 08:00:00的秒级的时间戳。
简言之:time.Unix(0,0)=1970-01-01 08:00:00,而IsZero判断是时间是否等于0001-01-01 00:00:00,因此time.Unix(0,0).IsZero() 的结果是false。

自定义一个函数IsZero,判断当前的时间是否为0值:

import "time"
//1970-01-01 08:00:00 +0800 CST
var zeroTime = time.Unix(0, 0)
// IsZero reports whether t represents the zero time instant
func IsZero(t time.Time) bool {
	return t.IsZero() || zeroTime.Equal(t)
	func TestIsZero(t *testing.T) {
	type args struct {
		t time.Time
	tests := []struct {
		name string
		args args
		want bool
		{name: "test1", args: args{time.Unix(0, 0)}, want: true},
		{name: "test2", args: args{}, want: true},
		{name: "test3", args: args{time.Now()}, want: false},
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := IsZero(tt.args.t); got != tt.want {
				t.Errorf("IsZero() = %v, want %v", got, tt.want)
 

=== RUN TestIsZero
=== RUN TestIsZero/test1
=== RUN TestIsZero/test2
=== RUN TestIsZero/test3
— PASS: TestIsZero (0.00s)
— PASS: TestIsZero/test1 (0.00s)
— PASS: TestIsZero/test2 (0.00s)
— PASS: TestIsZero/test3 (0.00s)
PASS

从测试结果符合预期即:time.Unix(0,0)及没有初始化的time.Time默认值都为true。

另外从上面也可以看出,time的IsZero方法可以用来判断是否对time.Time类型的属性做过初始化,或者说该类型的时间是否为0001-01-01 00:00:00

本次旅程到此结束,希望对你有所帮助!

背景业务场景中使用到的API或者RPC接口定义都采用的是thrift,因此时间的传递格式是i64类型的秒级时间戳。一般会选择统一逻辑对RPC的请求转换成数据库的model,时间类型的转换则是通过time.Unix(sec,0)方式转换的,时间是可以为0值。 不久前做一个数据发布录入功能,里面有一个发布时间字段,通过上面的方式转换成model的time.Time类型之后,统一判断如果发布时间是0值(t.IsZero())则重新赋值为当前系统时间即time.Now()。问题按照上面方式写好代码测试发现,数 t := time.Now() nilTime:=time.Time{} var waitConfirmRecordParam model.WaitConfirmRecord waitConfirmRecordParam.CreatedAt = t waitConfirmRecordParam.UpdatedAt = t waitConfirmRecordParam.DeletedAt = nilTime//此处即为零值 waitConfirmRecordParam.ConfirmTi
持续时间类isZero()方法 (Duration Class isZero() method) isZero() method is available in java.time package. isZero()方法在java.time包中可用。 isZero() method is used to check whether this Duration object holds the...
1.在C++中程序中不允许相同的函数出现,否则调用时无法区分函数; 2.区分函数靠的不仅是函数名,还有函数的参数列表,如果多个函数拥有相同的函数名,但参数列表不同,则称为函数重载。 int fun(); int fun(int,double); int fun(float); 函数的返回值不能用来区别函数。 二:示例代码 #include #include using
在我们编程过程中,经常会用到与时间相关的各种务需求,下面来介绍 golang 中有关时间的一些基本用法,我们从 time 的几种 type 来开始介绍。 时间可分为时间点与时间段,golang 也不例外,提供了以下两种基础类型 时间点(Time) 时间段(Duration) 除此之外 golang 也提供了以下类型,做一些特定的业务 时区(Location) Ticker Timer(定时器...
Date函数: 定义:func Date(yearint, month Month, day, hour, min, sec, nsec int, loc *Location) Time 函数基于给定的Location返回一个“yyyy-mm-ddhh:mm:ss + nsec nanoseconds”形式的Time对象,month, day, hour, mi
const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" RubyDate = "Mon Jan 02 15:04:05 -07...
使用reflect的过程中,想让结构体的值根据tag中default的值来进行赋值操作。 如果这个field本身有值,就不赋予默认值,如果是零值,则赋予默认值。 没办法判断这个值有没有被赋值过,但可以判断是否是零值。 https://studygolang.com/articles/12029?fr=sidebar
time.IsZero用于判断time.Time对象是否为零值。零值表示时间点为January 1, year 1, 00:00:00 UTC。方法一是使用golang标准库中的IsZero方法,该方法返回一个bool值,用于判断给定的time.Time对象是否为零值。方法二是使用函数式方法调用,使用t.IsZero()来判断time.Now()是否为零值,并根据结果进行相应的操作。方法三是通过赋值零值的方式,将time.Time对象赋值为nilTime,然后通过判断赋值后的对象是否为零值来进行判断。总之,time.IsZero用于判断time.Time对象是否为零值,可以通过多种方式进行判断。