一、日期和时间的类型如下
名称 | 存储空间 | 描述 | 例子 |
---|---|---|---|
timestamp [ p ] [ without time zone ] | 8字节 | 显示日期加时间 | 2020-02-23 12:00:00 |
timestamp [ p ] with time zone | 8字节 | 显示日期、时间加时区 | |
interval [ § ] | 12字节 | 时间间隔 | |
date | 4字节 | 只用于日期 | |
time [ p ] [ without time zone ] | 8字节 | 只用于1日内时间,不带时区 | |
time [ p ] with time zone | 8字节 | 只用于1日内时间,带有时区 |
二、日期输入
在SQL中,任何日期或时间的文本输入需要有 ’ 日期/时间 ‘ 类型加单引号包围的字符串组成,语法:
type [ ( p ) ] ’ value ’
日期和时间的输入几乎可以是任何合理的形式,在Postgresql中有系统参数 datestyle 决定是什么格式或形式,如下:
postgres=# show datestyle;
DateStyle
-----------
ISO, MDY
(1 row)
其中 “ MDY ” 表示 月-日-年
在数据库中参数可以设置成 YMD 的形式,但在使用语句插入时,用了date转换格式输入,参数设置那种格式没有影响,都可以进行插入成功。
postgres=# show datestyle;
DateStyle
-----------
ISO, MDY
(1 row)
postgres=# insert into tb_date values(date '02-23-2020');
INSERT 0 1
postgres=# insert into tb_date values(date '2020-02-23');
INSERT 0 1
postgres=# select * from tb_date ;
col1
------------
2020-02-23
2020-02-23
(2 rows)
但是有时候日期输入习惯使用诸如此类 ’ 1/8/2020 ‘ 的格式,类似这种各位月或日没有0做前缀时要注意参数 datestyle 的值,防止日期混乱或者插入错误。
日期输入示例:
例子 | 描述 |
---|---|
date ‘April 26,2020’ | 在任何datestyle参数值下都没有输入问题 |
date ‘2019-01-08’ | ISO 8601格式,任何方式输入没有问题 |
date ‘1/8/2019’ | 在datestyle为 MDY 时,表示2019年1月8日,在datestyle为 DMY 时,表示2019年8月1日,类似输入日期文本时没有在一位数月份或日前加前缀0的输入方式一定要注意 datestyle 参数的格式,凡是日期混乱 |
date ‘1/18/2020’ | 在datestyle参数值为 MDY 时,表示2020年1月18日,其他格式会出现输入错误 |
date ‘03/04/11’ | 在 MDY 格式下表示2011年3月4日,在DMY 格式下表示2011年4月3日,在YMD格式下表示2003年4月11日,所以建议在输入日期文本时要输入完整的日期文本,尽量不要用简写导致日期混乱。 |
date ‘2019-Apr-08’ | 在任何格式下都是2019年4月8日 |
date ‘Apr-08-2019’ | 在任何格式下都是2019年4月8日 |
date ‘08-Apr-2019’ | 在任何格式下都是2019年4月8日 |
date ‘20190405’ | ISO 8601格式,任何格式下都是2019年4月5日 |
date ‘110405’ | ISO 8601 格式,在任何格式下都是2011年4月5日 |
date ‘2019.098’ | 2019年的第98天,即2019年4月8日 |
date ‘J2455886’ | 儒略日,即从公元前4713年1月1日期到今天经过的天数,多为天文学家使用,2455886天,就是2011年11月20日 |
date ‘April 26,202 BC’ | 公元前202年4月26日 |
PS: 对于国内的程序员来说,避免使用 ’/’ 进行日期的输入,,最好使用 ‘-’ 来进行日期文本分割,然后使用 YMD 也就是 年-月-日
的格式输入日期。
三、时间输入
时间输入时,要注意时区的输入,time 被认为时 time without time zone 的类型,所以即使输入的字符串中有时区,也会被忽略,例如:
postgres=# select time '12:59:59';
time
----------
12:59:59
(1 row)
postgres=# select time '12:59:59 PST';
time
----------
12:59:59
(1 row)
postgres=# select time with time zone '12:59:59 PST';
timetz
-------------
12:59:59-08
(1 row)
时间输入时字符串之间使用冒号作为分隔符,输入格式为: ‘ hh:mm:ss ’,如:‘ 12:59:59 ’,也可以不使用分隔符,如:‘125959’ 表示 12时59分59秒。
更多的时间输入示例如下:
例子 | 描述 |
---|---|
time ‘12:59:59.789’ | ISO 8601 |
time ‘12:59:59’ | ISO 8601 |
time ‘12:59’ | ISO 8601 |
time ‘125959’ | ISO 8601 |
time ‘10:59 AM’ | 与 10:59 一样,AM不影响数值 |
time ‘10:59 PM’ | 与 22:59一样,使用PM时输入的小时的值小于等于12 |
time with time zone ‘12:59:59.789+8’ | 带有时区 |
time with time zone ‘12:59:59+08:00’ | ISO 8601 |
time with time zone ‘12:59+08:00’ | ISO 8601 |
time with time zone ‘125959+08:00’ | ISO 8601 |
time with time zone ‘12:59:59 CCT’ | 带有缩写的时区,北京时间12:59:59 |
select time with time zone ‘2020-02-24 12:59:59 Asia/Beijing’ | 用具体名字声明时区 |
PS: 建议在输入时区时不适用缩写表示,相同的缩写代表的可能时不同的时区。
四、特殊的时间字符串
在Postgresql中有一些特殊的字符串输入表示了特别的意义,如下:
字符串 | 使用类型 | 描述 |
---|---|---|
epoch | date,timestamp | 1970-01-01 00:00:00+00(Unix 系统的零时) |
infinity | timestamp | 时间戳的最大值,比任何其他时间戳都晚 |
-infinity | timestamp | 时间戳的最小值,比任何其他时间戳都早 |
now | date,time,timestamp | 当前事务的开始时间(当前时间) |
today | date,timestamp | 今日午夜 |
tomorrow | date,timstamp | 明日午夜 |
yesterday | date,timestamp | 昨日午夜 |
allballs | time | 00:00:00.00 UTC |
五、时间函数和操作符
日期、时间和interval类型之间可以进行加减乘除运算,具体如下:
操作符:
操作符 | 例子 | 结果 |
---|---|---|
+ | date ‘2020-02-01’ + integer ‘7’ | date ‘2020-02-08’ |
+ | date ‘2020-02-01’ + interval ‘1 hour’ | timestamp ‘2020-0201 01:00:00’ |
+ | date ‘2020-02-01’ + time ‘03:00’ | timestamp ‘2020-02-01 03:00:00’ |
+ | interval ‘1 day’ + interval ‘1 hour’ | interval ‘1 day 01:00:00’ |
+ | timestamp ‘2020-02-01 01:00’ + interval ‘23 hours’ | timestamp ‘2020-02-02 00:00:00’ |
+ | time ‘01:00’ + interval ‘2 hours’ | time ‘03:00:00’ |
- | date ‘2020-02-23’ - date ‘2020-02-20’ | 3 |
- | date ‘2020-02-23’ - integer ‘3’ | date ‘2020-02-20’ |
- | date ‘2020-02-23’ - interval ‘1 hour’ | timestamp ‘2020-02-22 23:00:00’ |
- | time ‘07:00’ - time ‘03:00’ | interval ‘04:00:00’ |
- | time ‘07:00’ - interval ‘4 hours’ | time ‘03:00:00’ |
- | timestamp ‘2020-02-23 22:00’ - interval ‘22 hour’ | timestamp ‘2020-02-23 00:00:00’ |
- | interval ‘a day’ - interval ‘1 hour’ | interval ‘1 day -01:00:00’ |
- | timestamp ‘2020-02-23 03:00:00’ - timestamp ‘2020-02-20 12:00’ | interval ‘2 days 15:00:00’ |
* | 600*interval ‘1 second’ | interval ‘00:01:00’ |
* | 15*interval ‘1 day’ | interval ‘15 days’ |
* | 2.5*interval ‘1 hour’ | interval ‘02:30:00’ |
/ | interval ‘2 hour’ / 1.5 | interval ‘01:22:00’ |
函数如下:
函数 | 返回类型 | 描述 | 例子 | 结果 |
---|---|---|---|---|
age(timestamp,timestamp) | interval | 两个时间段之间的时间间隔,前者时间一般为较新时间,结果为正数的时间间隔,否则为负数的时间间隔 | age(timestamp ‘2020-02-01’,timestamp ‘2019-01-01’); age(timestamp ‘2019-02-01’,timestamp ‘2020-01-01’); | 1 year 1 mon ;-11 mons |
age(timestamp) | interval | 从当前时间减去参数时间的结果(时间间隔) | select age(timestamp ‘2000-01-01’) | 20 years 1 mon 23 days |
clock_timestamp() | timestamp with time zone | 实时时钟的当前时间戳,带有时区 | select clock_timestamp(); | |
current_date | date | 当前日期,注意使用时不用加括号 | select current_date | |
current_time | time with time zone | 当前时间,带有时区 | select current_time; | |
current_timestamp | timestamp with time zone | 当前事务开始时的时间戳,带有时区 | select current_timestamp | |
date_part(text, timestamp) | double precision | 获取时间timestamp中指定年月日时分秒等,text的值包括了year(简写 y ),month(m),day(d),hour(h),minute(m),second(s) | select date_part(‘day’,timestamp ‘2020-02-23 12:59:30’); | 23 |
date_part(text, interval) | double precision | 获取interval时间类型中的指定的年月日时分秒等,text的值包括了year(简写 y ),month(m),day(d),hour(h),minute(m),second(s) | select date_part(‘hour’,interval ‘2 years 3 months 12 days 10 hours 30 minutes 10 seconds’); | 10 |
date_trunc(text, timestamp) | timestamp | 将时间timestamp截断成text指定的精度,text的值包括了year(简写 y ),month(m),day(d),hour(h),minute(m),second(s) | select date_trunc(‘hour’,timestamp’2020-02-23 12:59:30’); | 2020-02-23 12:00:00 |
extract(field from timstamp) | double precision | 获取timestamp中指定的text,类似date_part | select extract(‘hour’ from timestamp ‘2020-02-23 12:59:30’); | 12 |
extract(field from interval) | double pracision | 获取interval中指定的text,类似date_part | select extract(‘hour’ from interval ‘2 days 12 hours’) | 12 |
isfinite(timestamp) | boolean | 测试是否为有穷时间戳 | isfinite(timestamp ‘2020-02-25 20:12:30’) | true |
isfinite(interval) | boolean | 测试是否为有穷时间隔 | isfinite(interval ‘5 hours’) | true |
justify_days(interval) | interval | 按照每天30天调整时间间隔,每个30天会变为一个月,不够显示真是天数,超出显示减去30天后的天数 | select justify_days(interval ‘35 days’); | 1 mon 5 days |
justify_hours(interval) | interval | 按照每24小时调整为1天,满24小时会以day显示,如果输入的是day,只会显示day | select justify_hours(interval ‘35 hours’); | 1 day 11:00:00 |
justify_interval(interval) | interval | 同时具备justify_days与justify_hours的功能,而interval参数可以进行加减计算 | select justify_interval(interval ‘1 mon - 2 days’); | 28 days |
localtime | time | 当日时间 | select localtime; | 20:39:09.384134 |
localtimestamp | timestamp | 当前事务开始时的时间戳 | select localtimestamp; | 2020-02-25 20:40:17.168613 |
now() | timestamp with time zone | 当前事务开始时的时间戳并带有时区 | select now(); | 2020-02-25 20:41:28.969894+08 |
statement_timestamp() | timestamp with time zone | 与now()类似,实时时钟的当前时间戳 | select statement_timestamp(); | 2020-02-25 20:42:24.416925+08 |
timeofday() | text | 与statment_timestamp类似,但是返回的类型是text字符串,而非时间类型,显示的格式也不一样 | select timeofday(); | Tue Feb 25 20:44:17.330426 2020 CST |
transaction_timestamp() | timestamp with time zone | 当前事务开始时的时间戳 | select transaction_timestamp() | 2020-02-25 20:46:02.107255+08 |
除了以上的函数外,Postgresql还支持SQL的OVERLAPS操作符,如:
(start1,end1)OVERLAPS(start2,end2)
(start1,length1)OVERLAPS(start2,length2)
以上两个表达式表示在左边的时间段与右边的时间段是否有重叠,如果重叠返回true,如果没有重叠返回false。终点参数(end1、end2)可以是日期,时间,时间戳。或者后面(length1、length2)是一个时间间隔的日期、时间、时间戳。如:
postgres=# select (date '2019-01-01',date '2019-09-25')overlaps(date '2019-09-01',date '2020-02-25');
overlaps
----------
t
(1 row)
postgres=# select (date '2019-01-01',date '2019-08-31')overlaps(date '2019-09-01',interval '25 days');
overlaps
----------
f
(1 row)
六、时间函数
Postgresql数据库中内置了很多返回当前日期和时间的函数,一下函数是按照当前事务的开始时间返回结果:
current_date
current_time
current_timestamp
current_time(precision)
current_timestamp(precision’)
localtime
localstamp
localtime(precision)
localtimestamp(precision)
now()
transacion_timestamp()
其中precision代表的是精度,该精度会导致结果的秒数域会四舍五入到指定的小数位,如果没有精度参数,将给予全部得到的精度。
PS: 特别介绍一下,当前时间获取的函数分为事务开始时的时间戳和实时时钟(当前时间)的时间两类,分别如下:
1.当前事务开始时的时间戳。开始事务时也就是begin;执行时表示开始了一个事务,而当前事务开始时的当前时间,表示执行begin时的时间,在end结束事务前,获取的当前时间时不变的,都是相同一个时间。主要函数包括:current_date、current_time、current_timestamp、localtime、localstamp、transaction_timestamp().。Postgresql这么做的目的是为了允许一个事务在当前时间上有连贯的概念,同一个事务里的多个修改可以保持同样的时间戳。
2.实时时钟时间表示即便执行begin开始了事务,获取的当前时间仍是随着时间而改变的,类似直接获取的是系统时间,函数有:clock_timestamp()、statement_timestamp()、stimeofday()。
所有的日期或时间还接受特殊的文本值:now。用于声明当前的时间和日期(注意:是当前事务开始的开始时间),所以,一下三个语句返回结果是相同的:
postgres=# begin;
BEGIN
postgres=# select current_timestamp;
current_timestamp
-------------------------------
2020-02-25 21:24:32.964255+08
(1 row)
postgres=# select now();
now
-------------------------------
2020-02-25 21:24:32.964255+08
(1 row)
postgres=# select timestamp with time zone 'now';
timestamptz
-------------------------------
2020-02-25 21:24:32.964255+08
(1 row)
postgres=# end;
COMMIT
七、extract函数详解
extract函数格式:
extract(field from source)
extract函数从日期或时间数值中抽取子域,比如年分、小时等,返回类型为 double precision 的数值,source参数必须是一个timestamp、time、interval类型的值的表达式,此外,类型是date的表达式自动转换为timestamp,所以source也可用date类型,field参数是一个标识符或者字符串,指定了从源数据中抽取的域,下表列举了field可以取得值:
field值 | 说明 | 例子 | 结果 |
---|---|---|---|
century | 世纪 | select extract(century from timestamp ‘2020-02-25 12:59:59’); | 21 |
year | 年份 | select extract(year from timestamp ‘2020-02-25 12:59:59’); | 2020 |
decade | 得到年份除以10后的值 | select extract(decade from timestamp ‘2020-02-25 12:59:59’); | 202 |
millennium | 得到当前是第几个千年(0-1000是第一个,1001-2000是第二个,2001-3000是第三个) | select extract(millennium from timestamp ‘2020-02-25 12:59:59’); | 3 |
quarter | 是第几季度 | select extract(quarter from timestamp ‘2020-02-25 12:59:59’); | 1 |
month | 当source是timestamp得到的是月份,当source是interval得到是月的数目 | select extract(month from timestamp ‘2020-02-25 12:59:59’); l select extract(month from interval ‘2 years 8 months’); | 2 l 8 |
week | 得到所给的日期是这一年的第几个星期 | select extract(week from timestamp ‘2020-02-25 12:59:59’); | 9 |
dow | 得到所给的日期是星期几,0是星期天,1是星期一 。。。 | select extract(dow from timestamp ‘2020-02-25 12:59:59’); | 2 |
day | 本月的第几天 | select extract(day from timestamp ‘2020-02-25 12:59:59’); | 25 |
doy | 本年的第几天 | select extract(doy from timestamp ‘2020-02-25 12:59:59’); | 56 |
hour | 得到时间中的小时(0-23) | select extract(hour from timestamp ‘2020-02-25 12:59:59’); | 12 |
minute | 得到时间中的分钟 | select extract(minute from timestamp ‘2020-02-25 12:59:59’); | 59 |
second | 得到时间中的秒,包括小数部分 | select extract(second from timestamp ‘2020-02-25 12:59:59.7521’); | 59.7521 |
epoch | 对于date和timestamp值来说,得到的是自1970-01-01 00:00:00以来的秒数;对于interval值来说,得到时间间隔的总秒数 | select extract(epoch from timestamp ‘2020-02-25 12:59:59.7521’); l select extract(epoch from interval ‘2 days 12 hours’); | 1582635599.7521 l 216000 |
milliseconds | 秒域(包括小数)乘以 1000,即秒域的毫秒级 | select extract(milliseconds from timestamp ‘2020-02-25 12:59:59.7521’); | 59752.1 |
microseconds | 秒域(包括小数部分)乘以 1000000,即秒域的微秒级 | select extract(microseconds from timestamp ‘2020-02-25 12:59:59.7521’); | 59752100 |
timezone | 与UTC的时区偏移量,以秒记录。例如中国是 +8区,返回的是3600x8=28800 | select extract(timezone from timestamp with time zone ‘2020-02-25 12:59:59.7521’); | 28800 |
timezone_hour | 时区偏移量的小时部分 | select extract(timezone_hour from timestamp with time zone ‘2020-02-25 12:59:59.7521’); | 8 |
timezone_minute | 时区偏移量分钟部分,整数时区返回0 | select extract(timezone_minute from timestamp with time zone ‘2020-02-25 12:59:59.7521’); | 0 |