Warm tip: This article is reproduced from serverfault.com, please click

Date with Y=0, M=0, D=0 parsed to Nov 30 [Today]

发布于 2020-11-30 07:24:33

I have the below program to determine the date coming from a third party, sometimes the date is improper in this case I want to fail the comparison but somehow the date always grets parsed to today which returns a positive response.

import (
    "fmt"
    "time"
)

func main() {
    bday := time.Date(0, time.Month(0), 0, 0, 0, 0, 0, time.UTC)
    fmt.Print(bday)
}

The print from the main() is: -0001-11-30 00:00:00 +0000 UTC

Concerning for me is the DD and MM value which is converted to today, as this snippet I am using to check a users birthday.

Questioner
User3
Viewed
0
icza 2020-11-30 16:45:18

Foreword: The question was asked on November 30, that's why the month and day part seems like today.


Zero values are parsed properly, but there is no "Month 0". The first month is January which has numeric value 1. Similarly, there is no 0th day of month, the first day in every month is 1.

time.Date documents that:

The month, day, hour, min, sec, and nsec values may be outside their usual ranges and will be normalized during the conversion. For example, October 32 converts to November 1.

So if you pass 0 for month and day, that is interpreted the same as passing 1 to month and day, and adding -1 to each.

See this example:

bday := time.Date(0, time.Month(0), 0, 0, 0, 0, 0, time.UTC)
fmt.Println(bday)

bday2 := time.Date(0, time.Month(1), 1, 0, 0, 0, 0, time.UTC)
fmt.Println(bday2)
bday2 = bday2.AddDate(0, -1, -1)
fmt.Println(bday2)

Which outputs (try it on the Go Playground):

-0001-11-30 00:00:00 +0000 UTC
0000-01-01 00:00:00 +0000 UTC
-0001-11-30 00:00:00 +0000 UTC

So the result becoming "today" is purely by accident, today being November 30. If you run the code tomorrow, the month-day part will not be today anymore but yesterday.