V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Junjunya

go 语言时间比较,可以直接比较时间字符串????

  •  
  •   Junjunya · Mar 28, 2019 · 9278 views
    This topic created in 2594 days ago, the information mentioned may be changed or developed.

    看到同事这么写的时间比较

    if now < "2019-04-10 19:00:00" {
        result["isDo"] = 0
    }else if now > "2019-04-11 00:00:00"  {
        result["isDo"] = 2
    }else {
        result["isDo"] = 1
    }
    

    震惊了,居然可以这么写。自己试了下,可以比较

    但是网上搜索了一下,居然没找到相关的说明。想知道这样写的原理是什么

    19 replies    2019-03-29 09:36:37 +08:00
    www5070504
        1
    www5070504  
       Mar 28, 2019
    按 ascii 码逐个字符比较?
    dremy
        2
    dremy  
       Mar 28, 2019 via iPhone
    ascii 比较呗,肯定是能比的
    cpdyj0
        3
    cpdyj0  
       Mar 28, 2019
    没用过 Go,处理 ASCII 比较,会不会是运算符重载之类的?(不知道 Go 有没有这种东西)
    mengzhuo
        4
    mengzhuo  
       Mar 28, 2019
    字符比较,按 ascii,当然可以啦,效率嘛……比 time.Time 慢至少 2 倍多

    不过有些特殊情况就搞不定了,比如说两个不同时区的时间比较~(虽然国内程序员很少遇到)
    misaka19000
        5
    misaka19000  
       Mar 28, 2019
    某些情况下是能比较的,不过能写出这种代码的程序员水平也真是拙计
    liyunlong41
        6
    liyunlong41  
       Mar 28, 2019 via iPhone
    @mengzhuo 有 benchmarks 吗?很好奇为啥会慢
    pwrliang
        7
    pwrliang  
       Mar 28, 2019 via Android
    逐个字符比较呗,SQL 里经常这么写,感觉会比转换成日期类型还快
    Erskine
        8
    Erskine  
       Mar 28, 2019 via Android
    有才华 比解析一遍时间来的效率
    blankme
        9
    blankme  
       Mar 28, 2019 via Android
    @liyunlong41
    timestamp 比较只需要比一次数字,string 比较的话,一个一个字符比。。。
    petelin
        10
    petelin  
       Mar 28, 2019 via iPhone
    @blankme 难道不要计算构造 time 对象的花销?
    azh7138m
        11
    azh7138m  
       Mar 28, 2019
    @petelin 时间戳是个数字,直接比较,构建啥 time 对象?
    gamexg
        12
    gamexg  
       Mar 28, 2019   ❤️ 1
    package main

    import (
    "fmt"
    "time"
    )

    func main() {
    testData := "2006-01-02 15:04:05"

    nowStr := time.Now().Format("2006-01-02 15:04:05")
    f1 := func() bool {
    return testData > nowStr
    }

    f2 := func() bool {
    nowStr := time.Now().Format("2006-01-02 15:04:05")
    return testData > nowStr
    }

    f3 := func() bool {
    t, err := time.Parse("2006-01-02 15:04:05", testData)
    if err != nil {
    panic(err)
    }
    return time.Now().After(t)
    }

    T("字符串比较", f1)
    T("now 转换为字符串后和字符串比较", f2)
    T("字符串解析为 time 后比较", f3)

    }

    func T(name string, f func() bool) {
    s := time.Now()
    for i := 0; i < 1000000; i++ {
    f()
    }
    fmt.Printf("%v 耗时 %v\r\n", name, time.Now().Sub(s))
    }

    字符串比较 耗时 5.0145ms
    now 转换为字符串后和字符串比较 耗时 203.3878ms
    字符串解析为 time 后比较 耗时 190.563ms
    blankme
        13
    blankme  
       Mar 28, 2019   ❤️ 1
    @petelin
    其实要省时间可以把那串时间直接写成数字,然后边上注释一下
    (不过 9102 年了,干这种事没什么意义
    laminux29
        14
    laminux29  
       Mar 28, 2019   ❤️ 2
    [YYYY-MM-dd HH:mm:ss.fff] 格式的字符串,能进行比较的本质原因,是因为该字符串是一种 [进位数值系统] 。

    整数 123456 这种是以 10 作为进位的数值系统,它能进行比较。

    而 [YYYY-MM-dd HH:mm:ss.fff] 格式的字符串,也是进位的数值系统,只是它的进位是非固定的,比如时分位是右位 12 进 1,但月位却是右位 28、30、31 进 1。
    yippees
        15
    yippees  
       Mar 28, 2019
    now 也是 time.Now()转的吧,转换成数字比较更快吧
    如果涉及到金钱相关,跨个时区
    WilliamYang
        16
    WilliamYang  
       Mar 28, 2019
    这个时间格式本来就不带有时区, 当然可以这样比较啊
    skiy
        17
    skiy  
       Mar 28, 2019
    ...
    我一般是转成时间戳再比较的,我是不是做错了?
    wweir
        18
    wweir  
       Mar 29, 2019 via iPhone
    @skiy 那怎么转换成时间戳呢?不构建 time 对象生撸?
    mengzhuo
        19
    mengzhuo  
       Mar 29, 2019   ❤️ 1
    @blankme 并不是,Go 会用 AVX 并行优化这部分代码,而字符串时间是 19 个字节,19*8 = 152 < 256。一次比较就能得出结果。大概率是慢在内存加载上(懒得做分析了,摊手~

    @liyunlong41 嗯,有探索精神,可惜懒了点。
    我跑了跑,不是 2 倍( 100%),是~70%。

    差别嘛~自己看 objdump 吧

    ```
    func BenchmarkISOString(b *testing.B) {
    a := "2019-04-10 19:00:00"
    c := "2019-04-10 19:00:01"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    _ = a < c
    }
    }

    func BenchmarkTime(b *testing.B) {
    a := time.Now()
    c := time.Now().Add(time.Second)
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    _ = a.Before(c)
    }
    }


    goos: linux
    goarch: amd64
    BenchmarkISOString-12 200000000 6.68 ns/op
    BenchmarkISOString-12 200000000 6.71 ns/op
    BenchmarkISOString-12 200000000 6.55 ns/op
    BenchmarkTime-12 500000000 3.89 ns/op
    BenchmarkTime-12 500000000 4.07 ns/op
    BenchmarkTime-12 500000000 3.93 ns/op
    PASS
    ok _/root/hoho 13.189s
    ```
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1151 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 59ms · UTC 17:19 · PVG 01:19 · LAX 10:19 · JFK 13:19
    ♥ Do have faith in what you're doing.