golang 获取AB两个日期相差多少天

今天碰到了要求两个日期间相差多少天,两个不同日期的,相差一秒都算一天.
标准库中没有相应的实现,自己写了个.

func timeSubDays(t1, t2 time.Time) int {

    if t1.Location().String() != t2.Location().String() {
        return -1
    }
    hours := t1.Sub(t2).Hours()

    if hours <= 0 {
        return -1
    }
    // sub hours less than 24
    if hours < 24 {
        // may same day
        t1y, t1m, t1d := t1.Date()
        t2y, t2m, t2d := t2.Date()
        isSameDay := (t1y == t2y && t1m == t2m && t1d == t2d)

        if isSameDay {

            return 0
        } else {
            return 1
        }

    } else { // equal or more than 24

        if (hours/24)-float64(int(hours/24)) == 0 { // just 24's times
            return int(hours / 24)
        } else { // more than 24 hours
            return int(hours/24) + 1
        }
    }

}

test,直接在main中写的

layout := "2006-01-02 15:04:05"

    // just one second
    t1, _ := time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ := time.Parse(layout, "2007-01-03 00:00:00")
    if timeSub(t2, t1) != 1 {
        panic("one second but different day should return 1")
    }

    // just one day
    t1, _ = time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ = time.Parse(layout, "2007-01-03 23:59:59")
    if timeSub(t2, t1) != 1 {
        panic("just one day should return 1")
    }

    // more than one day
    t1, _ = time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ = time.Parse(layout, "2007-01-04 00:00:00")
    if timeSub(t2, t1) != 2 {
        panic("just one day should return 2")
    }
    // just 3 day
    t1, _ = time.Parse(layout, "2007-01-02 00:00:00")
    t2, _ = time.Parse(layout, "2007-01-05 00:00:00")
    if timeSub(t2, t1) != 3 {
        panic("just 3 day should return 3")
    }

    // different month
    t1, _ = time.Parse(layout, "2007-01-02 00:00:00")
    t2, _ = time.Parse(layout, "2007-02-02 00:00:00")
    if timeSub(t2, t1) != 31 {
        fmt.Println(timeSub(t2, t1))
        panic("just one month:31 days should return 31")
    }

    // 29 days in 2mth
    t1, _ = time.Parse(layout, "2000-02-01 00:00:00")
    t2, _ = time.Parse(layout, "2000-03-01 00:00:00")
    if timeSub(t2, t1) != 29 {
        fmt.Println(timeSub(t2, t1))
        panic("just one month:29 days should return 29")
    }

更正修订

经2楼空灵一月指出,上面的代码有逻辑错误,而且写的时候是参照另外一个人代码写的。现用time.Truncate 和 Time.Sub来做,测试追加2楼的case,如下:

package test

import (
    "fmt"
    "testing"
    "time"
)

func timeSub(t1, t2 time.Time) int {
    t1 = t1.UTC().Truncate(24 * time.Hour)
    t2 = t2.UTC().Truncate(24 * time.Hour)
    return int(t1.Sub(t2).Hours() / 24)
}

func TestTime(t *testing.T) {
    layout := "2006-01-02 15:04:05"

    // just one second
    t1, _ := time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ := time.Parse(layout, "2007-01-03 00:00:00")
    if timeSub(t2, t1) != 1 {
        panic("one second but different day should return 1")
    }

    // just one day
    t1, _ = time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ = time.Parse(layout, "2007-01-03 23:59:59")
    if timeSub(t2, t1) != 1 {
        panic("just one day should return 1")
    }

    t1, _ = time.Parse(layout, "2017-09-01 10:00:00")
    t2, _ = time.Parse(layout, "2017-09-02 11:00:00")
    if timeSub(t2, t1) != 1 {
        panic("just one day should return 1")
    }

    // more than one day
    t1, _ = time.Parse(layout, "2007-01-02 23:59:59")
    t2, _ = time.Parse(layout, "2007-01-04 00:00:00")
    if timeSub(t2, t1) != 2 {
        panic("just one day should return 2")
    }
    // just 3 day
    t1, _ = time.Parse(layout, "2007-01-02 00:00:00")
    t2, _ = time.Parse(layout, "2007-01-05 00:00:00")
    if timeSub(t2, t1) != 3 {
        panic("just 3 day should return 3")
    }

    // different month
    t1, _ = time.Parse(layout, "2007-01-02 00:00:00")
    t2, _ = time.Parse(layout, "2007-02-02 00:00:00")
    if timeSub(t2, t1) != 31 {
        fmt.Println(timeSub(t2, t1))
        panic("just one month:31 days should return 31")
    }

    // 29 days in 2mth
    t1, _ = time.Parse(layout, "2000-02-01 00:00:00")
    t2, _ = time.Parse(layout, "2000-03-01 00:00:00")
    if timeSub(t2, t1) != 29 {
        fmt.Println(timeSub(t2, t1))
        panic("just one month:29 days should return 29")
    }
}

再次更正修订
frfluter 指出个bug,Truncate方法用的是绝对时间,如果给出的时间为本地时间,会存在时区,会出现不同时间化为同一天的情况

func timeSub(t1, t2 time.Time) int {
    t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
    t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)

    return int(t1.Sub(t2).Hours() / 24)
}

新增测试case:
    t1 = time.Date(2018, 1, 10, 0, 0, 1, 100, time.Local)
    t2 = time.Date(2018, 1, 9, 23, 59, 22, 100, time.Local)
    if timeSub(t1, t2) != 1 {
        panic(fmt.Sprintf("just one day: should return 1 but got %v", timeSub(t1, t2)))
    }

    t1 = time.Date(2018, 1, 10, 0, 0, 1, 100, time.UTC)
    t2 = time.Date(2018, 1, 9, 23, 59, 22, 100, time.UTC)
    if timeSub(t1, t2) != 1 {
        panic(fmt.Sprintf("just one day: should return 1 but got %v", timeSub(t1, t2)))
    }
    原文作者:大漠狼道
    原文地址: https://www.jianshu.com/p/b2efbe971105
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞