我正在尝试转换这样的时间戳:
2015-06-27T09:34:22+00:00
自格式以来的某个时间,因此它会像9个月前1天2小时30分钟2秒。
这样的东西。
我用过time.Parse并time.Since达到以下目的:
time.Parse
time.Since
6915h7m47.6901559s
但是我该如何转换呢?我是这样想的:
for hours > 24 { days++ hours -= 24 }
但这是一个问题,因为几个月可能会有28、30和31天,所以几个月不会准确。
有没有实现我想要的更好的方法?
前言: 我在中发布了此实用程序github.com/icza/gox,请参见timex.Diff()。
github.com/icza/gox
timex.Diff()
就像一年中的日子(le年)一样,一个月中的日子取决于日期。
如果time.Since()用于获取自一个time.Time值以来的经过时间,或者time.Time使用该Time.Sub()方法计算两个值之间的差,则结果为a time.Duration,它会丢失时间上下文(Duration正好是以纳秒为单位的时间差)。这意味着您不能根据一个Duration值准确无误地计算出年,月等的差异。
time.Since()
time.Time
Time.Sub()
time.Duration
Duration
正确的解决方案必须在时间范围内计算差异。您可以计算每个字段(年,月,日,小时,分钟,秒)的差异,然后将结果归一化为没有任何负值。Time如果不期望它们之间的关系,也建议交换这些值。
Time
归一化表示如果值是负数,则将该字段的最大值加1,然后将下一个字段减1。例如,如果seconds是负数,则将60其加减minutes1。例如,当归一化天数之差时要注意的一件事(每月的天数),则必须应用适当月份中的天数。这个小技巧很容易计算出:
seconds
60
minutes
// Max days in year y1, month M1 t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC) daysInMonth := 32 - t.Day()
这背后的逻辑是,该天32大于任何月份的最大天数。它将自动归一化(额外的天数滚动到下个月,并且天数适当减少)。当我们从32减去归一化后的天时,我们确切地得到了该月的最后一天。
32
时区处理:
仅当我们传递的两个时间值都在同一时区(time.Location)时,差异计算才会给出正确的结果。我们将检查合并到函数中:如果不是这种情况,则使用以下Time.In()方法将时间值之一“转换”为与另一个时间值相同的位置:
time.Location
Time.In()
if a.Location() != b.Location() { b = b.In(a.Location()) }
这是一个计算年,月,日,小时,分钟,秒之间差异的解决方案:
func diff(a, b time.Time) (year, month, day, hour, min, sec int) { if a.Location() != b.Location() { b = b.In(a.Location()) } if a.After(b) { a, b = b, a } y1, M1, d1 := a.Date() y2, M2, d2 := b.Date() h1, m1, s1 := a.Clock() h2, m2, s2 := b.Clock() year = int(y2 - y1) month = int(M2 - M1) day = int(d2 - d1) hour = int(h2 - h1) min = int(m2 - m1) sec = int(s2 - s1) // Normalize negative values if sec < 0 { sec += 60 min-- } if min < 0 { min += 60 hour-- } if hour < 0 { hour += 24 day-- } if day < 0 { // days in month: t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC) day += 32 - t.Day() month-- } if month < 0 { month += 12 year-- } return }
一些测试:
var a, b time.Time a = time.Date(2015, 5, 1, 0, 0, 0, 0, time.UTC) b = time.Date(2016, 6, 2, 1, 1, 1, 1, time.UTC) fmt.Println(diff(a, b)) // Expected: 1 1 1 1 1 1 a = time.Date(2016, 1, 2, 0, 0, 0, 0, time.UTC) b = time.Date(2016, 2, 1, 0, 0, 0, 0, time.UTC) fmt.Println(diff(a, b)) // Expected: 0 0 30 0 0 0 a = time.Date(2016, 2, 2, 0, 0, 0, 0, time.UTC) b = time.Date(2016, 3, 1, 0, 0, 0, 0, time.UTC) fmt.Println(diff(a, b)) // Expected: 0 0 28 0 0 0 a = time.Date(2015, 2, 11, 0, 0, 0, 0, time.UTC) b = time.Date(2016, 1, 12, 0, 0, 0, 0, time.UTC) fmt.Println(diff(a, b)) // Expected: 0 11 1 0 0 0
输出是预期的:
1 1 1 1 1 1 0 0 30 0 0 0 0 0 28 0 0 0 0 11 1 0 0 0
在Go Playground上尝试一下。
要计算您的年龄,请执行以下操作:
// Your birthday: let's say it's January 2nd, 1980, 3:30 AM birthday := time.Date(1980, 1, 2, 3, 30, 0, 0, time.UTC) year, month, day, hour, min, sec := diff(birthday, time.Now()) fmt.Printf("You are %d years, %d months, %d days, %d hours, %d mins and %d seconds old.", year, month, day, hour, min, sec)
输出示例:
You are 36 years, 3 months, 8 days, 11 hours, 57 mins and 41 seconds old.
Go游乐场时间开始的不可思议的日期/时间是:2009-11-10 23:00:00 UTC 这是Go首次宣布的时间。让我们计算Go的年龄:
2009-11-10 23:00:00 UTC
goAnnounced := time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC) year, month, day, hour, min, sec := diff(goAnnounced, time.Now()) fmt.Printf("Go was announced "+ "%d years, %d months, %d days, %d hours, %d mins and %d seconds ago.", year, month, day, hour, min, sec)
输出:
Go was announced 6 years, 4 months, 29 days, 16 hours, 53 mins and 31 seconds ago.