三类:取当前时间(curdate、curtime、now)、拆日期(year、month、day)、
算派生值(monthname、dayname、dayofweek、dayofyear、quarter、datediff)。
Demo 里 now() 给 2026-10-30 07:29:34(跑的那一天);
monthname 给 October、dayname 给 Friday;dayofweek 给 6,因为它的 1 是星期日。
datediff('2026-10-30', '2026-01-01') 给 302——
参数顺序是「晚减小」,给负数就说明写反了。
上一类处理文本,这一类处理时间——也是「不能硬编」最集中的一类。 时间函数有两件麻烦事:「现在」是相对的(同一句 SQL 隔一天跑结果就不同), 以及「一周从哪天算」各地规定不一样。 这一篇的 Demo 输出带着跑它的日期,别当常量记。
一、取当前时间:三个函数各管一段
curdate() 给日期(2026-10-30),curtime() 给时分秒(07:29:34),
now() 给完整的日期时间。
这一段的输出是「跑这一句的那一天那一秒」,你跑的时候肯定不是这个数。
凡是写进正文的当前时间,都要连「什么时候跑的」一起说,否则读者会以为那是固定值。
now() 在同一条语句里多次调用给同一个值——
因为一条语句算「一个时间点」。 做批次记录时这一点很关键:一批数据的时间戳应该完全一致,
否则对账时排序会乱。
二、拆年、月、日:从日期里取值
year('2026-10-30') 给 2026、month 给 10、day 给 30。
它们吃字符串日期也行,只要格式是 年-月-日。 真实 MySQL 里日期是 DATE 类型,函数照样吃。
最常见的用法是按年按月统计:GROUP BY YEAR(created_at), MONTH(created_at)。
但记住上一篇那条:这样写用不上索引,大表要换成范围条件。
三、英文名与星期几:monthname、dayname、dayofweek
monthname 给 October、dayname 给 Friday——
都是英文,因为 MySQL 返回的就是英文名。 中文名得自己映射。
dayofweek 给 6,但它代表星期五。 因为它的编号是:1 周日、2 周一、…、6 周五、7 周六。
这个编号跟「周一算第一天」的习惯不同。
做「本周一到周日」这类统计时,先算清楚编号,再写条件——差一天,整张报表的数字就全错。
四、天数、季度、相隔几天
dayofmonth 给 30(这个月的第几天)、dayofyear 给 303(这一年的第几天)、
quarter 给 4(第四季度)。
datediff(晚, 早) 给 302——两个日期之间隔了 302 天。
参数顺序容易反:它算的是 a - b,给负数就说明写反了。
datediff 只算「日期差」,不带时分秒。 要算精确到秒的间隔,
MySQL 用 timestampdiff(second, a, b),本沙箱没有这个函数,所以没演示。
五、时间函数与索引:同一条常识再讲一次
WHERE YEAR(created_at) = 2026 会让 created_at 上的索引用不上,
和上一篇 YEAR(birthday) 是同一个毛病。
换成范围:created_at >= '2026-01-01' AND created_at < '2027-01-01'。
结果一样,索引能用。
为什么不用 BETWEEN:
BETWEEN '2026-01-01' AND '2026-12-31' 会漏掉 12 月 31 日当天带时分秒的记录
(2026-12-31 10:00:00 比 2026-12-31 大)。 开区间最稳。
六、动手 Demo:从「今天是哪天」到「隔了多少天」
Demo 六段:当前时间、拆年月日、英文名与星期、天数与季度、日期差、索引那条常识。 第一段的输出带着跑它的时间戳,别把它当固定值抄进笔记。
import _q46 as Q
c = Q.con()
# 当前时间
c.execute("SELECT CURDATE() AS d, CURTIME() AS t, NOW() AS dt")
# 拆年月日
c.execute("SELECT YEAR('2026-10-30') AS y, MONTH('2026-10-30') AS m, "
"DAY('2026-10-30') AS d")
c.execute("SELECT name, YEAR(birthday) AS y, MONTH(birthday) AS m "
"FROM students LIMIT 3")
# 英文名与星期几
c.execute("SELECT MONTHNAME('2026-10-30') AS mn, "
"DAYNAME('2026-10-30') AS dn, DAYOFWEEK('2026-10-30') AS dw")
# 天数、季度
c.execute("SELECT DAYOFMONTH('2026-10-30') AS dm, "
"DAYOFYEAR('2026-10-30') AS dy, QUARTER('2026-10-30') AS q")
# 相隔几天
c.execute("SELECT DATEDIFF('2026-10-30', '2026-01-01') AS days")
实跑输出:
--------------------------------------------------------------------
第二十六课:时间函数,和「今天是哪天」这件事
--------------------------------------------------------------------
取当前时间:三个函数各管一段
SQL> SELECT CURDATE() AS d, CURTIME() AS t, NOW() AS dt
d t dt
------------------------------------------------
2026-10-30 07:31:08 2026-10-30 07:31:08
(1 行)
**`curdate()` 给日期、`curtime()` 给时分秒、`now()` 给完整的日期时间。**
**这一段的输出就是跑这句的那一天那一秒**,你跑的时候肯定不是这个数。
**`now()` 在同一句里多次调用给的是同一个值**,**因为一条语句算「一个时间点」**。
这一点在做批次记录时很重要。
拆年、月、日:从日期里取值
SQL> SELECT YEAR('2026-10-30') AS y, MONTH('2026-10-30') AS m, DAY('2026-10-30') AS d
y m d
-------------------
2026 10 30
(1 行)
SQL> SELECT name, YEAR(birthday) AS y, MONTH(birthday) AS m FROM students LIMIT 3
name y m
-----------------------
张伟 2007 3
王芳 2007 5
李娜 2007 7
(3 行)
**这些函数吃字符串日期也行**,只要格式是 `年-月-日`。
**真实 MySQL 里日期是 DATE 类型,函数照样吃。**
英文名与星期几:monthname、dayname、dayofweek
SQL> SELECT MONTHNAME('2026-10-30') AS mn, DAYNAME('2026-10-30') AS dn,
DAYOFWEEK('2026-10-30') AS dw
mn dn dw
--------------------------
October Friday 6
(1 行)
**`monthname` 给 `October`、`dayname` 给 `Friday`**——**都是英文,因为 MySQL 返回的就是英文名。**
**`dayofweek` 给 6,代表星期五。** **注意它从 1 开始且 1 是星期日**:1 周日、2 周一、…、6 周五、
7 周六。 **这个编号规则跟「周一算第一天」的习惯不一样,用之前先对一遍。**
天数、季度、相隔几天
SQL> SELECT DAYOFMONTH('2026-10-30') AS dm, DAYOFYEAR('2026-10-30') AS dy,
QUARTER('2026-10-30') AS q
dm dy q
------------------
30 303 4
(1 行)
SQL> SELECT DATEDIFF('2026-10-30', '2026-01-01') AS days
days
-----
302
(1 行)
**10 月 30 日是这一年的第 303 天,第 4 季度。** **`datediff(晚, 早)` 给 302**——
两个日期之间隔了 302 天。
**`datediff` 的参数顺序容易反**:`datediff(a, b)` 算的是 `a - b`,**给负数就说明顺序反了。**
时间函数与索引:同一条常识
**`WHERE YEAR(created_at) = 2026` 会让 `created_at` 上的索引用不上**,
**和上一篇 `YEAR(birthday)` 是同一个毛病。**
**换成范围**:`created_at >= '2026-01-01' AND created_at < '2027-01-01'`。
**结果一样,索引能用。**
**另一种写法是用 `BETWEEN`**,
但 `BETWEEN '2026-01-01' AND '2026-12-31'` **会漏掉 12 月 31 日当天带时分秒的记录**,
所以还是开区间最稳。
第一段当前时间。 日期、时分秒、完整时间三列——这三列是同一秒的事。
第二段拆年月日。 2026/10/30;换成 birthday 列,前三个人的出生年月也出来了。
第三段英文名。 October、Friday、6——6 是周五,不是周六。
第四段天数与季度。 30、303、4——10 月 30 日是第 303 天。
第五段日期差。 302 天。
第六段没有 SQL,讲的是「怎么改写成范围条件」。
30 秒实验
NOW()与CURDATE()的区别是什么?哪个带时分秒?DAYOFWEEK('2026-11-01')给几?那天是星期几?DATEDIFF('2026-01-01', '2026-10-30')给正数还是负数?为什么?
常见误区
- 把 Demo 里的当前时间当成固定值。 那是跑 demo 那一刻的时间,隔一天就变了, 不能抄进配置或测试用例。
- 以为
dayofweek的 1 是周一。 它是周日,按「周一算第一天」写条件会整体错一天。 - 用
BETWEEN '2026-01-01' AND '2026-12-31'取整年。 12 月 31 日当天带时分秒的记录会被漏掉, 该用< '2027-01-01'。
自测三问(点开对答案)
1. `NOW()`、`CURDATE()`、`CURTIME()` 各给什么? —— `now()` 给完整日期时间,`curdate()` 只给日期,`curtime()` 只给时分秒。 2. `DAYOFWEEK` 的编号规则是什么? —— 1 是周日、2 是周一、…、7 是周六。跟「周一算第一天」的习惯不一样。 3. 为什么取整年要用 `< '2027-01-01'` 而不是 `BETWEEN … '2026-12-31'`? —— 因为 `2026-12-31 10:00:00` 大于 `2026-12-31`,`BETWEEN` 会漏掉当天的带时间记录。数学、字符串、时间都过完了。下一篇是 MySQL 8 才有的新东西——三个排名函数。
- ☐ (本篇完,下一篇 6.5 排名函数)