在关系型数据库里获取当前日期时间是高频需求,无论是插入记录时落库时间戳,还是查询某天之后的订单,都离不开系统时间函数。SQL标准里并没有强制规定NOW这个名称,所以各个数据库厂商的实现差异很大。理解这些差异,才能写出在目标环境稳定执行的语句,而不是在测试库跑得好好的,上线到另一种库就报错。

主流数据库中NOW函数的具体用法
MySQL和MariaDB提供了最直接的NOW()函数,调用后返回格式为YYYY-MM-DD HH:MM:SS的datetime值,精确到秒。它反映的是执行语句的开始时刻,在同一个事务的多条语句里取值一致。与之相近的还有SYSDATE(),后者取的是函数执行瞬间的系统时间,在存储过程循环里两者可能不同。日常写INSERT INTO log(create_at) VALUES(NOW())就能自动填时间。
PostgreSQL里的NOW()返回的是timestamptz类型,也就是带时区的当前时刻。如果你只想要本地日期,可以用CURRENT_DATE或者NOW()::date做类型转换。SQL Server没有NOW,要用GETDATE()或者更新的SYSDATETIME(),而Oracle传统上用SYSDATE,新版本也可用SYSTIMESTAMP。下面这段PostgreSQL示例展示了如何只取日期部分:
-- PostgreSQL 取当前日期而非时间
SELECT NOW() AS full_time,
NOW()::date AS just_date,
DATE(NOW()) AS same_date;
从底层看,这些函数大多封装了操作系统时钟调用,并受数据库会话时区参数影响。当服务器跨时区部署时,若应用层和数据库层时区配置不一致,用NOW入库的时间在业务系统里显示就会偏差几小时。因此生产环境建议在连接串里显式指定时区,或者统一用UTC存时间,展示时再转换。
基于NOW的日期截取与条件查询技巧
拿到完整的当前时间后,经常需要按天、按月做统计。MySQL可以用DATE(NOW())把时间截到零点的日期,也可以NOW() - INTERVAL 1 DAY算昨天。写查询条件时,WHERE create_time >= DATE(NOW())能命中create_time上的索引,而WHERE DATE(create_time) = DATE(NOW())因为对列用了函数,通常导致索引失效,全表扫描。这是慢查询里极常见的坑。
另一种场景是取最近三十天的数据,不同库写法不同。MySQL用WHERE order_time >= NOW() - INTERVAL 30 DAY,PostgreSQL用NOW() - INTERVAL '30 days',SQL Server则是DATEADD(day, -30, GETDATE())。把NOW或等价函数放在比较符右边、不对业务列做计算,是保证性能的关键。下面给出MySQL统计今日新增用户的示例:
-- 统计今天注册的用户数 SELECT COUNT(*) AS today_users FROM user_account WHERE register_time >= DATE(NOW()) AND register_time < DATE(NOW()) + INTERVAL 1 DAY;
除了查询,NOW也常用于更新语句。比如把过期未支付订单置为关闭,可写UPDATE orders SET status='closed' WHERE status='unpaid' AND create_time < NOW() - INTERVAL 2 HOUR。这种写法把时间计算推给数据库,比在应用代码里算好字符串再传进去更安全,也避免了应用服务器与数据库时钟不同步带来的边界误差。
NOW函数在程序与批量任务中的注意事项
在后台定时任务里,如果每条记录都用NOW更新时间,要注意语句级与行级的区别。MySQL的NOW在同一条SQL里所有行取值相同,适合做批量打标;若用SYSDATE()则每行可能差几毫秒,在海量更新时会造成时间字段无序,影响后续按时间分页。选择哪个,取决于业务是否要求批次内时间一致。
当使用ORM框架如MyBatis时,有人习惯在Java代码里用new Date()传参,有人偏好直接写NOW。若应用服务器时区与数据库不一致,前者可能因JDBC连接属性而偏移,后者完全由库决定。推荐在关键表统一用数据库的默认时间约束,例如字段定义DEFAULT CURRENT_TIMESTAMP,插入时不传该列,让引擎自己填,这样比在SQL里显式调NOW更省心且不易错。
-- 建表时让时间由数据库自动维护
CREATE TABLE audit_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(255),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 插入不指定created_at,自动填入当前时间
INSERT INTO audit_log (content) VALUES ('system startup');
最后提醒,NOW类函数返回的是语句或事务时间点,不要把它当作绝对精确的毫秒级时钟用在金融对账等强一致场景。这类系统应引入专门的时间服务或数据库事务时间戳,并在应用层做幂等保护。理解函数语义、避开索引陷阱、统一时区配置,才能把SQL获取当前日期时间这件小事做稳。