为什么我在Golang的Date函数中得到错误答案

为什么我在Golang的Date函数中得到错误答案

问题描述:

In the following code,

  • t1 is time on 62 days after the date 1970/1/1 (yy/mm/dd)
  • t2 is time on 63 days after the date 1970/1/1 (yy/mm/dd)

package main

import (
    "fmt"
    "time"
)

func main() {

    t1 := time.Date(0, 0, 62, 0, 0, 0, 0, time.UTC).AddDate(1970, 1, 1)
    t2 := time.Date(0, 0, 63, 0, 0, 0, 0, time.UTC).AddDate(1970, 1, 1)

    fmt.Println("Time1:  ", t1)
    fmt.Println("Time2:  ", t2)
}

If t1 is:

Time1: 1970-03-04 00:00:00 +0000 UTC

I expect t2 to be:

Time2: 1970-03-05 00:00:00 +0000 UTC

But the output is:

Time2: 1970-03-02 00:00:00 +0000 UTC

What is the reason for this?

在以下代码中, p>

  • t1是时间 1970年1月1日(yy / mm / dd)之后62天的时间 li>
  • t2是1970年1月1日(yy / mm / dd)之后63天的时间 li> ul>
     包main 
     
    import(
    “ fmt” 
    “ time” 
    )
     
    func main  (){
     
     t1:= time.Date(0,0,62,0,0,0,0,time.UTC).AddDate(1970,1,1)
     t2:= time.Date(  0,0,63,0,0,0,0,time.UTC).AddDate(1970,1,1)
     
     fmt.Println(“ Time1:”,t1)
     fmt.Println(“ Time2  :“,t2)
    } 
      code>  pre> 
     
     

    如果t1为: p>

     时间1:1970-03-04  00:00:00 +0000 UTC 
      code>  pre> 
     
     

    我希望t2为: p>

      Time2:1970-03  -05 00:00:00 +0000 UTC 
      code>  pre> 
     
     

    但输出为: p>

      Time2:1970-  03-02 00:00:00 +0000 UTC 
      code>  pre> 
     
     

    这是什么原因? p> div>

t1 is time on 62 days after the date 1970/1/1 (yy/mm/dd) t2 is time on 63 days after the date 1970/1/1 (yy/mm/dd)

This is not true. t1 is the time 1970 years, 1 month and 1 day after whatever time.Date(0, 0, 62, 0, 0, 0, 0, time.UTC) means.

fmt.Println(time.Date(0, 0, 62, 0, 0, 0, 0, time.UTC))
fmt.Println(time.Date(0, 0, 63, 0, 0, 0, 0, time.UTC))

gives us:

0000-01-31 00:00:00 +0000 UTC
0000-02-01 00:00:00 +0000 UTC

This is completely wrong. UTC isn't defined for any dates before 1972, the Gregorian calendar doesn't start until 1582 and there was never any year 0. Ignoring all that, I don't see how day 63 of a year could be interpreted as January 31st, but let's go with it anyway.

Let's add things to the first timestamp: add 1970, we get 1970-01-31. Add a month, we get 1970-02-31. But 1970-02-31 isn't a valid date. So it is normalized to March 3rd. 1970 wasn't a leap year, February had 28 days, so Feb 29 is Mar 1, Feb 30 is Mar 2, Feb 31 is Mar 3. Add one day to 1970-03-03 and we get 1970-03-04.

The second timestamp already parses to February 1st. Add a month and we get March 1st, add a day and we get March 2nd.

This is what happens when you add months to timestamps. A month is not a very well defined duration. So the library tries to be clever for you and that gets you unexpected results.

Btw. for some reason: fmt.Println(time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)) is interpreted as -0001-11-30 00:00:00 +0000 UTC. No idea why. Doesn't really matter since year 0 and month 0 don't exist. But it explains why the earlier timestamps end up at Jan 31st and Feb 1st.

There is no reason for AddDate to add things in this order. It is not documented as far as I can see. It could as well have added the day first, then the month, then the years. Try running this:

fmt.Println(time.Date(2015, 1, 31, 0, 0, 0, 0, time.UTC).AddDate(1, 0, 0).AddDate(0, 1, 0))
fmt.Println(time.Date(2015, 1, 31, 0, 0, 0, 0, time.UTC).AddDate(0, 1, 0).AddDate(1, 0, 0))