Невозможно разобрать строку на время с включенным смещением часового пояса RFC3339 с кажущимися противоречивыми ошибками

Я использую Golang и time.Time для синтаксического анализа заданной строки в объект времени.

Используя RFC3339 и time.Parse, вот пример моего кода:

t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z07:00")
if err != nil {
   return nil, err
}

Я получаю следующие ошибки.

Когда я включаю смещение часового пояса, я получаю:

ERRO[0002] parsing time "2020-08-08T00:22:44Z07:00": extra text: 07:00

Когда я не включаю смещение часового пояса, я получаю:

ERRO[0002] parsing time "2020-08-08T00:15:36" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"

Как избежать этой проблемы при синтаксическом анализе времени в структурированный объект?


person Dan    schedule 08.08.2020    source источник
comment
2020-08-08T00:22:44Z07:00 не является допустимой датой RFC3339. Попробуйте 2020-08-08T00:22:44Z, 2020-08-08T00:22:44+07:00 или 2020-08-08T00:22:44-07:00   -  person Flimzy    schedule 08.08.2020
comment
интересно, что golang time.RFC3339 == 2006-01-02T15:04:05Z07:00   -  person Dan    schedule 09.08.2020
comment
Это шаблон. Это не означает, что это действительная метка времени.   -  person Flimzy    schedule 09.08.2020


Ответы (1)


Публикация ответа, так как это слишком долго для комментария.

Наличие символа Z в константе Go time.RFC3339 "2006-01-02T15:04:05Z07:00" не означает, что дата, соответствующая шаблону, должна включать Z, за которой следует смещение часового пояса.

На самом деле дата с Z, за которой следует что-то еще, не является допустимой датой RFC3339. Следовательно, ваша первая ошибка extra text: 07:00

Z означает Zulu Time, то есть часовой пояс UTC. Из спецификаций RFC3339:

  Z           A suffix which, when applied to a time, denotes a UTC
              offset of 00:00; often spoken "Zulu" from the ICAO
              phonetic alphabet representation of the letter "Z".

Таким образом, Z одна уже предоставляет информацию о часовом поясе, то есть UTC.

Как отметил @Flimzy в комментариях, 2020-08-08T00:22:44Z будет действительной датой RFC3339.

    t, err := time.Parse(time.RFC3339, "2020-08-08T00:22:44Z")
    if err != nil {
        panic(err)
    }
    fmt.Println(t) // 2020-08-08 00:22:44 +0000 UTC

Теперь, если вы прочитаете стандарт RFC3339 дальше, вы увидите следующее определение:

time-zone       = "Z" / time-numoffset
time-numoffset  = ("+" / "-") time-hour [[":"] time-minute]

Это означает, что часть даты, связанная с часовым поясом, представляет собой либо Z, либо смещение. Понятно, что поскольку Z уже представляет смещение 00:00, вы не можете иметь еще одно смещение +/-HH:mm в той же строке даты.

Но это также означает, что должны присутствовать Z или +/-HH:mm. Поэтому, если вы удалите их оба, вы получите вторую ошибку: cannot parse "" as "Z07:00"

Анализатор пытается прочитать строку "2020-08-08T00:15:36" как RFC3339, поэтому он ожидает либо Z, либо смещение после секунд (или миллисекунд, если есть).


В заключение, Z07:00 в шаблоне Go time.RFC3339 — это просто представление того факта, что строка даты должна включать часовой пояс. Действительная строка даты RFC3339 должна включать либо Z, либо смещение.

person blackgreen    schedule 09.08.2020
comment
Спасибо, что прояснили это для всех, кто погуглил эти термины и пришел сюда. Golang разделяет стандарт как жестко закодированное время golang.RFC3339 = 2006-01-02T15:04:05Z07:00, что может сбить людей с толку. - person Dan; 09.08.2020