time.Since() with months and years

huangapple go评论75阅读模式
英文:

time.Since() with months and years

问题

我正在尝试将一个类似这样的时间戳转换为时间差格式,比如说9个月前1天2小时30分钟2秒钟。我使用了time.Parsetime.Since得到了这个结果:6915小时7分钟47.6901559秒。但是我该如何继续转换呢?我想到了以下的方法:

for hours > 24 {
    days++
    hours -= 24
}

但是这种方法存在问题,因为对于月份来说,这样的计算不准确,因为月份可能有28、30和31天。有没有更好的方法来实现我想要的效果呢?

英文:

I am trying to convert a timestamp like this:

2015-06-27T09:34:22+00:00

to a time since format so it would say like 9 months ago 1 day 2 hours 30 minutes 2 seconds.

something like that.

I used time.Parse and time.Since to get to this:

6915h7m47.6901559s

But how do I convert from there on? Something like this is what I thought:

for hours > 24 {
		days++
		hours -= 24
}

But the issue with this is that this won't be accurate for months because months can have 28, 30 and 31 days.

Is there a better way of achieving what I want?

答案1

得分: 59

**前言:**我在github.com/icza/gox发布了这个实用程序,请参阅timex.Diff()


一个月的天数取决于日期,就像一年的天数(闰年)一样。

如果你使用time.Since()获取自time.Time值以来的经过时间,或者当你计算两个time.Time值之间的差异时使用Time.Sub()方法,结果是一个time.Duration,它丢失了时间上下文(因为Duration只是以纳秒为单位的时间差)。这意味着你无法准确且明确地从Duration值中计算出年、月等的差异。

正确的解决方案必须在时间的上下文中计算差异。你可以为每个字段(年、月、日、小时、分钟、秒)计算差异,然后将结果归一化,以消除任何负值。如果两个时间之间的关系不是预期的关系,建议交换这两个Time值。

归一化意味着如果一个值是负数,就加上该字段的最大值,并将下一个字段减1。例如,如果seconds是负数,就加上60,并将minutes减1。需要注意的一点是,在归一化天数差异(月中的天数)时,必须应用正确月份的天数。可以使用以下小技巧轻松计算出这个值:

// year y1, month M1中的最大天数
t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
daysInMonth := 32 - t.Day()

这个逻辑的背后是,第32天大于任何一个月的最大天数。它会自动归一化(多余的天数滚动到下个月,并适当地减少天数)。当我们用32减去归一化后的天数时,我们得到的正好是该月的最后一天。

时区处理:

只有当我们传入的两个时间值在相同的时区(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)

	// 归一化负值
	if sec < 0 {
		sec += 60
		min--
	}
	if min < 0 {
		min += 60
		hour--
	}
	if hour < 0 {
		hour += 24
		day--
	}
	if day < 0 {
		// 月中的天数:
		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)) // 期望输出: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)) // 期望输出: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)) // 期望输出: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)) // 期望输出: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上试一试。

计算你的年龄:

// 你的生日:假设是1980年1月2日,上午3点30分
birthday := time.Date(1980, 1, 2, 3, 30, 0, 0, time.UTC)
year, month, day, hour, min, sec := diff(birthday, time.Now())

fmt.Printf("你已经活了%d年%d个月%d天%d小时%d分钟%d秒。",
	year, month, day, hour, min, sec)

示例输出:

你已经活了36年3个月8天11小时57分钟41秒。

Go Playground的时间起始魔法日期/时间是:2009-11-10 23:00:00 UTC
这是Go首次宣布的时间。让我们计算Go的年龄:

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宣布已经%d年%d个月%d天%d小时%d分钟%d秒。",
	year, month, day, hour, min, sec)

输出:

Go宣布已经6年4个月29天16小时53分钟31秒。
英文:

Foreword: I released this utility in github.com/icza/gox, see timex.Diff().


The days in a month depends on the date, just like the days in a year (leap years).

If you use time.Since() to get the elapsed time since a time.Time value, or when you calculate the difference between 2 time.Time values using the Time.Sub() method, the result is a time.Duration which loses the time context (as Duration is just the time difference in nanoseconds). This means you cannot accurately and unambiguously calculate the difference in years, months, etc. from a Duration value.

The right solution must calculate the difference in the context of the time. You may calculate the difference for each field (year, month, day, hour, minute, second), and then normalize the result to not have any negative values. It is also recommended to swap the Time values if the relation between them is not the expected.

Normalization means if a value is negative, add the maximum value of that field and decrement the next field by 1. For example if seconds is negative, add 60 to it and decrement minutes by 1. One thing to look out for is when normalizing the difference of days (days in month), the number of days in the proper month has to be applied. This can easily be calculated with this little trick:

// Max days in year y1, month M1
t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
daysInMonth := 32 - t.Day()

The logic behind this is that the day 32 is bigger than the max day in any month. It will get automatically normalized (extra days rolled to the next month and day decremented properly). And when we subtract day we have after normalization from 32, we get exactly what the last day was in the month.

Time zone handling:

The difference calculation will only give correct result if both of the time values we pass in are in the same time zone (time.Location). We incorporate a check into our function: if this is not the case, we "convert" one of the time value to be in the same location as the other using the Time.In() method:

if a.Location() != b.Location() {
	b = b.In(a.Location())
}

Here's a solution which calculates difference in year, month, day, hour, min, sec:

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 &lt; 0 {
		sec += 60
		min--
	}
	if min &lt; 0 {
		min += 60
		hour--
	}
	if hour &lt; 0 {
		hour += 24
		day--
	}
	if day &lt; 0 {
		// days in month:
		t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
		day += 32 - t.Day()
		month--
	}
	if month &lt; 0 {
		month += 12
		year--
	}

	return
}

Some tests:

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

Output is as expected:

1 1 1 1 1 1
0 0 30 0 0 0
0 0 28 0 0 0
0 11 1 0 0 0

Try it on the Go Playground.

To calculate how old you are:

// Your birthday: let&#39;s say it&#39;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(&quot;You are %d years, %d months, %d days, %d hours, %d mins and %d seconds old.&quot;,
	year, month, day, hour, min, sec)

Example output:

You are 36 years, 3 months, 8 days, 11 hours, 57 mins and 41 seconds old.

The magic date/time at which the Go playground time starts is: 2009-11-10 23:00:00 UTC
This is the time when Go was first announced. Let's calculate how old Go is:

goAnnounced := time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)
year, month, day, hour, min, sec := diff(goAnnounced, time.Now())
fmt.Printf(&quot;Go was announced &quot;+
	&quot;%d years, %d months, %d days, %d hours, %d mins and %d seconds ago.&quot;,
	year, month, day, hour, min, sec)

Output:

Go was announced 6 years, 4 months, 29 days, 16 hours, 53 mins and 31 seconds ago.

答案2

得分: 5

izca提出的解决方案很好,但是它缺少一点。如果你添加以下示例,你可以看到效果:

a = time.Date(2015, 1, 11, 0, 0, 0, 0, time.UTC)
b = time.Date(2015, 3, 10, 0, 0, 0, 0, time.UTC)
fmt.Println(diff(a, b))
// 期望输出: 0 1 27 0 0 0
// 实际输出: 0 1 30 0 0 0

代码计算的是基于第一个月的总天数(y1,M1)的下一个不完整月份的剩余天数,但是它需要从后一个日期的前一个月份(y2,M2-1)计算。

最终的代码如下:

package main

import (
	"fmt"
	"time"
)

func DaysIn(year int, month time.Month) int {
	return time.Date(year, month, 0, 0, 0, 0, 0, time.UTC).Day()
}

func Elapsed(from, to time.Time) (inverted bool, years, months, days, hours, minutes, seconds, nanoseconds int) {
	if from.Location() != to.Location() {
		to = to.In(to.Location())
	}

	inverted = false
	if from.After(to) {
		inverted = true
		from, to = to, from
	}

	y1, M1, d1 := from.Date()
	y2, M2, d2 := to.Date()

	h1, m1, s1 := from.Clock()
	h2, m2, s2 := to.Clock()

	ns1, ns2 := from.Nanosecond(), to.Nanosecond()

	years = y2 - y1
	months = int(M2 - M1)
	days = d2 - d1

	hours = h2 - h1
	minutes = m2 - m1
	seconds = s2 - s1
	nanoseconds = ns2 - ns1

	if nanoseconds < 0 {
		nanoseconds += 1e9
		seconds--
	}
	if seconds < 0 {
		seconds += 60
		minutes--
	}
	if minutes < 0 {
		minutes += 60
		hours--
	}
	if hours < 0 {
		hours += 24
		days--
	}
	if days < 0 {
		days += DaysIn(y2, M2-1)
		months--
	}
	if days < 0 {
		days += DaysIn(y2, M2)
		months--
	}
	if months < 0 {
		months += 12
		years--
	}
	return
}

func main() {
	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(Elapsed(a, b)) // 期望输出: 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(Elapsed(a, b)) // 期望输出: 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(Elapsed(a, b)) // 期望输出: 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(Elapsed(a, b)) // 期望输出: 0 11 1 0 0 0

	a = time.Date(2015, 1, 11, 0, 0, 0, 0, time.UTC)
	b = time.Date(2015, 3, 10, 0, 0, 0, 0, time.UTC)
	fmt.Println(Elapsed(a, b)) // 期望输出: 0 1 27 0 0 0

	a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
	b = time.Date(2015, 3, 1, 0, 0, 0, 0, time.UTC)
	fmt.Println(Elapsed(a, b)) // 期望输出: 0 9 30 0 0 0

	a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
	b = time.Date(2016, 3, 1, 0, 0, 0, 0, time.UTC)
	fmt.Println(Elapsed(a, b)) // 期望输出: 0 2 1 0 0 0

	a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
	b = time.Date(2016, 2, 28, 0, 0, 0, 0, time.UTC)
	fmt.Println(Elapsed(a, b)) // 期望输出: 0 2 1 0 0 0
}
英文:

The solution proposed by izca is great, but it misses one thing. If you add the following example, you can see the effect:

a = time.Date(2015, 1, 11, 0, 0, 0, 0, time.UTC)
b = time.Date(2015, 3, 10, 0, 0, 0, 0, time.UTC)
fmt.Println(diff(a, b))
// Expected: 0 1 27 0 0 0
// Actual output: 0 1 30 0 0 0

<kbd>playground</kbd>

The code is calculating the remaining days of the next incomplete month based on the total days of the first month (y1,M1), but it needs to be computed from the previous month of the later date month (y2,M2-1).

The final code is as follows:

package main
import (
&quot;fmt&quot;
&quot;time&quot;
)
func DaysIn(year int, month time.Month) int {
return time.Date(year, month, 0, 0, 0, 0, 0, time.UTC).Day()
}
func Elapsed(from, to time.Time) (inverted bool, years, months, days, hours, minutes, seconds, nanoseconds int) {
if from.Location() != to.Location() {
to = to.In(to.Location())
}
inverted = false
if from.After(to) {
inverted = true
from, to = to, from
}
y1, M1, d1 := from.Date()
y2, M2, d2 := to.Date()
h1, m1, s1 := from.Clock()
h2, m2, s2 := to.Clock()
ns1, ns2 := from.Nanosecond(), to.Nanosecond()
years = y2 - y1
months = int(M2 - M1)
days = d2 - d1
hours = h2 - h1
minutes = m2 - m1
seconds = s2 - s1
nanoseconds = ns2 - ns1
if nanoseconds &lt; 0 {
nanoseconds += 1e9
seconds--
}
if seconds &lt; 0 {
seconds += 60
minutes--
}
if minutes &lt; 0 {
minutes += 60
hours--
}
if hours &lt; 0 {
hours += 24
days--
}
if days &lt; 0 {
days += DaysIn(y2, M2-1)
months--
}
if days &lt; 0 {
days += DaysIn(y2, M2)
months--
}
if months &lt; 0 {
months += 12
years--
}
return
}
func main() {
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(Elapsed(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(Elapsed(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(Elapsed(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(Elapsed(a, b)) // Expected: 0 11 1 0 0 0
a = time.Date(2015, 1, 11, 0, 0, 0, 0, time.UTC)
b = time.Date(2015, 3, 10, 0, 0, 0, 0, time.UTC)
fmt.Println(Elapsed(a, b)) // Expected: 0 1 27 0 0 0
a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
b = time.Date(2015, 3, 1, 0, 0, 0, 0, time.UTC)
fmt.Println(Elapsed(a, b)) // Expected: 0 9 30 0 0 0
a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 3, 1, 0, 0, 0, 0, time.UTC)
fmt.Println(Elapsed(a, b)) // Expected: 0 2 1 0 0 0
a = time.Date(2015, 12, 31, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 2, 28, 0, 0, 0, 0, time.UTC)
fmt.Println(Elapsed(a, b)) // Expected: 0 2 1 0 0 0
}

<kbd>playground</kbd>

答案3

得分: 3

如果您使用PostgreSQL,可以使用age函数轻松获取结果。

假设您有两个日期ab

像icza所说的那样,请注意,ab必须处于相同的时区。

首先,您可以使用两个参数调用age,在您的情况下是日期a和日期b。该函数返回一个间隔类型,其中包含年、月、周、天、小时、分钟、秒和毫秒。

SELECT age('2016-03-31', '2016-06-30'); -- 结果为:-2 mons -30 days

第二种可能性是使用带有一个参数的age函数。结果也是一个间隔,但在这种情况下,age从当前日期(午夜)开始减去。假设今天是2016/06/16:

SELECT age(timestamp '2016-06-30'); -- 结果为:-14 days

注意,需要使用timestamp关键字来转换日期'2016-06-30'。

要获取更多详细信息,您可以使用date_part或直接使用返回一个特定字段(年、月、日等)的extract函数。

SELECT date_part('month', age('2016-03-31', '2016-06-30')); -- 结果为:-2
SELECT date_part('day',   age('2016-03-31', '2016-06-30')); -- 结果为:-30

完整的查询:

SELECT  
date_part('year', diff) as year
, date_part('month', diff) as month
, date_part('day', diff) as day
FROM (
SELECT age(timestamp '2016-06-30') AS diff
) as qdiff;
-- 结果为: 
-- year	month day
-- 0	0	  -14

(使用CTE - 公共表达式):

WITH qdiff AS (
SELECT age(timestamp '2016-06-30') AS diff
)
SELECT  
date_part('year', diff) as year
, date_part('month', diff) as month
, date_part('day', diff) as day
FROM qdiff
-- 结果为: 
-- year	month day
-- 0	0	  -14

PostgreSQL文档(当前版本):https://www.postgresql.org/docs/current/static/functions-datetime.html

英文:

If you use PostgreSQL, you can easily get the result with age function.

Suppose you have two dates a and b.

Like icza said, be careful, a and b must be in the same time zone.

First, you can invoke age with two parameters, in your case date a and date b. This function return a interval type that contains years, months, weeks, days, hours, minutes, seconds, and milliseconds.

SELECT age(&#39;2016-03-31&#39;, &#39;2016-06-30&#39;); -- result is: -2 mons -30 days

The second possibilty is to use age function with one parameter. The result is a interval too but in this case, age subtract from current_date (at midnight). Suppose today is 2016/06/16:

SELECT age(timestamp &#39;2016-06-30&#39;); -- result is: -14 days

Note, timestamp keyword is needed to cast the date '2016-06-30'.

For more details, you can use date_part or directly extract function that return one specific field (years, months, days...).

SELECT date_part(&#39;month&#39;, age(&#39;2016-03-31&#39;, &#39;2016-06-30&#39;)); --result is: -2
SELECT date_part(&#39;day&#39;,   age(&#39;2016-03-31&#39;, &#39;2016-06-30&#39;)); --result is: -30

Full request:

SELECT  
date_part(&#39;year&#39;, diff) as year
, date_part(&#39;month&#39;, diff) as month
, date_part(&#39;day&#39;, diff) as day
FROM (
SELECT age(timestamp &#39;2016-06-30&#39;) AS diff
) as qdiff;
-- result is: 
-- year	month day
-- 0	0	  -14

(with CTE - Common Table Expression):

WITH qdiff AS (
SELECT age(timestamp &#39;2016-06-30&#39;) AS diff
)
SELECT  
date_part(&#39;year&#39;, diff) as year
, date_part(&#39;month&#39;, diff) as month
, date_part(&#39;day&#39;, diff) as day
FROM qdiff
-- result is: 
-- year	month day
-- 0	0	  -14

PostgreSQL documentation (current version): https://www.postgresql.org/docs/current/static/functions-datetime.html

答案4

得分: 2

以下是翻译好的内容:

func main() {
    a := time.Date(2015, 10, 15, 0, 0, 0, 0, time.UTC)
    b := time.Date(2016, 11, 15, 0, 0, 0, 0, time.UTC)
    fmt.Println(monthYearDiff(a, b))
}

func monthYearDiff(a, b time.Time) (years, months int) {
    m := a.Month()
    for a.Before(b) {
        a = a.Add(time.Hour * 24)
        m2 := a.Month()
        if m2 != m {
            months++
        }
        m = m2
    }
    years = months / 12
    months = months % 12
    return
}

playground

英文:

Something like this would work, probably not the most efficient but it is as accurate as you gonna get:

func main() {
a := time.Date(2015, 10, 15, 0, 0, 0, 0, time.UTC)
b := time.Date(2016, 11, 15, 0, 0, 0, 0, time.UTC)
fmt.Println(monthYearDiff(a, b))
}
func monthYearDiff(a, b time.Time) (years, months int) {
m := a.Month()
for a.Before(b) {
a = a.Add(time.Hour * 24)
m2 := a.Month()
if m2 != m {
months++
}
m = m2
}
years = months / 12
months = months % 12
return
}

<kbd>playground</kbd>

答案5

得分: 2

你可以尝试使用我的date包,其中包括用于处理ISO风格时间段的period包(维基百科)。

Period类型带有一个格式化程序,可以理解复数形式,打印可读的字符串,例如"9 years, 2 months"和"3 hours, 4 minutes, 1 second",以及ISO等效形式" P9Y2M"和"PT3H4M1S"。

由于日期的可变长度(由于夏令时)和月份(由于公历),时间段当然是棘手的。period包试图通过提供一个API来帮助您进行精确和不精确的计算。对于短时间段(最多±3276小时),它能够精确地转换为持续时间。

duration := time.Since(...)
p, _ := period.NewOf(duration)
str := p.String()

如果您需要更长时间跨度的精确持续时间,您需要使用Between函数(体现了icza的出色答案)。

p := period.Between(t1, t2)
str := p.String()
英文:

You could try working with my date package, which includes the period package for working with ISO-style periods of time (Wikipedia).

The Period type comes with a formatter that understands plurals, printing readable strings such as "9 years, 2 months" and "3 hours, 4 minutes, 1 second", along with the ISO equivalents ("P9Y2M" and "PT3H4M1S").

Periods are, of course, tricky due to the variable lengths of days (due to DST) and months (due to the Gregorian calendar). The period package tries to help you by providing an API that allows both precise and imprecise calculations. For short periods (up to ±3276 hours) it is able to convert a Duration precisely.

duration := time.Since(...)
p, _ := period.NewOf(duration)
str := p.String()

If you need precise durations over longer spans, you need to use the Between function (which embody icza's excellent answer).

p := period.Between(t1, t2)
str := p.String()

huangapple
  • 本文由 发表于 2016年4月10日 21:16:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/36530251.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定