Django/MySQL Database - Timezones are changing when Datetime values entered into database

Viewed 21

My Django application is changing the timezone when I enter a DateTime value into the MySQL database.

Here's my method which adds the new record to the database:

def add_record(self, mdl, **kwargs):
        """add new data as new record in local db"""
        return mdl.objects.create(**kwargs)

This is in the **kwargs:

'timestamp': 2020-09-17T17:50:14.304Z

When the time is entered in the database and I view it via phpMyAdmin it shows the same time as above but with -0400 offset.

The MySQL GLOBAL timezone is showing SYSTEM, which on mine would be 'America/New York'. So, it appears the database is defaulting to this timezone even though I'm passing it a timezone.

Note: I've tried replacing the "Z" with "UTC" or "+00:00" but that doesn't resolve the issue.

Django settings are:

TIME_ZONE = 'UTC'
USE_TZ = True

Note: I tried setting USE_TZ to False but this did not resolve the issue and I was not able to pass any timezone information to the database.

How can I force the database to save the correct timezone?


WORKAROUND:

Was not able to get database to store times in UTC timezone so I ended up using this workaround to modify the time to match the database's default timezone. Here's what I used in case it helps anyone.

Note: Your MySQL timezone tables must be loaded for this to work.

After adding the record, this function fixes the time:

def fix_timezone(self, tm, rid):
        sql = "UPDATE data_testdata SET timestamp=CONVERT_TZ('"
        sql += tm.replace("T", " ").replace("Z", "")
        sql += "', '+00:00', '" + DateTimeFunctions().get_mysql_timezone_offset() + "') "
        sql += "WHERE dataPointId=" + str(rid) + ";"
        cursor = connection.cursor()
        cursor.execute(sql)
        transaction.commit()

using this class:

from django.db import connection
from datetime import datetime
from zoneinfo import ZoneInfo
from django.utils.dateformat import time_format

class DateTimeFunctions(object):
    """functions for manipulating dates, times, timezones, etc"""

    def __init__(self):
        pass

    def get_mysql_timezone_offset(self):
        """get the offset (+HH:MM) for the mysql timezone"""
        return self.get_timezone_offset_from_name(self.get_mysql_timezone_name())
    
    def get_mysql_timezone_name(self):
        """get the name default timezone for the datbase (session tz, or global tz if no session)"""
        cursor = connection.cursor()
        cursor.execute("SELECT @@global.time_zone, @@session.time_zone;")
        tzglobal, tzsession = cursor.fetchone()
        if tzsession == "" or tzsession is None:
            tz = tzglobal
        else:
            tz = tzglobal
        if tz == "SYSTEM":
            return self.get_mysql_system_timezone_name()
        else:
            return tz

    def get_mysql_system_timezone_name(self):
        """get the name of the mysql system timezone"""
        cursor = connection.cursor()
        cursor.execute("SELECT @@system_time_zone;")
        tzname = cursor.fetchone()
        return tzname[0]

    def get_timezone_offset_from_name(self, tznm):
        tdelta = datetime.now(ZoneInfo(tznm)).utcoffset()
        deltaseconds = tdelta.total_seconds()
        sign = "-" if deltaseconds < 0 else "+"
        deltahrs = str(abs(round(deltaseconds/(60*60))))
        if len(deltahrs) == 1: 
            deltahrs = "0" + deltahrs
        deltamin = str(round((deltaseconds % (60*60))))
        if len(deltamin) == 1:
            deltamin = "0" + deltamin
        return sign + deltahrs + ":" + deltamin
0 Answers
Related