今天我们又来聊聊错误。因为搞日期和时间就像踩地雷:一切都好,直到你第一步踩错。
选数据类型时的错误
这通常就是一切悲剧的开始。选错数据类型,之前你对日期和时间的努力都白费了。
场景 1:用 DATE 代替 TIMESTAMP
当你记录一个既有日期又有时间的事件时,只用 DATE,你就会丢掉重要信息。
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
order_date DATE -- 只有日期
);
这样设计的话,你根本不知道两个订单是早上下的还是晚上下的。为啥要放弃喝咖啡时欣赏漂亮时间戳的机会呢?
场景 2:忘了时区
如果你的应用有国际用户,但你只用 TIMESTAMP 存日期和时间,没考虑时区,那你的数据就成了“无家可归”。TIMESTAMPTZ 能帮你搞定这个问题。
CREATE TABLE events (
event_time TIMESTAMP -- 没有时区
);
没人想把纽约的晚会和东京的早晨搞混。用 TIMESTAMPTZ 吧!
用函数时的错误
场景 1:TO_CHAR() 里的格式写错了
你格式写错了,问题就来了。比如:
SELECT TO_CHAR(NOW(), 'YYYY-DD-MM'); -- 哎,把月和日搞反了
这里本来应该是 年-月-日,结果成了 年-日-月。这会让你的用户遇到一些很搞笑(但不一定好笑)的情况。一定要检查格式。
场景 2:用 TO_DATE() 时出错
反过来,如果你想把字符串转成日期,但格式不对,PostgreSQL 就会报错。
SELECT TO_DATE('10/31/2023', 'YYYY-MM-DD'); -- 错误!格式不匹配。
字符串的格式必须和你写的一样。比如:
SELECT TO_DATE('2023-10-31', 'YYYY-MM-DD'); -- 这样才对。
时间间隔相关的错误
场景 1:隐式类型转换坑
有时候你会忘了类型转换的细节。比如:
SELECT NOW() + '1'; -- 错误!'1' 是啥意思?
PostgreSQL 不知道你想加一天。正确写法:
SELECT NOW() + INTERVAL '1 day';
场景 2:减 interval 时写乱了
加减 interval 时要小心:
SELECT NOW() - INTERVAL '-1 day'; -- 这其实是加一天!
这里两个负号反而变成加法。最好别这么写。
四舍五入和截断数据时的错误
场景 1:DATE_TRUNC() 截错了
用 DATE_TRUNC() 做分组时,一定要确认你选对了级别。比如:
SELECT DATE_TRUNC('hour', NOW()); -- 截到小时头
SELECT DATE_TRUNC('minute', NOW()); -- 截到分钟头
如果你想要的结果和实际不一样,可能是级别选错了。
场景 2:DATE_TRUNC() 忘了时区
如果你在不同的时区处理时间,结果可能会很迷:
SELECT DATE_TRUNC('day', NOW() AT TIME ZONE 'UTC');
一定要确认时区写对了,不然你真的会“迷失在时间里”。
Unix 时间:丢失的秒
Unix 时间 (EPOCH) 很方便,但也很坑。最常见的错误就是把秒和毫秒搞混。
SELECT TO_TIMESTAMP(1680000000); -- 这样对(单位是秒)。
SELECT TO_TIMESTAMP(1680000000000); -- 错了!零太多了。
一定要搞清楚你的 timestamp 单位,不然会多存一大堆没用的秒。
时区相关的错误
场景 1:时区混乱
你和不同时区的用户打交道时,数据很容易混在一起。比如:
SELECT TIMESTAMP '2023-10-01 10:00:00' AT TIME ZONE 'UTC';
一定要搞清楚你的数据到底在哪个时区。
场景 2:时区重复
存了带时区的时间,又想再加一次时区——千万别这样:
SELECT TIMESTAMP '2023-10-01 10:00:00 UTC' AT TIME ZONE 'UTC'; -- 别这么写!
这样会导致结果完全错乱。
防止错误的小建议
选对数据类型。 如果你要处理国际时间数据,用 TIMESTAMPTZ。只要日期就用 DATE。
多测试你的 SQL。 一定要确认结果和你预期一样,特别是 interval、格式和四舍五入相关的。
用 UTC 存时间数据。 这样能最大程度避免时区混乱。
检查格式。 TO_CHAR() 和 TO_DATE() 的格式一定要和你的数据匹配。
小心用各种函数。 认真看看 PostgreSQL 时间函数文档,别被坑了。
搞时间数据确实挺麻烦,但只要你方法对、细节注意到,绝对能顺利搞定。日期和时间是你应用里很重要的一部分,忘了它们就像忘了周一早上定闹钟一样危险!
GO TO FULL VERSION