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.