关于 Time.Before 陷阱

Justin19960208 · 2018-08-04 11:44:53 · 3798 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2018-08-04 11:44:53 的主题,其中的信息可能已经有所发展或是发生改变。

判断一个字符串 clock time 格式时间是否发生穿越(比当前时间晚)

func IsTimeThrough(clockTime string) bool {
    tm, err := time.Parse("2006-01-02 15:04:05", clockTime)
    if err != nil {
        return false
    }

    if time.Now().Add(time.Minute * 10).Before(tm) {
        return true
    }

    return false
}

单体测试代码:

func IsTimeThrough(clockTime string) bool {
    tm, err := time.Parse("2006-01-02 15:04:05", clockTime)
    if err != nil {
        return false
    }

    t1 := time.Now().Add(time.Minute * 10)
    fmt.Println(t1.Format("2006-01-02 15:04:05"))
    fmt.Println(tm.Format("2006-01-02 15:04:05"))

    var flag = false
    if t1.Before(tm) {
        fmt.Println("true")
        flag = true
    } else {
        fmt.Println("false")
        flag = false
    }


    return flag
}

测试结果:

2018-08-04 11:30:34
2018-08-04 11:21:10
true

查看 time 包源码注释找到:

go1.9.2 time/time.go L48
// If Times t and u both contain monotonic clock readings, the operations
// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out
// using the monotonic clock readings alone, ignoring the wall clock
// readings. If either t or u contains no monotonic clock reading, these
// operations fall back to using the wall clock readings.

如果两个时钟都是 monotonic 模式,会忽略 wall 的值,如果有一个不是 mononotic,会使用 wall 来作为补偿。

通过 debug 发现 Now 生成的时钟是 monitonic,传入的字符串转化的时钟不是 monotonic(wall = 0)。 虽然有这样的限制,但是不能违反结果啊!!!

这算 BUG 吗?

贴相应的源码片段:

// 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 int64(t.ext)
}
// Before reports whether the time instant t is before u.
func (t Time) Before(u Time) bool {
    if t.wall&u.wall&hasMonotonic != 0 {
        return t.ext < u.ext
    }
    return t.sec() < u.sec() || t.sec() == u.sec() && t.nsec() < u.nsec()
}

如果这样的需求该自己作比较?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3798 次点击  
加入收藏 微博
5 回复  |  直到 2018-08-15 14:54:32
Justin19960208
Justin19960208 · #1 · 7年之前

上一个实现:

func IsTimeThrough(clockTime string) bool {
    tm, err := time.Parse("2006-01-02 15:04:05", clockTime)
    if err != nil {
        return false
    }

    // as the restricted condition for time.Before()
    now := time.Now().Add(time.Minute * 10)
    nY, nM, nD := now.Date()
    tY, tM, tD := tm.Date()
    if tY > nY {
        return true
    } else if tY < nY {
        return false
    }
    // tY == nY
    if tM > nM {
        return true
    } else if tM < nM {
        return false
    }
    // tM == nM
    if tD > nD {
        return true
    } else if tD < nD {
        return false
    }
    // tD == nD
    nH, nMinute, nS := now.Clock()
    tH, tMinute, tS := tm.Clock()
    if tH > nH {
        return true
    } else if tH < nH {
        return false
    }
    // tH == nH
    if tMinute > nMinute {
        return true
    } else if tMinute < nMinute {
        return false
    }
    // tMinute == nMinute
    if tS > nS {
        return  true
    }

    return false
}
smartwalle
smartwalle · #2 · 7年之前

建议楼主把时区信息也打印出来,就知道是怎么回事了

dosecin
dosecin · #3 · 7年之前
smartwallesmartwalle #2 回复

建议楼主把时区信息也打印出来,就知道是怎么回事了

此楼正解,楼主代码中time.Parse得到时区0的时间,time.Now得到东八区时间。建议time.Parse解析时加上时区

wangjieyanda
wangjieyanda · #4 · 7年之前

楼上正解。

Justin19960208
Justin19960208 · #5 · 7年之前

根据楼上的反馈,测试了下,好像是这样子的。又GET到新知识。 再贴个实现。

func IsTimeThrough(clockTime string) bool {
    tm, err := time.ParseInLocation("2006-01-02 15:04:05", clockTime, time.Now().Location())
    if err != nil {
        return false
    }

    if time.Now().Add(time.Minute * 10).Before(tm) {
        return true
    }

    return false
}
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传