一篇文章掌握Postgresql中对于日期类数据的计算和处理

在使用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’

1.字符串转日期、时间戳类型

--将字符串类型转为日期类型
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');

2.时间戳、日期类型转字符串

--将时间戳转为字符串(年月日)
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');

3.日期与时间戳之间的互相转换

-- 带时区(推荐使用)
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));

4.时间、日期筛选

为方便进行演示,在这里进行构造数据。

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 ; 

数据截图:
一篇文章掌握Postgresql中对于日期类数据的计算和处理_第1张图片
数据类型截图:
一篇文章掌握Postgresql中对于日期类数据的计算和处理_第2张图片
以下基于上面的数据进行日期筛选,为了降低阅读成本,这里会对一些常用的写法进行整理。

-- 对字符串格式/日期格式进行筛选
--获取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';
--基于时间戳格式的日期筛选与字符串格式的筛选方法类似,这里不多加赘述。

5.时间截断

--按年截断,结果为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');

6.计算时间差

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;

7.其他

7.1 生成日期序列
-- 按天生成自2000-01-01至2100-12-31的时间序列
SELECT generate_series(DATE '2000-01-01',
                       DATE '2100-12-31',
                       INTERVAL '1 day')::DATE
AS frequency;

你可能感兴趣的:(数据库,postgresql,数据库,sql,日期处理)