当前位置: 首页 > 面试题库 >

time.Since()与月和年

游高杰
2023-03-14
问题内容

我正在尝试转换这样的时间戳:

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

自格式以来的某个时间,因此它会像9个月前1天2小时30分钟2秒。

这样的东西。

我用过time.Parsetime.Since达到以下目的:

6915h7m47.6901559s

但是我该如何转换呢?我是这样想的:

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

但这是一个问题,因为几个月可能会有28、30和31天,所以几个月不会准确。

有没有实现我想要的更好的方法?


问题答案:

前言:
我在中发布了此实用程序github.com/icza/gox,请参见timex.Diff()

就像一年中的日子(le年)一样,一个月中的日子取决于日期。

如果time.Since()用于获取自一个time.Time值以来的经过时间,或者time.Time使用该Time.Sub()方法计算两个值之间的差,则结果为a
time.Duration,它会丢失时间上下文(Duration正好是以纳秒为单位的时间差)。这意味着您不能根据一个Duration值准确无误地计算出年,月等的差异。

正确的解决方案必须在时间范围内计算差异。您可以计算每个字段(年,月,日,小时,分钟,秒)的差异,然后将结果归一化为没有任何负值。Time如果不期望它们之间的关系,也建议交换这些值。

归一化表示如果值是负数,则将该字段的最大值加1,然后将下一个字段减1。例如,如果seconds是负数,则将60其加减minutes1。例如,当归一化天数之差时要注意的一件事(每月的天数),则必须应用适当月份中的天数。这个小技巧很容易计算出:

// 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减去归一化后的天时,我们确切地得到了该月的最后一天。

时区处理:

仅当我们传递的两个时间值都在同一时区(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的年龄:

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.


 类似资料:
  • 2019 年 5 月和 6 月发布的 Adobe XD。 有关 Adobe XD 早期版本中推出的功能摘要,请参阅功能摘要 | 早期版本。 Adobe XD 是一款用于设计 Web 和移动应用程序用户体验以及为其构建原型的基于矢量的工具。轻松地在线框、视觉设计、交互设计、原型构建、预览和共享功能间进行切换 — 均可在一个功能强大的工具中实现。 XD 适合所有类型的创作者 — UX/UI 设计人员、

  • 本文向大家介绍php获取当前月与上个月月初及月末时间戳的方法,包括了php获取当前月与上个月月初及月末时间戳的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了php获取当前月与上个月月初及月末时间戳的方法。分享给大家供大家参考,具体如下: 当前月 上一月 这里对关键的就是date函数中的t,它是用来获取当前月所含天数的,28天,29天,30天,31天。含有多少天,月底就是多少号。 PS

  • 问题内容: 我正在尝试在一个包含带有日期的列(Oracle 11G)的模型中进行标准查询(JPA / Hibernate)。例如,我有 09年1月13日 09年1月15日 09年3月16日 我的功能就像: 如果我想按c =“ 01-JAN-09”进行过滤,则应返回: 09年1月13日 09年1月15日 任何帮助将不胜感激,在此先感谢。 问题答案: 您可以使用builder.function方法。例

  • 问题内容: 我有一张桌子,看起来像: 我想对过去3个月(不包括当月)的数量求和。我的where子句当前看起来像: 它有效,但丑陋和侮辱。关于使其更漂亮有什么建议吗?非常感谢! 问题答案: 没什么好… 但是,可以将嵌套的DATEADD用作计算列和索引列 这使

  • 我有一个JSON对象,它有几个日期,例如:15/12/2005或14/12/2012。 我需要将月份和日期与今天的月份和日期进行比较;年份无关紧要。我正在这样做: 这会选择日期,但返回2000-12-15。我只想要日期和月份。 什么时候会比较下一个方法 虽然当前日期匹配,但测试不通过。

  • 问题内容: 我正在尝试按 年 和 月 对表进行分区。我将通过其划分分区的列是具有ISO格式(‘20150110’,20150202’等)的日期时间类型列。 例如,我有2010年,2011年和2012年的销售数据。我希望数据按年份进行分区,并且每年也按月份进行分区。(2010/01,2010/02,… 2010/12,2011/01,… 2015/01 …) 前任: Sales2010Jan,Sal