按日期筛选,不必先把时间列变成显示字符串。先确认列类型与时区,再用明确的起止边界表达范围;格式化主要服务展示,不应不加区分地承担查询语义。

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再比较,通常也不能期待普通时间列索引像直接范围条件一样使用;是否使用索引要看实际版本、索引定义与执行计划,不能保证某种写法必快。

验证时覆盖午夜、月界、空值及小数秒,记录边界代表的真实时间;不要从一张未注明版本的类型表推导全部存储空间与取值范围。