【SQL】SQL的日期与时间函数
一、引言
今天来聊聊 Hive 里日期和时间函数的应用场景。
做数据分析的同学都知道,日期处理绝对是个"高频刚需"------无论是统计报表、用户行为分析,还是考勤打卡、业务指标计算,到处都要跟日期打交道。
Hive 提供了超级丰富的日期函数,用好了能省很多事儿。
今天咱们梳理下 Hive 里常用的日期时间函数系统梳理一遍,配上实战案例,保证你看完就能用上。
- SQL专题往期内容:
二、核心函数一览
先上一个表格,让大家对 Hive 日期函数有个全局印象:
| 函数类别 | 常用函数 | 说明 |
|---|---|---|
| 日期计算 | date_add/date_sub, date_add/minus | 日期加减 |
| 日期差值 | datediff, months_between | 计算日期间隔 |
| 日期提取 | year/month/day/hour/minute/second | 提取日期各部分 |
| 格式化 | date_format, from_unixtime, unix_timestamp | 日期与字符串互转 |
| 时间戳 | unix_timestamp, from_unixtime | 时间戳处理 |
| 其他 | trunc, datetrunc,current_date, now | 日期工具函数 |
三、常见案例枚举
1. 日期计算(加减、差值)
日期加减
sql
-- 当前日期加减N天
SELECT
current_date AS 今日,
date_add(current_date, 7) AS 七天后,
date_sub(current_date, 30) AS 三十天前;
划重点:
date_add和date_sub接受负数,效果反一反就对了。
sql
-- 简单写法:直接用 + - 是不是很神奇~
SELECT
current_date,
current_date + 7, -- 等同于 date_add
current_date - 30; -- 等同于 date_sub
计算日期间隔
sql
-- 计算两个日期相差天数,这里需注意日期格式DATE、DATETIME或TIMESTAMP类型,不然会报错
SELECT
datediff('2026-04-23', '2026-01-01') AS 天数差;
-- 计算月数差(返回小数)
SELECT
months_between('2026-04-23', '2025-01-01') AS 月数差;
划重点:
datediff只计算日期部分,忽略时间;months_between会精确到月。如果用的是阿里云ODPS,SELECT DATEDIFF(TIMESTAMP '2006-01-01 00:00:00', TIMESTAMP '2005-12-31 23:59:59', 'dd') 后面可以限制日期部分为年月日、时分秒都行;
实战:计算用户最近N天活跃
sql
-- 统计近7天有活跃的用户 是不是面试很熟悉?
SELECT user_id,
count(*) AS 活跃天数
FROM user_log
WHERE dt >= date_sub(current_date, 7)
GROUP BY user_id
HAVING count(*) >= 3; -- 至少活跃3天才算
2. 格式化与解析
日期转字符串
sql
-- date_format:灵活格式化
SELECT
current_timestamp AS 当前时间,
date_format(current_timestamp, 'yyyy-MM-dd') AS 日期,
date_format(current_timestamp, 'yyyy-MM-dd HH:mm:ss') AS 完整时间,
date_format(current_timestamp, 'yyyy年MM月dd日') AS 中文格式,
date_format(current_timestamp, 'yyyyMMdd') AS 紧凑格式;
输出示例:
当前时间 | 日期 | 完整时间 | 中文格式 | 紧凑格式
2026-04-23 16:44:00 | 2026-04-23 | 2026-04-23 16:44:00 | 2026年04月23日 | 20260423
字符串转日期
sql
-- 字符串转日期
SELECT
to_date('2026-04-23 16:44:00') AS 日期部分,
to_date('20260423') AS 字符串日期;
-- 指定格式解析
SELECT
from_unixtime(unix_timestamp('23/04/2026', 'dd/MM/yyyy'), 'yyyy-MM-dd') AS 解析后;
划重点:字符串格式不统一时,用
unix_timestamp(str, format)指定格式。
3. 日期提取
sql
-- 提取年月日时分秒
SELECT
current_timestamp AS 时间,
year(current_timestamp) AS 年,
month(current_timestamp) AS 月,
day(current_timestamp) AS 日,
hour(current_timestamp) AS 时,
minute(current_timestamp) AS 分,
second(current_timestamp) AS 秒,
dayofweek(current_timestamp) AS 星期几, -- 1=周日
weekofyear(current_timestamp) AS 第几周;
截断到指定粒度
sql
-- trunc:截断日期
SELECT
current_date AS 今天,
trunc(current_date, 'MM') AS 月初, -- 截断到月
trunc(current_date, 'YY') AS 年初, -- 截断到年
trunc(current_date, 'DD') AS 当天零点; -- 截断到日
划重点:
trunc在Hive里支持 MM(月初)、YY(年初)、DD(日)等格式。
4. 时间戳处理
时间戳互转
sql
-- 当前时间戳
SELECT
unix_timestamp() AS 当前时间戳,
from_unixtime(unix_timestamp()) AS 时间戳转字符串;
-- 指定时间转时间戳
SELECT
unix_timestamp('2026-04-23 16:44:00') AS 指定时间的时间戳;
-- 时间戳转指定格式
SELECT
from_unixtime(1713861840, 'yyyy-MM-dd HH:mm:ss') AS 转日期格式;
毫秒级时间戳
sql
-- 毫秒级时间戳(13位)
SELECT
unix_timestamp() * 1000 AS 毫秒时间戳;
-- 毫秒转日期
SELECT
from_unixtime(1713861840000 / 1000) AS 毫秒转日期;
划重点:Hive 的
unix_timestamp是秒级(10位),Java/JavaScript 是毫秒级(13位),注意换算。
5. 常见业务场景
场景一:考勤打卡统计
sql
-- 统计每人每月上班天数
SELECT
user_id,
name,
date_format(clock_time, 'yyyy-MM') AS 月份,
count(DISTINCT date(clock_time)) AS 上班天数,
sum(case when hour(clock_time) > 9 then 1 else 0 end) AS 迟到次数
FROM attendance
WHERE year(clock_time) = 2026
GROUP BY
user_id,
name,
date_format(clock_time, 'yyyy-MM');
场景二:月报表统计
sql
-- 计算每月的自然月周期
SELECT
trunc(create_time, 'MM') AS 月份,
count(*) AS 新增用户,
sum(payment_amount) AS 成交金额
FROM order_log
WHERE create_time >= date_sub(trunc(current_date, 'MM'), 30) -- 近30个自然月
GROUP BY trunc(create_time, 'MM')
ORDER BY 月份 DESC;
场景三:周环比分析
sql
-- 本周 vs 上周 指标对比
WITH weekly_stats AS (
SELECT
date_format(dt, 'yyyy-iw') AS 周,
sum(pv) AS 总PV,
sum(uv) AS 总UV
FROM page_stats
WHERE dt >= date_sub(current_date, 56) -- 预留8周
GROUP BY date_format(dt, 'yyyy-iw')
)
SELECT
w1.周 AS 本周,
w1.总PV AS 本周PV,
w0.周 AS 上周,
w0.总PV AS 上周PV,
round((w1.总PV - w0.总PV) * 100.0 / w0.总PV, 2) AS 环比增幅百分比
FROM weekly_stats w1
LEFT JOIN weekly_stats w0
ON datediff(to_date(concat(substr(w1.周, 6), '-1')), to_date(concat(substr(w0.周, 6), '-1'))) = 7
WHERE w1.周 = date_format(current_date, 'yyyy-iw');
四、总结对比
| 场景 | 推荐函数 |
|---|---|
| 日期加减 | date_add / date_sub 或 +/- |
| 计算差值 | datediff/ months_between |
| 提取部分 | year month day hour 等 |
| 日期格式化 | date_format(from, to) |
| 字符串转日期 | to_date / unix_timestamp(str, format) |
| 时间戳互转 | unix_timestamp / from_unixtime |
| 日期截断 | trunc(date, unit) |
最后给个小建议:日常写 SQL 时,能用 日期函数 就不用字符串拼接,日期函数比字符串拼接解析稳定且高效,而且跨版本兼容性更好。
好了,今天的分享就到这里,觉得有用动动小手点赞+关注+收藏,一键三连~ 有问题留言沟通啦~