【问题标题】:How can I stop python from converting a mySQL DATETIME to a datetime.date when the time is 00:00:00?当时间为 00:00:00 时,如何阻止 python 将 mySQL DATETIME 转换为 datetime.date?
【发布时间】:2016-08-10 18:34:28
【问题描述】:

我正在从 mySQL 数据库中读取各种数据类型。第五列在数据库中具有类型“DATETIME”。我将其用作“BloodTraitRecord”对象的 entry_date。

import mysql.connector
from datetime import timedelta
from datetime import datetime

show_DB = """select  RUID, test_sname, test_value, units, ref_range, entry_date from %s
             where RUID=%%s and test_sname=%%s order by RUID,
             test_sname, entry_date Limit 5;""" % (tableToUse,)

cursor.execute(show_DB, (ruid, traitPair[0]))
resultsForOneTrait = cursor.fetchall()

for result in resultsForOneTrait:
    ruid = result[0]
    s_name = result[1].decode("UTF-8")
    value = result[2]
    units = result[3].decode("UTF-8")
    ref_range = result[4].decode("UTF-8")

    # Need assistance here
    entryDate = result[5]

    record = BloodTraitRecord(ruid, s_name, value, units, ref_range, entryDate)

BloodTraitRecord 类:

class BloodTraitRecord:

def __init__(self, ruid, test_sname, test_value, units, ref_range, entry_date):
    self.RUID = ruid
    self.test_sname = test_sname     
    self.test_value = test_value
    self.units = units               
    self.ref_range = ref_range


    self.entry_date = entry_date

数据库中的 DATETIME 对象在 mySQL 服务器中如下所示:

'2008-11-14 13:28:00'

除非数据库中的时间是午夜,否则代码会按预期运行,如下所示:

'2014-05-18 00:00:00'

在这种情况下,并且仅在这种情况下,在将记录的 entry_date.date() 与代码后面的另一个 datetime.date 进行比较时,我会收到此错误:

# 'cancerCutoff' is consistently a datetime.date 
cancerCutoff = firstCancerAnemiaCodeDate[ruidkey] - timedelta(days=180)
if cancerCutoff < record.entry_date.date():
AttributeError: 'datetime.date' object has no attribute 'date'

打印 record.entry_date 确认此案例的时间属性已消失:

'2014-05-18'

我有办法通过检查对象的类型来解决此问题,并且仅在对象是日期时间时才调用 date 属性,但我想知道是否有比这更好的解决方法。

我也不明白为什么当 DATETIME 时间为 00:00:00 时,python 会立即将 MySQL DATETIME 转换为 datetime.date。

感谢您的帮助!

【问题讨论】:

  • 你是说如果值包括午夜,Python 会将 MySQL DATETIME 转换为 datetime.date,但不是吗?您使用的是什么 ORM 或连接器?貌似mysql.connector,但请在问题中确认。
  • 所有这些都是正确的。更新问题。
  • 无法在带有本地 MySQL 5.6.24 服务器的 OSX 上运行 mysql.connector 2.1.3 版和 Python 3.5 复制问题。你运行的是什么版本?
  • mysql.connector = 2.1.3 版; Python = 3.4.4 版;本地 MySQL 服务器 = 版本 5.7.11。在 Windows 7 上运行。
  • 这很奇怪,我看不出任何逻辑原因为什么它会根据午夜的时间将其解析为 datetime.data,也许这是一个特定于 Windows 的问题。附带说明一下,仅使用 self.entry_date = entry_date 与您的 if/else 逻辑相同,但如果它是“无”,也会导致错误。

标签: python mysql date datetime


【解决方案1】:

我会确保您从数据库中提取日期时间对象后立即拥有它。那么您以后不必进行任何检查。所以你可以说:

entryDate = ensure_datetime(result[5])

这只是一点额外的代码,并且还有一个优点,如果您的查询发生更改并且您没有正确更新代码,它会立即捕获类型错误。这是一个示例实现:

from datetime import datetime, date

# Thanks to http://stackoverflow.com/a/1937636/2482744
def date_to_datetime(d):
    return datetime.combine(d, datetime.min.time())

def ensure_datetime(d):
    if isinstance(d, datetime):
        return d
    elif isinstance(d, date):
        return date_to_datetime(d)
    else:
        raise TypeError('%s is neither a date nor a datetime' % d)

演示:

for x in [date(2016, 5, 12),
          datetime(2016, 5, 12, 9, 32, 57, 345),
          'a string']:
    print(ensure_datetime(x))

输出:

2016-05-12 00:00:00
2016-05-12 09:32:57.000345
Traceback (most recent call last):
  File "/Users/alexhall/Dropbox/python/sandbox/sandbox.py", line 14, in <module>
    print(ensure_datetime(x))
  File "/Users/alexhall/Dropbox/python/sandbox/sandbox.py", line 9, in ensure_datetime
    raise TypeError('%s is neither a date nor a datetime' % d)
TypeError: a string is neither a date nor a datetime

但我感觉你不想这样做,所以我将它变甜如下:

def clean_types(row):
    new_row = []
    for item in row:
        if isinstance(item, date) and not isinstance(item, datetime):
            item = date_to_datetime(item)
        elif isinstance(item, str):
            item = item.decode("UTF-8")
        new_row.append(item)
    return new_row

# Demo
print(clean_types([3, 'abc', u'def', date.today(), datetime.now()]))
# [3, u'abc', u'def', datetime.datetime(2016, 5, 12, 0, 0), datetime.datetime(2016, 5, 12, 17, 22, 7, 519604)]

现在您的代码可以缩短为:

for result in resultsForOneTrait:
    record = BloodTraitRecord(*clean_types(result))

而且你不必记住做任何事情。

【讨论】:

    【解决方案2】:

    我最近也遇到了类似的问题。

    我通过 db_cursor = db_con.cursor(raw=True) 修复了它, 根据MySQL Python connector reference docs.

    但结果以列表/列表的形式返回,其中元素为bytearray(b'data'), 因此,要将数据恢复为可用的友好格式,我必须这样做:

    db_cursor.execute(some_sql)

    query_result = db_cursor.fetchall()

    ...

    for data_row in query_result:
        tempList = [x.decode('utf-8') if x != None else x for x in data_row]
    

    然后对tempList 做一些事情,但要保证来自数据库的datetime 数据类型符合我的预期,例如,在我的例子中,我有两列具有预期值'2020-10-30', '03:09:03', 'AM'

    在参考文档站点上的进一步阅读揭示了为什么在打开或关闭数据类型转换之间存在一个选项。

    我希望这有助于为更可行的解决方案打开大门。

    【讨论】:

      猜你喜欢
      • 2017-10-03
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      相关资源
      最近更新 更多