在使用postgresql中的SQL语句时,往往会遇到时间和日期的处理方法,本文会对日期进行一个总结,方便更多人来使用。
对格式化字符串的介绍:
模式 | 描述 |
---|---|
HH | 一天的小时数(01-12) |
HH12 | 一天的小时数(01-12) |
HH24 | 一天的小时数(00-23) |
MI | 分钟(00-59) |
ss | 秒(00-59) |
MS | 毫秒(000-999) |
US | 微秒(000000-999999) |
AM或A.M. | 正午标识(大写) |
pm或p.m. | 下午标识(小写) |
Y,YYY | 带逗号的年(4和更多位) |
YYYY | 年(4和更多位) |
YYY | 年的后三位 |
YY | 年的后两位 |
Y | 年的最后一位 |
BC或B.C. 或 AD 或 A.D. | 纪元标识(大写) |
CC | 世纪(2位) |
MONTH | 全长大写月份名(空白填充为9字符) |
Month | 全长混合大小写月份名(空白填充为9字符) |
month | 全长小写月份名(空白填充为9字符) |
MON | 大写缩写月份名(3字符) |
Mon | 缩写混合大小写月份名(3字符) |
mon | 小写缩写月份名(3字符) |
MM | 月份号(01-12) |
DAY | 全长大写日期名(空白填充为9字符) |
Day | 全长混合大小写日期名(空白填充为9字符) |
day | 全长小写日期名(空白填充为9字符) |
DY | 缩写大写日期名(3字符) |
Dy | 缩写混合大小写日期名(3字符) |
dy | 缩写小写日期名(3字符) |
DDD | 一年里的日子(001-366) |
DD | 一个月里的日子(01-31) |
D | 一周里的日子(1-7;周日是1) |
W | 一个月里的周数(1-5)第一周从该月第一天开始) |
WW | 一年里的周数(1-53)(第一周从该年第一天开始算) |
IW | ISO一年里的咒术(第一个星期四在第一周里) |
Q | 季度 |
RM | 罗马数字的月份(I-XII ;I=1月)(大写) |
rm | 罗马数字的月份(I-XII ;I=1月)(小写) |
TZ | 时区名(大写) |
tz | 时区名(小写) |
对时间加减类的介绍:
操作符 | 例子 | 结果 |
---|---|---|
+ | date ‘2001-09-28’ + integer ‘7’ | date ‘2001-10-05’ |
+ | date ‘2001-09-28’ + interval ‘1 hour’ | timestamp ‘2001-09-28 01:00:00’ |
+ | date ‘2001-09-28’ + time ‘03:00’ | timestamp ‘2001-09-28 03:00:00’ |
+ | interval ‘1 day’ + interval ‘1 hour’ | interval ‘1 day 01:00:00’ |
+ | timestamp ‘2001-09-28 01:00’ + interval ‘23 hours’ | timestamp ‘2001-09-29 00:00:00’ |
+ | time ‘01:00’ + interval ‘3 hours’ | time ‘04:00:00’ |
- | - interval ‘23 hours’ | interval ‘-23:00:00’ |
- | date ‘2001-10-01’ - date ‘2001-09-28’ | integer ‘3’ (days) |
- | date ‘2001-10-01’ - integer ‘7’ | date ‘2001-09-24’ |
- | date ‘2001-09-28’ - interval ‘1 hour’ | timestamp ‘2001-09-27 23:00:00’ |
- | time ‘05:00’ - time ‘03:00’ | interval ‘02:00:00’ |
- | time ‘05:00’ - interval ‘2 hours’ | time ‘03:00:00’ |
- | timestamp ‘2001-09-28 23:00’ - interval ‘23 hours’ | timestamp ‘2001-09-28 00:00:00’ |
- | interval ‘1 day’ - interval ‘1 hour’ | interval ‘1 day -01:00:00’ |
- | timestamp ‘2001-09-29 03:00’ - timestamp ‘2001-09-27 12:00’ | interval ‘1 day 15:00:00’ |
* | 900 * interval ‘1 second’ | interval ‘00:15:00’ |
* | 21 * interval ‘1 day’ | interval ‘21 days’ |
* | double precision ‘3.5’ * interval ‘1 hour’ | interval ‘03:30:00’ |
/ | interval ‘1 hour’ / double precision ‘1.5’ | interval ‘00:40:00’ |
--将字符串类型转为日期类型
select to_date('2020-06-14','yyyy-mm-dd');
select to_date('14 Jun 2022','DD Mon yyyy');
--将字符串类型转为时间戳
select to_timestamp(1655211000);
select to_timestamp('2020-06-04', 'yyyy-mm-dd');
--将时间戳转为字符串(年月日)
select to_char(now(),'yyyy-mm-dd');
--将时间戳转为字符串(年月日 时分秒)
select to_char(now(),'yyyy-mm-dd HH24:MI:SS');
--将时间间隔转为字符串
select to_char(interval '1 year 1 mon 2day 3h 4m 5s','yy-mm-dd HH24:MI:SS');
--将日期转为字符串
select cast(current_date as VARCHAR);
select to_char(CURRENT_DATE,'yy-mm-dd');
-- 带时区(推荐使用)
select EXTRACT(epoch FROM CAST(CURRENT_DATE AS TIMESTAMPTZ));
--不带时区(会多出8小时,时间会变为08:00:00)
select EXTRACT(epoch from CURRENT_DATE);
select EXTRACT(epoch FROM CAST(CURRENT_DATE AS TIMESTAMP));
为方便进行演示,在这里进行构造数据。
DROP TABLE IF EXISTS "test_table";
CREATE TABLE "test_table" (
"depart" varchar(15),
"name" varchar(15),
"create_date" date,
"last_login_date" varchar(50),
"update_time" timestamp,
"birth_time" varchar(50),
"salary" int8
)
;
INSERT INTO test_table (depart, name, create_date,last_login_date,update_time,birth_time,salary)
WITH test_table AS (
SELECT UNNEST( ARRAY [ '财务', '行政', '销售', '财务', '行政', '行政' ] ) AS depart,
UNNEST ( ARRAY [ 'A', 'B', 'A', 'C', 'D', 'C' ] ) AS NAME,
UNNEST ( ARRAY [ cast('2021-12-21' as date), cast('2020-01-03' as date), cast('2022-01-01' as date), cast('2021-05-31' as date), cast('2020-02-28' as date), cast('2019-01-31' as date) ] ) AS create_date,
UNNEST ( ARRAY [ '2022-06-21', '2022-06-03', '2022-06-01', '2021-06-02', '2022-06-28', '2022-05-31' ] ) AS last_login_date,
UNNEST ( ARRAY [to_timestamp('2022-05-21 12:20:30','yyyy-mm-dd HH24:MI:SS'), to_timestamp('2022-01-03 23:59:58','yyyy-mm-dd HH24:MI:SS'), to_timestamp('2022-01-04 01:01:39','yyyy-mm-dd HH24:MI:SS'), to_timestamp('2022-01-01 11:32:36','yyyy-mm-dd HH24:MI:SS'), to_timestamp('2021-12-31 09:18:27','yyyy-mm-dd HH24:MI:SS'), to_timestamp('2021-12-30 17:12:29','yyyy-mm-dd HH24:MI:SS')] ) AS update_time,
UNNEST ( ARRAY [ '1998-02-21 07:20:36', '1994-01-03 22:59:51', '1994-01-04 18:09:14', '1994-01-01 04:12:43', '1993-12-31 15:12:57', '1993-12-30 10:12:49']) AS birth_time,
UNNEST ( ARRAY [ 200, 100, 50, 30, 200, 100 ] ) AS donate
) SELECT
*
FROM
test_table ;
数据截图:
数据类型截图:
以下基于上面的数据进行日期筛选,为了降低阅读成本,这里会对一些常用的写法进行整理。
-- 对字符串格式/日期格式进行筛选
--获取last_login_date大于等于2022-06-21日的
select * from test_table where last_login_date>='2022-06-21';
--获取create_date大于等于2021-05-21日的
select * from test_table where create_date>='2021-05-21';
--获取last_login_date等于2022-06-21日的
select * from test_table where last_login_date>='2022-06-21' and last_login_date <='2022-06-21';
select * from test_table where last_login_date between '2022-06-21' and '2022-06-21';
--获取last_login_date大于等于2021-05-21日并且小于等于2021-12-10日的
select * from test_table where create_date>='2021-05-21' and create_date<='2021-12-10';
select * from test_table where create_date between '2021-05-21' and '2021-12-10';
--基于字符串格式/时间戳格式的时间筛选
--对字符串格式数据进行筛选:
--获取出生日期大于等于1994-01-03的数据。
select * from test_table where birth_time>='1994-01-03';
--获取出生日期在1994-01-03和1994-01-04日期之间的数据,含1994-01-03和1994-01-04当天的数据。
--特别注意:以下写法会遗漏1994-01-04当天的数据。
--select * from test_table where birth_time between '1994-01-03' and '1994-01-04';
--需要对末尾日期加1天,等同于:'1994-01-03 00:00:00' and'1994-01-05 00:00:00'
select * from test_table where birth_time between '1994-01-03' and '1994-01-05';
--需要对日期进行转换
select * from test_table where cast(birth_time as date) between '1994-01-03' and '1994-01-04';
--需要加上时分秒
select * from test_table where birth_time >='1994-01-03 00:00:00' and birth_time <='1994-01-04 23:59:59';
select * from test_table where birth_time between '1994-01-03 00:00:00' and '1994-01-04 23:59:59';
--基于时间戳格式的日期筛选与字符串格式的筛选方法类似,这里不多加赘述。
--按年截断,结果为2022-01-01 00:00:00
SELECT date_trunc('year', TIMESTAMP '2022-06-14 20:24:30');
--按月截断,结果为2022-06-01 00:00:00
SELECT date_trunc('month', TIMESTAMP '2022-06-14 20:24:30');
--按天截断,结果为2022-06-14 00:00:00+08
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2022-06-14 20:24:30+08');
--按天和时区截断,结果为2022-06-14 22:00:00+08
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2022-06-14 20:24:30+00', 'Australia/Sydney');
--按小时截断,结果为2022-06-14 20:00:00
SELECT date_trunc('hour', TIMESTAMP '2022-06-14 20:24:30');
--按小时对时间间隔进行截断,结果为2 days 02:00:00
SELECT date_trunc('hour', INTERVAL '2 days 02:30:58');
with temp as (select now() now,now() -INTERVAL '2 year 2 month 1 day 1h 3m 33s' last_date)
select now,
last_date,
EXTRACT(year from age(now,last_date)) years, --年
EXTRACT(year from age(now,last_date))*12+EXTRACT(month from age(now,last_date)) months, --月份
EXTRACT(day from (now-last_date)) days, --日
now::date-last_date::date days_2, --日
EXTRACT(epoch from (now-last_date)/3600) hours, --时
round(EXTRACT(epoch from (now-last_date))::numeric/3600,2) hour_2fs, --时 四舍五入形式
EXTRACT(epoch from (now-last_date))::numeric/60 minutes, --分
trunc(EXTRACT(epoch from (now-last_date))::numeric/60,1) minutes_1fs, --分 截断形式
round(EXTRACT(epoch from (now-last_date))::numeric/60,1) minutes_1fs_another, --分 四舍五入形式
EXTRACT(epoch from (now-last_date)) epoch --秒数
from temp;
-- 按天生成自2000-01-01至2100-12-31的时间序列
SELECT generate_series(DATE '2000-01-01',
DATE '2100-12-31',
INTERVAL '1 day')::DATE
AS frequency;