HQL时间函数应用

一、Hive时间函数的应用

第一节、时间函数(初级)

1、获取当前系统时间

1.1获取当前时间戳 current_timestamp 返回值:timestamp
select current_timestamp();
返回结果:2023-08-14 19:39:54.041 
1.2 获取当前时间 current_date 返回值:date
select current_date();
返回结果:2023-08-14  
1.3 仅Spark sql支持:now()获取当前时间
select now();
返回结果:2023-09-20 14:27:30.955

2、当前UNIX时间戳: unix_timestamp() 返回值:bigint

2.1 获取当前UNIX时间戳函数

函数

格式

返回值

说明

unix_timestamp

unix_timestamp()

bigint

获得当前时区的UNIX时间戳

select unix_timestamp();
1472105939
2.2 日期转UNIX时间戳函数--转换格式为"yyyy-MM-dd HH:mm:ss"

函数

格式

返回值

说明

unix_timestamp

unix_timestamp(string date)

bigint

转换格式为"yyyy-MM-dd HH:mm:ss"的日期到UNIX时间戳。

转化失败,则返回0

select unix_timestamp('2016-08-25 13:02:03');
1472101323
2.3 指定格式日期转UNIX时间戳函数unix_timestamp--转换格式为"yyyyMMdd HH:mm:ss"

函数

格式

返回值

说明

unix_timestamp

unix_timestamp(string date, string pattern)

bigint

转换格式为"yyyyMMdd HH:mm:ss"的日期到UNIX时间戳。转化失败,则返回0

select unix_timestamp('20160825 13:02:03','yyyyMMdd HH:mm:ss');
1472101323

总结:

unix_timestamp : 转换成时间戳,他是可以将符合时间格式转换成按秒计数的函数。例如:'YYYY-MM-DD','YYYYMMDD','YYYY/MM/DD',以及后面的时分秒。

3、日期函数UNIX时间戳转日期函数:from_unixtime() 返回值:string

函数

格式

返回值

说明

from_unixtime

from_unixtime(bigint unixtime[, string format])

string

转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式

hive (temp)> select from_unixtime(1323308943,'yyyyMMdd') ;
20111208
hive (temp)> select from_unixtime(1323308943,'yyyy-MM-dd');
2011-12-08

  

eg1:获取当前时间:年月日格式
select from_unixtime(unix_timestamp(),'yyyy-MM-dd');
2023-08-14

eg2:获取当前时间 时分秒格式:yyyy-MM-dd HH:mm:ss
select from_unixtime(unix_timestamp(),'yyyy-MM-dd HH:mm:ss');
2023-08-14 17:39:21 

4,date_format日期格式提取转换

date_format(date/timestamp/string ts, string fmt) 返回值:string

将date/timesatmp/str转化为日期格式fmt指定格式的字符串值

注意:日期字符串必须满足yyyy-MM-dd格式  

Hive应用:提取年份
select date_format('2021-10-20','yyyy');
2021
Spark应用:小时取整
取小时(可加:00)
select date_format(now(),'HH:00');
15:00


取秒
select date_format(now(),'ss');
50

5、日期时间转日期函数: to_date():日期时间字段中的日期(年月日)部分 返回值:string

函数

格式

返回值

说明

to_date

to_date(string timestamp)

string

返回日期时间字段中的日期部分

select to_date('2023-12-08 10:03:01') ;
2023-12-08

6、年月日秒周提取

日期提取年函数: year()

函数

格式

返回值

说明

year

year(string date)

int

返回日期中的年

hive (temp)> select year('2016-12-08 10:03:01');
2016


hive (temp)> select year('2016-12-08');
2016
日期提取月函数: month()

函数

格式

返回值

说明

month

month(string date)

int

返回日期中的月份

hive (temp)> select month('2016-12-08 10:03:01') ;
12


hive (temp)> select month('2016-11-08') ;
11
日期提取天函数: day()

函数

格式

返回值

说明

day

day(string date)

int

返回日期中的天

hive (temp)> select day('2016-12-08 10:03:01') from dual;
8


hive (temp)> select day('2016-11-18') from dual;
18
日期提取小时函数: hour()

函数

格式

返回值

说明

hour

hour(string date)

int

返回日期中的小时

hive (temp)> select hour('2016-12-08 10:03:01') ;
10
日期提取分钟函数: minute()

函数

格式

返回值

说明

minute

minute(string date)

int

返回日期中的分钟

hive (temp)> select minute('2016-12-08 10:03:01') from dual;
3
日期提取秒函数: second()

函数

格式

返回值

说明

second

second(string date)

int

返回日期中的秒

hive (temp)> select second('2016-12-08 10:03:01') from dual;
1
日期提取周函数: weekofyear()当前日期是该年的第几周

函数

格式

返回值

说明

weekofyear

weekofyear(string date)

int

返回日期在当前的周数

select weekofyear('2016-12-08 10:03:01');
49
日期提取天函数: dayofyear()当前日期是一年的第几天
select dayofyear('2016-12-08 10:03:01');

7、日期比较函数: datediff(string enddate, string startdate)

函数

格式

返回值

说明

datediff

datediff(string enddate, string startdate)

int

返回结束日期减去开始日期

的天数

eg1 :计算给定的2个时间节点之间的天数差
---计算给定的2个时间节点之间的天数差
select datediff('2023-12-08','2023-08-02') ;    ---128天

eg2:计算当前时间 到 2023-11-18 的天数差
----计算当前时间 到 2023-11-18 的天数差
select datediff('2023-11-18',from_unixtime(unix_timestamp(),'yyyy-MM-dd'));    
96天

8、日期增加函数: date_add(string startdate, int days)

函数

格式

返回值

说明

date_add

date_add(string startdate, int days)

string

返回开始日期startdate增加days天后的日期

hive (temp)> select date_add('2016-12-08',10);
2016-12-18
eg:当前日期基础上加7天
#当前日期基础上加7天
select date_add(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),7);

9、日期减少函数:date_sub (string startdate, int days)

函数

格式

返回值

说明

date_sub

date_sub(string startdate, int days)

string

返回开始日期startdate减少days天后的日期

hive (temp)> select date_sub('2016-12-08',10);
2016-11-28
eg:当前日期基础上减7天
select date_sub(from_unixtime(unix_timestamp(),'yyyy-MM-dd'),7) ;
2016-08-18

10、 获取某月最后一天last_day(expr)

expr一个 DATE 表达式

SELECT last_day('2023-02-12');
2023-02-28

11、next_day(expr, dayOfWeek) 获取当前日期的下一周里“星期几”的日期

next_day(STRING start_date, STRING day_of_week)返回 当前日期下个 周几的 日期;

例1:求当前日期的下周一,day_of_week 参数输入的是MO,则返回的是下周周一的日期;

SELECT next_day(current_date(), 'MO')
2023-09-25

第二个参数:周几缩写(可以小写)或全称:

下个周一(‘MO’)、下个周二(‘TU’)、下个周三(‘WE’)、下个周四(‘TH’)、下个周五(‘FR’)、下个周六(‘SA’)、下个周日(‘SU’);

例2:返回指定日期的‘2023-08-15’下个周一的日期

SELECT next_day('2023-08-15', 'TU');
2023-08-22
-- 除了周一,其他不适用,需要更新
-- 本周一
SELECT date_add(next_day(current_date(), 'MO'), -7)
-- 上周一
SELECT date_add(next_day(current_date(), 'MO'), -14)
-- 下周一
SELECT next_day(current_date(), 'MO')
-- 下下周一
SELECT date_add(next_day(current_date(), 'MO'), 7)

12、求“时间”为当年的第几季度(仅spark3支持)

select quarter('2023-09-20')
返回结果:3

第二节、时间函数(中级--年月加减)

1、add_months月份加减

add_months函数,负数代表往历史方向减月份, 正数代表往未来方向加月份

举例:当前时间的上个月这个时间

select add_months(CURRENT_DATE,-1) ;
返回结果:2023-08-19 

2、取当前格式化时间的前30天

select from_unixtime(unix_timestamp('2023-09-19','yyyy-MM-dd')-30*86400,'yyyy-MM-dd');
返回结果:2023-08-20 

3、trunc():获取本月第一天

select trunc('2023-09-19','MM');
返回结果: 2023-09-01 

3.1 trunc():获取上个月第一天
select add_months(trunc('2023-09-19','MM'),-1);
返回结果:2023-08-01 
3.2 trunc():获取下个月第一天
select add_months(trunc('2023-09-19','MM'),1);
返回结果:2023-10-01
3.3 trunc():获取本月最后一天
select date_sub(trunc(add_months('2023-09-19',1),'MM'),1);
返回结果:2023-09-30 
3.4 trunc():获取上个月最后一天下个月最后一天
select date_sub(trunc('2023-09-20','MM'),1);
返回结果:2023-08-31   2023-10-31
3.5 trunc():获取下个月最后一天
select date_sub(trunc(add_months('2023-09-20',2),'MM'),1);
返回结果:2023-10-31
3.6 trunc():获取当年第一天
select trunc('2023-09-19','YY');
返回结果: 2023-01-01 
3.7 trunc():获取当年最后一天

4、last_day(STRING date) :返回月末日期

返回月末日期,返回的是 "yyyy-MM-dd"格式的日期。

5、获取本周任意一天

6、每天的上周日–本周六:

应用场景:统计每周的访问量、点击次数等等

每天的上周日:

select date_sub(next_day('2023-09-20','MO'),8);
返回结果:2023-09-17

每天的本周六:

select date_sub(next_day('2023-09-20','MO'),2);
返回结果:2023-09-23

7、months_between 两个日期之间的月数(仅spark3支持)

select months_between ('2023-09-20','1992-11-18');
370.06451613

第三节、时间函数应用案例(同比or环比)

1、同比和环比概念

SQL同比环比_sql 环比-CSDN博客^v94^insert_down1&utm_term=%E5%90%8C%E6%AF%94%E7%8E%AF%E6%AF%94sql&spm=1018.2226.3001.4187

数据分析SQL环比增长率、同比增长率_大数据sql 年环比-CSDN博客^v94^insert_down1&spm=1018.2226.3001.4187

二、时间函数应用的异常案例

1,json中提取时间戳

示例:

info对应的字段值为如:48330a9a94d73db188c78ae6bdc58cbe|0|5|0|11|cxvideo_relate|1605655303|1|516||0|OvPMS|0|92201|1605655303076e5630d435593||a|2|0|comos%3Aiznctke14900

需求:

要拿到时间戳并转换为小时从经过group by操作的表中抽取出来

分析:

split分割值,拿到时间戳1605655303 ,然后转换为bigint后再转换为hour函数需要的时间格式的形式,再利用Hour函数读取其中的小时出来。具体代码形如:

max(hour(from_unixtime(cast(split(info,'\\\|')[6] as BIGINT),'yyyy-MM-dd HH:mm:ss'))) as hour

2,数据类型不一致报错

报错:

Caused by: java.lang.ClassCastException: java.sql.Timestamp cannot be cast to java.lang.String

at java.lang.String.compareTo(String.java:111)

at org.apache.hadoop.hive.ql.io.orc.RecordReaderImpl.compareToRange(RecordReaderImpl.java:2295)

atorg.apache.hadoop.hive.ql.io.orc.RecordReaderImpl.evaluatePredicateRange(RecordReaderImpl.java:2444)at org.apache.hadoop.hive.ql.io.orc.RecordReaderImpl.evaluatePredicate(RecordReaderImpl.java:2383)

at org.apache.hadoop.hive.ql.io.orc.RecordReaderImpl.pickRowGroups(RecordReaderImpl.java:2595)

at org.apache.hadoop.hive.ql.io.orc.RecordReaderImpl.readStripe(RecordReaderImpl.java:2658)

原代码:
SELECT 
    date_format(a.start_time, 'yyyy-MM-dd') AS `date`
FROM 
    a
WHERE 
AND a.start_time < date_sub(CURRENT_DATE(),-8)

根本原因:

等式两边数据类型不一致。timestamp函数date类型string类型比较大小时,需要先将timestamp类型转成date类型再去比较。(方法不唯一,应该是只要能进行自动类型转换就可以比较)

解决办法:

把a.start_time的int/string数值类型转换成date类型即可与右边比较

from_unixtime(unix_timestamp( a.start_time, 'yyyyMMdd') , 'yyyy-MM

-dd') < date_sub(CURRENT_DATE(),-8)

3,date_format 报错NULL值

案例1:提取2015/04/08中的年

select date_format('2015/04/08', 'y');

--null 识别不了/ 这种分隔符

解决办法:regexp_replace替换

select date_format(regexp_replace('2015/04/08', '/', '-'), 'y');
--2015

----------------------------------------------------------分割线君---------------------------------------------------------

案例2:提取2015/04/08中的月份or年月

select month('2015/04/08');

--null 无法识别

解决办法:

1,提取年月

select date_format(regexp_replace('2015/04/08', '/', '-'), 'y-MM');
--2015-04    

2,提取月:先将2015/04/08替换成 2015-04-08

select month(regexp_replace('2015/04/08', '/', '-'));
-- 4 

----------------------------------------------------------分割线君-----------------------------------------------------------

案例3:比较字段dayno时间大小取值范围

select date_format ('20230809','yyyy-MM-dd');

---NULL 报错空值

原因:

因为这里的dayno字段是20230809 int或string,并非date/timestamp/string ts类型,识别不到所以null异常

解决办法:

第一步:unix_timestamp先将20230809转换为时间戳

select unix_timestamp('20230809', 'yyyyMMdd')
1691510400 

第二步:from_unixtime再将上一步时间戳转换为年月日格式

select from_unixtime(unix_timestamp('20230809', 'yyyyMMdd') , 'yyyy-MM
-dd');
2023-08-09 

总 结

date_format 的语法:

date_format(date/timestamp/string ts, string fmt)

  • date_format函数如果第一个参数是字符串,连接符只能是-,别的都识别不了

4,yyyy-MM-dd大小写导致报错

问题背景:

任务需求查询获取dayno往前一天的数据,但这里的dayno每到月底的那一天就会直接读到该月的第一天,例如20230731这天需求是20230801这天的数据,但异常表现是读到20230701

select model, from_unixtime(unix_timestamp(dayno, 'yyyymmdd')+86400, 'yyyy-mm-dd') as dayno from wireless.wireless_daily_network_kpi_aggr  where dayno = 20230731 limit 100

原因:date数据类型大小写导致

因为这里的'yyyymmdd'中的mm是分钟,不是MM月

'yyyymmdd'中的mm是分钟,不是MM月

解决办法:改写mm大小写

select model, from_unixtime(unix_timestamp(dayno, 'yyyyMMdd')+86400, 'yyyy-MM-dd') as dayno from wireless.wireless_daily_network_kpi_aggr  where dayno = 20230731 limit 100

5,spark 任务报错

Spark任务报错异常:

java.lang.AssertionError: assertion failed

at scala.Predef$.assert(Predef.scala:208)

at org.apache.spark.sql.catalyst.util.DateTimeUtils$.extractSpecialValue

原因:date函数转变字段数值类型异常

三,其他

1,Hive中时区计算

Hive SQL 支持处理时间和日期数据类型,但其内置函数对于直接处理时区计算相对有限。Hive 通常默认使用服务器所在的时区,如果需要处理不同时区的数据,你通常需要自己实现逻辑或使用UDF(用户定义函数)。

时区相关计算,比如手动偏移时间:

SELECT from_utc_timestamp('2023-01-01 00:00:00', '+08:00') as beijing_time;
这将返回 UTC 时间加上 8 小时的时间,大致模拟北京时间(UTC+8)。

更复杂的时区转换需要以下方法:

计算时区差异:

如果是两个已知时区的时间计算,你可以自行计算时间差并进行加减。例如,从 UTC 转换到 UTC+8:

SELECT date_add(your_timestamp_column, INTERVAL 8 HOURS) FROM your_table;

使用 UDF:

如果 Hive 的内置函数不满足需求,你可以使用 Java 或其他支持的语言编写自定义的 UDF 来进行时区的转换操作。

外部工具处理:

在某些情况下,你可能需要在将数据加载到 Hive 之前或在从 Hive 中提取数据后,在外部使用程序或脚本进行时区转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值