Django写入MySQL时DateTime时区自动变更问题及解决方法
问题:Django向MySQL写入DateTime值时时区偏移
我的Django应用在向MySQL数据库写入DateTime值时会出现时区变更问题。添加新记录的方法如下:
def add_record(self, mdl, **kwargs): """add new data as new record in local db""" return mdl.objects.create(**kwargs)
传入的**kwargs包含:
'timestamp': 2020-09-17T17:50:14.304Z
写入数据库后,通过phpMyAdmin查看时,时间显示为上述值但带有-0400偏移。
MySQL全局时区为SYSTEM,对应服务器时区为'America/New York',数据库似乎默认使用此时区,即便我传入了带时区的时间。
注:我尝试将"Z"替换为"UTC"或"+00:00",但无法解决问题。
Django配置如下:
TIME_ZONE = 'UTC' USE_TZ = True
注:我尝试将USE_TZ设为False,但问题仍未解决,且无法向数据库传递时区信息。
如何强制数据库保存正确的时区?
临时解决方案
无法让数据库以UTC时区存储时间,因此采用以下临时方案修改时间以匹配数据库默认时区,供参考。
注:需加载MySQL时区表才能生效。
添加记录后,使用以下函数修正时间:
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()
配套使用的工具类:
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
内容的提问来源于stack exchange,提问作者Amy
相关产品推荐
相关产品推荐

