Остерегайтесь стандарта даты и времени !!

Итак, сегодняшняя история о странном поведении при демаршалинге DateTime из JSON в Golang. Я не говорю, что это ошибка, но это только моя история из-за отсутствия у меня опыта работы с DateTime и часовым поясом в Golang.

Это случается, когда я хочу создать систему CRUD API на Golang. Итак, у меня есть конечная точка, скажем: /event, которая получит объект события из JSON.

{
  "title": "title here in string",
  "place": "place name here in string",
  "start_time": "date time here in string"
}

Я использую labstack / echo в качестве библиотеки маршрутизации, чтобы упростить обработку моего запроса. С помощью echo, чтобы получить тело ответа и демаршалировать его в мою структуру, я могу сделать это с помощью простого кода, как показано ниже:

Итак, когда я хочу его протестировать, я создал тело запроса, как показано ниже, я просто скопировал и вставил его из нашего примера документации API. Потому что сначала я даже не думаю, что это имеет значение.

{
  "title": "Core i13 Anniversarry",
  "place": "Ancol Beach",
  "start_time": "2018-09-22T12:42:31Z"
}

API уже развернут на промежуточном сервере, поэтому я тестирую его прямо из Postman на промежуточный сервер. Но после получения всего сохраненного элемента события start_time отличается от того, что я разместил в теле запроса. Ниже это будет выглядеть так.

{
  "id": "1", // auto increment from database
  "title": "Core i13 Anniversarry",
  "place": "Ancol Beach",
  "start_time": "2018-09-22T19:42:31+07:00",
  "created_at": "2018-09-22T16:35:08+07:00",
  "updated_at": "2018-09-22T16:35:08+07:00"
}

А в базе он хранится вот так:

Посмотрите поле start_time. Это изменилось по сравнению с тем, что я опубликовал. Я хочу, чтобы сохраненные данные были такими же, как и данные, которые я отправил из Postman.

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

Решение проблемы

Чтобы решить эту проблему, я выполняю все действия, указанные ниже.

Ищем строку подключения в драйвере подключения

Поскольку я использую MySQL в качестве хранилища БД, мне нужен драйвер для подключения моего приложения к MySQL. Я использую github.com/go-sql-driver/mysql в качестве драйвера подключения. Итак, после поиска документации и проверки моей строки подключения ничего плохого не произошло. Я сделал правильно.

dsn := root:root@tcp(127.0.0.1:3306)/event?parseTime=true&loc=Asia%2FJakarta&charset=utf8mb4&collation=utf8mb4_unicode_ci

Восстановите Datetime вручную

Все еще любопытно, почему это происходит. Затем я пытаюсь найти ответы на вопросы или проблемы по этому поводу в StackOverflow или даже на GitHub.

Честно говоря, у меня уходит до 2 часов, когда я пытаюсь решить эту проблему 🤦‍
А пока я был разочарован. Итак, у меня есть 2 варианта, как решить эту проблему.

  1. Я перестрою start_time перед сохранением в базе данных.
  2. Спрашивать моих товарищей по команде (* даже если это так глупо, когда я спрашиваю об этом)

Но просто хочу приложить больше усилий 😶, я исправил ситуацию, перестроив DateTime.

startTime := e.StartTime
loc, _ := time.LoadLocation("Asia/Jakarta")
localStartTime := time.Date(startTime.Year(), startTime.Month(), startTime.Day(), startTime.Hour(), startTime.Minute(), startTime.Second(), startTime.Nanosecond(), loc)

Затем, просто из любопытства, я спрашиваю свою команду о проблеме. Потом смотрят, как я это воспроизводю, тоже как и я, им тоже любопытно, почему это происходит. Всего за несколько минут один из моих сотрудников нашел причины, по которым это происходит.

Это происходит из-за неправильного смещения часового пояса в теле запроса.

{
  "title": "Core i13 Anniversarry",
  "place": "Ancol Beach",
  "start_time": "2018-09-22T12:42:31Z" // look for the `Z` indicator
}

Поскольку я жил в +7.00 timezone (Asia/Jakarta), он должен быть включен в мой JSON.

Итак, когда я меняю start_time с:

2018-09-22T12:42:31Z

в

2018-09-22T12:42:31+07:00

это решает мою проблему. С моей системой ничего плохого не произошло. Все работает отлично.

Когда я это понял, я почувствовал себя таким тупым 🤦‍. Я зря потратил два часа своей жизни 🤦‍.

Урок, который нужно усвоить

  • Всегда сначала спрашивайте своих товарищей по команде (были ли они в любом случае доступны)
  • 2018–09–22T12:42:31+07:00 - это формат RFC 3339, каждый символ имеет значение.

Если вы считаете, что эту статью стоит прочитать, похлопайте в ладоши или поделитесь в своем сетевом кругу, чтобы все также могли это прочитать. Следите за другими подобными историями!