今天碰到了要求两个日期间相差多少天,两个不同日期的,相差一秒都算一天.
标准库中没有相应的实现,自己写了个.
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)))
}