一、几个时间相关的概念。
GMT时间:Greenwich Mean Time,格林尼治平时,又称格林尼治平均时间或格林尼治标准时间。是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间。
GMT存在较大误差,因此现在已不再被作为标准时间使用。现在的标准时间,是由原子钟报时的协调世界时(UTC)
UTC时间:Universal Time Coordinated,中文名称:世界标准时间或世界协调时。
UTC时间可以理解为全世界都公用的一个时间。它实际上反映了一种约定,即为全世界所认可的一个统一时间,而不是某特定地区的时间。
中国人常用的北京时间比UTC时间快8个小时。也即UTC时间凌晨0点时,北京时间已经是早上8点,这就是为啥全世界人往往不直接用UTC时间计时原因。
CST时间:China Standard Time,即中国标准时间。在时区划分上,属东八区,比协调世界时早8小时,记为UTC+8
。
UNIX时间戳(timestamp):计算机中的UNIX时间戳,是以GMT/UTC时间1970-01-01T00:00:00
为起点,到当前具体时间的秒数(不考虑闰秒)。这样做的目的,主要是通过“整数计算”来简化计算机对时间操作的复杂度。
二、Linux 中几种时间的操作与转化
2.1、获取当前系统时区
可以通过date +%Z
或者timedatectl
[root@chb1 ~]# date +%z+0800[root@chb1 ~]#
查看时区配置文件
2.2、获取本地时间
[root@chb1 ~]# dateSat Apr 22 12:14:21 CST [root@chb1 ~]# date +'%Y-%m-%d %H:%M:%S.%s'-04-22 12:14:22.1682136862[root@chb1 ~]#
2.3、获取 UTC 时间
# -u 获取 utc 时间[root@chb1 ~]# date +'%Y-%m-%d %H:%M:%S.%s' -u-04-22 04:15:36.1682136936 # 与 本地时间相差八小时[root@chb1 ~]#
本地时间和utc时间相差八小时
[root@chb1 ~]# date; date -uSat Apr 22 12:16:47 CST Sat Apr 22 04:16:47 UTC [root@chb1 ~]#
2.4、获取时间戳,不管是UTC时间还是北京时间 时间戳都是一样
是以GMT/UTC时间1970-01-01T00:00:00
为起点,到当前具体时间的秒数(不考虑闰秒)
[root@chb1 ~]# date; date -uSat Apr 22 12:16:47 CST Sat Apr 22 04:16:47 UTC [root@chb1 ~]# date +%s;date +%s -u1682137482137420
2.5、将时间戳转为 时间字符串
[root@chb1 ~]# date -d @1682137164Sat Apr 22 12:19:24 CST [root@chb1 ~]# date -d @1682137164 +'%Y-%m-%d %H:%M:%S.%s'-04-22 12:19:24.1682137164[root@chb1 ~]# date -d @1682137164 +'%Y-%m-%d %H:%M:%S.%s' -u-04-22 04:19:24.1682137164
三、SparkSQL
3.1、获取时间戳
3.1.1、UNIX_TIMESTAMP
spark-sql> select UNIX_TIMESTAMP(), -- 当前的时间戳 > UNIX_TIMESTAMP('1970-01-01', 'yyyy-MM-dd'), -- 指定本地时间转为时间戳> UNIX_TIMESTAMP('1970-01-01T00:00:00Z', "yyyy-MM-dd'T'HH:mm:ssX"), -- utc时间转为时间戳> UNIX_TIMESTAMP('1970-01-01 00:00:00 UTC', "yyyy-MM-dd HH:mm:ss z") -- utc时间转为时间戳> ;1682168617-28800 0 0Time taken: 0.077 seconds, Fetched 1 row(s)spark-sql>
问题: 如果 UTC 时间有 纳秒, UNIX_TIMESTAMP
spark-sql> select UNIX_TIMESTAMP('1970-01-01 00:00:23.123456789 UTC', "yyyy-MM-dd HH:mm:ss.SSS z");NULL -- 返回空值Time taken: 0.097 seconds, Fetched 1 row(s)spark-sql> 解决select UNIX_TIMESTAMP(concat_ws(' ', substr('1970-01-01 00:00:23.123456789 UTC', 0,19), -- yyyy-MM-dd HH:mm:sssubstr('1970-01-01 00:00:23.123456789 UTC', 31)), -- UTC"yyyy-MM-dd HH:mm:ss z") -- 时间戳 秒值* 1000000000 -- 转为纳秒+ cast (substr('1970-01-01 00:00:23.123456789 UTC', 21,9) as bigint) -- 截取纳秒;
注意 时间的格式 /docs/latest/sql-ref-datetime-pattern.html
3.1.2、to_unix_timestamp
spark-sql> select> to_unix_timestamp('1970-01-01', 'yyyy-MM-dd'), -- 指定本地时间转为时间戳> to_unix_timestamp('1970-01-01T00:00:00Z', "yyyy-MM-dd'T'HH:mm:ssX"), -- utc时间转为时间戳> to_unix_timestamp('1970-01-01 00:00:00 UTC', "yyyy-MM-dd HH:mm:ss z") -- utc时间转为时间戳> ;-28800 0 0
3.2、 时间戳转为指定时间字符串
from_unixtime(unix_time[, fmt])Returns `unix_time` in the specified `fmt`.spark-sql> select from_unixtime(0),> from_unixtime(0, 'yyyy-MM-dd HH:mm:ss'),> from_unixtime(0, 'yyyy-MM-dd HH:mm:ss z');1970-01-01 08:00:001970-01-01 08:00:001970-01-01 08:00:00 CST
3.3、UTC时间与其他时间转化
3.3.1、to_utc_timestamp 指定时间的时间转为 UTC 时间
to_utc_timestamp(timestamp, -- 指定时间timezone) -- 指定分区spark-sql> SELECT to_utc_timestamp('1970-01-01', 'PRC');1969-12-31 16:00:00spark-sql> SELECT to_utc_timestamp('1970-01-01 00:00:00.123456789', 'PRC');1969-12-31 16:00:00.123456
3.3.2、from_utc_timestamp 将utc时间 转为指定时区时间
from_utc_timestamp(timestamp, -- utc时间 timezone) -- 目的时间spark-sql> select from_utc_timestamp('1970-01-01 00:00:23', 'PRC');1970-01-01 08:00:23-- 错误使用spark-sql> select from_utc_timestamp('1970-01-01T00:00:00Z', 'PRC');1970-01-01 16:00:00spark-sql> select from_utc_timestamp('1970-01-01 00:00:00 UTC', 'PRC');1970-01-01 16:00:00