如何在Flask-SQLAlchemy SQLite中截断Datetime至时分
解决SQLite中DateTime列截断到小时和分钟的问题
嘿,我来帮你搞定这个DateTime精度和格式化的问题!
为什么会有六位小数?
首先说下原因:SQLite本身并没有真正的DateTime类型,它会把Python的datetime对象直接存储为对应的字符串。而Python的datetime.utcnow()返回的是微秒级精度的时间(小数点后六位),所以你查出来的结果就带了这些小数位——之前遇到的三位是毫秒级精度,只是场景不同而已。
三种解决方案(按推荐程度排序)
1. 查询时直接格式化(推荐,不修改存储)
用SQLite内置的strftime函数,在查询阶段就把时间格式转换成只包含小时和分钟的形式,既保留了原始的精确时间,又能拿到想要的格式:
在Flask-SQLAlchemy中可以这么写:
from sqlalchemy import func # 查询单个用户的格式化登录时间 user_login_time = User.query.filter_by(id=your_user_id).with_entities( func.strftime('%Y-%m-%d %H:%M', User.last_login_date) ).scalar()
这样拿到的结果就是类似2020-12-30 09:46的字符串。
如果是直接写SQL:
SELECT strftime('%Y-%m-%d %H:%M', last_login_date) FROM users WHERE id = ?;
2. 给模型添加快捷属性(代码更优雅)
可以给User模型加一个property方法,这样在业务代码里调用起来更方便,不用每次都写格式化逻辑:
from datetime import datetime from flask_login import UserMixin from your_app import db class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) # ... 其他列 # 注意!这里默认值不要加括号,不然会变成服务器启动时的固定时间 last_login_date = db.Column(db.DateTime, default=datetime.utcnow) @property def last_login_short(self): """返回只包含小时和分钟的登录时间字符串""" if self.last_login_date: return self.last_login_date.strftime('%Y-%m-%d %H:%M') return None @classmethod def update_login_date(cls, user): # 修正类方法:需要传入具体的用户实例来更新 user.last_login_date = datetime.utcnow() db.session.commit()
之后你就可以直接用user.last_login_short来获取格式化后的时间啦~
另外提醒下:你原来的default=datetime.utcnow()有个小坑——加括号的话,这个默认值会变成服务器启动时的时间,而不是用户创建时的当前时间,所以要改成default=datetime.utcnow(传递函数对象,而不是调用后的结果)。
3. 存储时直接截断(不推荐,丢失精度)
如果你确定以后永远不需要秒和微秒的精度,可以在存储的时候就截断时间:
from datetime import datetime, timedelta # 更新登录时间时 now = datetime.utcnow() # 截断秒和微秒 truncated_time = now - timedelta(seconds=now.second, microseconds=now.microsecond) user.last_login_date = truncated_time db.session.commit()
但这种方法会丢失原始的精确时间,除非你明确不需要,否则不建议这么做。
内容的提问来源于stack exchange,提问作者half of a glazier
相关产品推荐
相关产品推荐

