Go time 包中的 AddDate 的逻辑避坑指南


本文摘自网络,作者,侵删。

从 C++ 转 Go 后,当操作时间变量的时候,Go 原生的 time 包用起来简直不要太舒服,再也不用自己写轮子了。我之前就写过一篇文章介绍了 time 的常用用法。

不过在开发过程中其实也遇到 time 在 AddDate 的一个坑,因此撰此薄文分享一下。

问题发现

AddDate 有三个参数,分别是年、月、日。在官方文档中,对 time.AddDate 方法的说明如下:

AddDate returns the time corresponding to adding the given number of years, months, and days
to t. For example, AddDate(-1, 2, 3) applied to January 1, 2011 returns March 4, 2010.

AddDate normalizes its result in the same way that Date does, so, for example, adding one
month to October 31 yields December 1, the normalized form for November 31.

简单翻译一下:

  • AddDate 根据指定的年、月、日数字,加到原来的 time 类型值上并返回。比如对于 2011-1-1 这个日期,执行 AddDate(-1, 2, 3) 会返回 2010-3-4
  • AddDate 将它的结果按实际日期进行标准化,所以,比如在10月31日加上一个月,会返回12月1日,而不是11月31日。

上文解释的第二段就是坑所在:AddDate 函数中,year 参数等于 365 天,month 参数等于 30 天。实际上,在日常生活中,如果真有一个人在10月31日说:“下个月”(AddDate(0, 1, 0)),大部分人会理解为11月30日,而不是官方例子给出的12月1日!

问题解决

其实问题的解决也不难,首先确立以下逻辑:

  • 优先按照年、月、日的顺序来调整日期
  • 增减年份时,直接调整年份字段,不影响月和日
  • 增减月份时,首先调整月份字段,如果日字段在调整后依然合法,则不调整
  • 如果增减之后的日期不合法(当月不存在本日),则直接将日改为当月的最后一天
  • 剩余的日数,则直接使用原生的 AddDate 逻辑计算即可。

好了,不用自己写轮子了,我已经造好了这样的一个轮子,timeconv,实现了 AddDate 函数如下:

package main

import (
    "fmt"
    "time"
    "github.com/Andrew-M-C/go.timeconv"
)

func main() {
    t := time.Date(2019, 1, 31, 0, 0, 0, 0, time.UTC)   // 2019-01-31

    nt := t.AddDate(0, 1, 0)    // 后推一个月
    fmt.Printf("%v\n", nt)        // 2019-03-03 00:00:00 +0000 UTC, 不是我们想要的

    nt = timeconv.AddDate(t, 0, 1, 0)
    fmt.Printf("%v\n", nt)        // 2019-02-28 00:00:00 +0000 UTC,这就对了
}

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原作者: amc,欢迎转载,但请注明出处。

原文标题:《Go time 包中的 AddDate 的逻辑避坑指南》

发布日期:2021-03-24

本文链接:https://segmentfault.com/a/1190000039701631

原文链接:https://cloud.tencent.com/developer/article/1803695,也是本人的博客


本文来自:Segmentfault

感谢作者:amc

查看原文:Go time 包中的 AddDate 的逻辑避坑指南

相关阅读 >>

手撸Golang Go与微服务 chatserver之4 内存泄漏

Go写的第一个小程序记账系统,来啦

关于在c++中结构体与json字符串互转的问题

Go orm 干啥的?

Go语言 continue 语句

以下两个函数执行结果一样嘛? 为什么

Go 语言环境安装

n皇后问题(Go版本)

手撸Golang 仿spring ioc/aop 之6 扫码1

[系列] - Go-gin-api 路由中间件 - 签名验证(七)

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...