CONVERT_TZ to funkcja MySQL do przerobienia czasu z jednej strefy czasowej na inną i tym samym trafiłem ostatnio na ciekawy problem, który osobiście nie znałem i pojawił się samodzielnie, bez zmian w kodzie. Jest to związane z operowaniem czasem w wielu strefach czasowych w ramach bazy MySQL.

W ramach aplikacji opartej o Django, którą tworzę od jakiegoś czasu, jest specjalny system, który wyciąga dane z bazy, szukając tych danych na podstawie miesiąca i roku.

something = SomeModel.objects.filter(
    user=self.user,
    start_time__year=self.date_year,
    start_time__month=self.date_month,
)

W powyższym fragmencie kodu wyciągam dane z bazy danych i coś z nimi później operuję. Jakie było moje zdziwienie, gdy pewnego dnia ten model przestał zwracać cokolwiek. Pustą tablicę QuerySet’ów.

Rozpocząłem debugowanie i doszedłem do wniosku, że pytanie o miesiąc start_time__month=self.date_month zawsze zwraca nullową tablicę, niezależnie od pozostałych parametrów zapytania.

Sprawdziłem, że wartość zwraca prawidłowo int i wszystko wygląda, że musi działać.

Debugowanie

No to robimy potworka:

>> something1 = SomeModel.objects.filter(user=self.user).first()
>> print(something1)
<SomeModel: SomeData id: 1>
>> print(something1.start_time.month)
6
>> something2 = SomeModel.objects.filter(start_time__month=something1.start_time.month)
>> print(something2)
<QuerySet []>

Dobra, zaczęło być dziwnie. Wyciągam dane z bazy i na ich podstawie szukam samych siebie. Zwraca brak informacji.

CONVERT_TZ – co to do licha jest?

No to wykorzystajmy piękne możliwości Django, czyli sprawdźmy, jakie zapytanie jest wykonywane na bazie:

SELECT * FROM `module_somemodel` WHERE EXTRACT(MONTH FROM CONVERT_TZ(`module_somemodel`.`start_time`, 'UTC', 'Europe/Warsaw')) = 6

No dobra, co zwraca zapytanie? A nic nie zwraca. W takim razie mamy jakieś dziwne zapytanie, tym samym sprawdźmy po kolei warunki. Najgłębszym warunkiem jest funkcja CONVERT_TZ, której zadaniem jest konwertowanie jakiejś daty, z jakiejś strefy czasowej na inną strefę czasową, np.: z UTC na czas obowiązujący w Warszawie.

Wykonajmy się zapytanie:

select CONVERT_TZ('2022-06-01 19:00:00.000000','UTC','GMT');

Odpytujemy i… null. Dobra, to dziwne. Chwila grzebania w internecie i mamy odpowiedź.

CONVERT_TZ zwraca NULL? Pewnie MySQL jest głodny!

Z jakiegoś powodu (strzelam w auto update), wywaliły się informacje o strefie czasowej dla bazy MySQL. Rozwiązaniem jest więc nakarmienie MySQL tymi informacjami, a dokładnie wykonujemy następujące operacje:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

Tym samym nakarmiliśmy bazę danych informacjami i od tego momentu, baza danych dla CONVERT_TZ przestała zwracać null, tylko zwraca prawidłowo przekonwertowane czasy.

Tego typu sytuacja zdarzyła się mi pierwszy raz, dlatego stwierdziłem, że warto ją opisać i pokazać krok po kroku elementy dochodzenia do przyczyny problemu i jej rozwiązania.

Dołącz do newslettera, by być na bieżąco!

Jeśli chcesz być na bieżąco z blogiem, otrzymywać świetne porady dot. programowania i administracji serwerami, opinie w temacie gier - dołącz do newslettera!

Raz na jakiś czas wyślę Ci informację nt. bloga, a także będę wysyłać ekskluzywne materiały techniczne!

Nie czekaj i dołącz!

Dołączając do newslettera, akceptujesz naszą politykę prywatności!