按日期筛选,不必先把时间列变成显示字符串。先确认列类型与时区,再用明确的起止边界表达范围;格式化主要服务展示,不应不加区分地承担查询语义。
MySQL格式符不是Java日期模式
常用对应关系:
| 目的 | MySQL格式符 |
|---|---|
| 四位年份 | %Y |
| 两位月份 | %m |
| 不补零月份 | %c |
| 两位日 | %d |
| 24小时、分钟、秒 | %H:%i:%s |
因此 %Y-%m-%d 才是通常的年-月-日显示;%d-%m-%Y 是日-月-年。%i是分钟,不要拿 %m 代替。MySQL日期函数
SELECT DATE_FORMAT('2018-02-03 04:05:06', '%Y-%m-%d %H:%i:%s');
这个表达式按文档规则可得到 2018-02-03 04:05:06,是算例说明而非查询日志。若用不补零月份生成字符串,再按字面比较,可能把显示顺序误当时间顺序。
按天筛选用起点包含、终点不包含
假设create_time是时间列,目标是业务日2018年10月16日,可由应用计算对应边界,并通过驱动绑定:
SELECT id, create_time
FROM example_event
WHERE create_time >= ?
AND create_time < ?;
在与列和会话一致的时间语义下,两个边界分别为当天零点、次日零点。半开区间避免“截至23:59:59”遗漏小数秒,也便于相邻区间不重叠。
如果列存的是字符串,就先处理类型契约,不能只因为字符串看起来像日期就假定与时间列相同。
TIMESTAMP与DATETIME不能忽略时区
MySQL的TIMESTAMP值按会话时区与UTC进行转换,DATETIME不承担同样的自动转换语义。应确认业务时区、会话time_zone和驱动参数绑定方式,尤其是跨时区写入与查询。MySQL日期时间类型
在列上套DATE_FORMAT再比较,通常也不能期待普通时间列索引像直接范围条件一样使用;是否使用索引要看实际版本、索引定义与执行计划,不能保证某种写法必快。
验证时覆盖午夜、月界、空值及小数秒,记录边界代表的真实时间;不要从一张未注明版本的类型表推导全部存储空间与取值范围。