Подтвердить что ты не робот

Почему я получаю неправильные ответы в функции Date в golang

В следующем коде

  • t1 - время через 62 дня после даты 1970/1/1 (yy/mm/dd)
  • t2 - время на 63 дня после даты 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)
}

Если t1:

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

Я ожидаю, что t2 будет:

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

Но выход:

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

В чем причина этого?

4b9b3361

Ответ 1

t1 - это время в течение 62 дней после даты 1970/1/1 (yy/mm/dd) t2 - это время на 63 дня после даты 1970/1/1 (yy/mm/dd)

Это неверно. t1 - это время 1970 лет, 1 месяц и 1 день после того, что означает time.Date(0, 0, 62, 0, 0, 0, 0, time.UTC).

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))

дает нам:

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

Это совершенно неправильно. UTC не определен для каких-либо дат до 1972 года, григорианский календарь не начинается до 1582 года, и никогда не было ни одного года 0. Игнорируя все это, я не вижу, как 63-й день можно интерпретировать как 31 января, но все равно отпустите.

Давайте добавим вещи к первой отметке времени: добавьте 1970, мы получим 1970-01-31. Добавьте месяц, мы получим 1970-02-31. Но 1970-02-31 не является допустимой датой. Так что это нормализовано до 3 марта. 1970 год не был високосным годом, февраль имел 28 дней, поэтому 29 февраля - 1 марта, 30 февраля - 2 марта, 31 февраля - 3 марта. Добавьте один день в 1970-03-03, и мы получим 1970-03-04.

Вторая временная метка уже анализируется до 1 февраля. Добавьте месяц, и мы получим 1 марта, добавим день, и мы получим 2 марта.

Это то, что происходит, когда вы добавляете месяцы к отметкам времени. Месяц не очень четко определен. Таким образом, библиотека пытается быть умной для вас, и это дает вам неожиданные результаты.

Btw. по какой-то причине: fmt.Println(time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)) интерпретируется как -0001-11-30 00:00:00 +0000 UTC. Не знаю, почему. Не имеет значения с года 0 и месяц 0 не существует. Но это объясняет, почему более ранние временные метки заканчиваются 31 января и 1 февраля.

У AddDate нет причин добавлять вещи в этот порядок. Насколько мне известно, он не документирован. Он мог бы также добавить первый день, затем месяц, затем годы. Попробуйте запустить это:

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))