1. SQL NOW() 函数概述
NOW() 是 SQL 中最常用的日期时间函数之一,它返回当前数据库服务器的系统日期和时间。这个函数在不同数据库系统中实现方式略有差异,但核心功能都是获取当前时间戳。
注意:NOW() 函数返回的时间精度取决于数据库系统,MySQL 默认精确到秒,而 PostgreSQL 可以精确到微秒级。
在实际开发中,NOW() 常用于记录创建时间、更新时间,或者作为时间计算的基准点。与同类型的 CURRENT_TIMESTAMP 函数相比,NOW() 更具可读性,是大多数开发者的首选。
2. 不同数据库中的 NOW() 实现
2.1 MySQL 中的 NOW()
MySQL 的 NOW() 函数返回格式为 'YYYY-MM-DD HH:MM:SS' 的 datetime 值:
SELECT NOW(); -- 输出示例: 2023-08-20 14:30:45MySQL 还提供了一些变体函数:
- SYSDATE(): 返回函数执行时的时间(与语句开始时间不同)
- CURRENT_TIMESTAMP: NOW() 的同义词
- LOCALTIME/LOCALTIMESTAMP: 不带时区的时间戳
2.2 PostgreSQL 中的 NOW()
PostgreSQL 的实现更为精确:
SELECT NOW(); -- 输出示例: 2023-08-20 14:30:45.123456+08PostgreSQL 特有的时间函数:
- TRANSACTION_TIMESTAMP(): 等同于 NOW()
- STATEMENT_TIMESTAMP(): 语句开始时间
- CLOCK_TIMESTAMP(): 函数调用时的实时时间
2.3 SQL Server 中的 GETDATE()
SQL Server 使用 GETDATE() 函数实现类似功能:
SELECT GETDATE(); -- 输出示例: 2023-08-20 14:30:45.123相关函数:
- SYSDATETIME(): 更高精度的时间戳
- CURRENT_TIMESTAMP: ANSI SQL 标准写法
3. NOW() 函数的实际应用
3.1 记录创建和修改时间
最常见的用法是在表设计中自动记录时间:
CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATETIME DEFAULT NOW(), last_updated DATETIME ON UPDATE NOW() );3.2 时间计算和比较
NOW() 常用于时间计算:
-- 查询过去24小时内的订单 SELECT * FROM orders WHERE order_date >= NOW() - INTERVAL 1 DAY; -- 计算年龄 SELECT name, TIMESTAMPDIFF(YEAR, birth_date, NOW()) AS age FROM users;3.3 定时任务和过期检查
-- 检查过期优惠券 UPDATE coupons SET status = 'EXPIRED' WHERE expire_date < NOW();4. NOW() 的性能优化
4.1 索引使用策略
在频繁查询的时间字段上创建索引:
CREATE INDEX idx_order_date ON orders(order_date);注意:避免在 WHERE 子句中对 NOW() 计算结果使用函数,这会导致索引失效:
-- 不好的写法(索引失效) SELECT * FROM orders WHERE DATE_FORMAT(order_date, '%Y-%m-%d') = DATE_FORMAT(NOW(), '%Y-%m-%d'); -- 好的写法(可以使用索引) SELECT * FROM orders WHERE order_date >= CURDATE() AND order_date < CURDATE() + INTERVAL 1 DAY;4.2 批量处理的时间一致性
在事务中需要保持时间一致时:
START TRANSACTION; SET @current_time = NOW(); UPDATE table1 SET updated_at = @current_time WHERE ...; INSERT INTO table2 VALUES (..., @current_time); COMMIT;5. 时区处理技巧
5.1 时区转换
-- MySQL 时区转换 SELECT CONVERT_TZ(NOW(), 'SYSTEM', 'Asia/Shanghai'); -- PostgreSQL 时区设置 SET TIME ZONE 'Asia/Shanghai'; SELECT NOW();5.2 存储时区信息
最佳实践是始终以 UTC 时间存储,在显示时转换:
-- 存储UTC时间 CREATE TABLE events ( id INT PRIMARY KEY, event_time DATETIME DEFAULT UTC_TIMESTAMP() ); -- 查询时转换 SELECT id, CONVERT_TZ(event_time, 'UTC', 'Asia/Shanghai') AS local_time FROM events;6. 常见问题解决方案
6.1 时间精度不一致
问题:不同数据库返回的时间精度不同
解决方案:
-- MySQL 获取微秒级时间 SELECT NOW(6); -- SQL Server 获取高精度时间 SELECT SYSDATETIME();6.2 函数调用时间差异
问题:同一语句中多次调用 NOW() 可能返回不同值
解决方案:
-- 使用变量保存时间值 SET @current_time = NOW(); SELECT @current_time AS time1, @current_time AS time2;6.3 测试环境模拟特定时间
问题:测试需要固定时间
解决方案:
-- MySQL 测试时模拟固定时间 SET @mock_now = '2023-01-01 00:00:00'; SELECT @mock_now AS simulated_now;7. 高级应用场景
7.1 生成时间序列
-- MySQL 生成最近7天日期序列 SELECT CURDATE() - INTERVAL (n) DAY AS date_seq FROM ( SELECT 0 AS n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 ) AS numbers;7.2 营业时间计算
-- 计算下一个工作日9点 SELECT CASE WHEN DAYOFWEEK(NOW()) = 6 THEN DATE_ADD(DATE(NOW()), INTERVAL 3 DAY) + INTERVAL 9 HOUR WHEN DAYOFWEEK(NOW()) = 7 THEN DATE_ADD(DATE(NOW()), INTERVAL 2 DAY) + INTERVAL 9 HOUR WHEN TIME(NOW()) >= '17:00:00' THEN DATE_ADD(DATE(NOW()), INTERVAL 1 DAY) + INTERVAL 9 HOUR ELSE DATE(NOW()) + INTERVAL 9 HOUR END AS next_business_time;7.3 性能监控
-- 记录SQL执行时间 SET @start_time = NOW(); -- 执行复杂查询 SELECT * FROM large_table WHERE ...; SET @end_time = NOW(); SELECT TIMESTAMPDIFF(MICROSECOND, @start_time, @end_time) AS execution_time_us;在实际项目中合理使用 NOW() 函数可以大大简化时间处理逻辑,但需要注意不同数据库系统的实现差异。对于需要高精度时间控制的场景,建议使用专门的时间服务或者数据库特有的高精度时间函数。