18.TRUNC / LAST_DAY / NEXT_DAY 函数深度解析

Hive TRUNC / LAST_DAY / NEXT_DAY 函数深度解析

目录

  1. 函数概述
  2. [TRUNC 函数详解](#TRUNC 函数详解)
    • [2.1 语法定义](#2.1 语法定义)
    • [2.2 参数详解](#2.2 参数详解)
    • [2.3 核心原理](#2.3 核心原理)
    • [2.4 使用示例](#2.4 使用示例)
  3. [LAST_DAY 函数详解](#LAST_DAY 函数详解)
    • [3.1 语法定义](#3.1 语法定义)
    • [3.2 核心原理与闰年处理](#3.2 核心原理与闰年处理)
    • [3.3 使用示例](#3.3 使用示例)
  4. [NEXT_DAY 函数详解](#NEXT_DAY 函数详解)
    • [4.1 语法定义](#4.1 语法定义)
    • [4.2 参数详解](#4.2 参数详解)
    • [4.3 核心原理](#4.3 核心原理)
    • [4.4 使用示例](#4.4 使用示例)
  5. 跨引擎行为差异与迁移指南
    • [5.1 Hive vs Spark SQL vs Presto/Trino vs MySQL](#5.1 Hive vs Spark SQL vs Presto/Trino vs MySQL)
    • [5.2 迁移检查清单](#5.2 迁移检查清单)
  6. 性能优化与常见问题
    • [6.1 性能优化建议](#6.1 性能优化建议)
    • [6.2 常见问题与避坑指南](#6.2 常见问题与避坑指南)
  7. 总结

1. 函数概述

TRUNCLAST_DAYNEXT_DAY 是 Hive SQL 中三个专门用于日期截断与周期计算的函数。它们共同构成了日期维度分析的重要工具链,在 BI 报表、时间窗口聚合和数据清洗等场景中应用广泛。

  • TRUNC:将日期截断到指定的时间精度(年、月、日等),返回该精度单位的起始点。
  • LAST_DAY:返回指定日期所在月份的最后一天,是计算月末截止日期的核心函数。
  • NEXT_DAY:返回指定日期之后的下一个指定星期几的日期,常用于计算工作日、预约日等业务场景。

这三个函数相辅相成,配合使用可以高效地处理各类周期性日期计算需求。

2. TRUNC 函数详解

2.1 语法定义

sql 复制代码
-- 标准语法
TRUNC(date[, fmt])
  • 引入版本:Hive 1.2.0 开始支持
  • 返回值类型DATESTRING(取决于输入类型)
  • 参数说明
    • date:一个日期值,可以是 DATE 类型或符合标准格式的 STRING
    • fmt:可选参数,指定截断的精度单位。如果省略,则默认截断到天('DD'),即去除时间部分

2.2 参数详解

fmt 参数支持的格式如下:

fmt 取值 含义 说明
'MONTH' / 'MON' / 'MM' 截断到月 返回当月第一天
'YEAR' / 'YYYY' / 'YY' 截断到年 返回当年第一天
'QUARTER' / 'Q' 截断到季度 返回当前季度第一天
省略或 'DD' 截断到天 去除时间部分,仅保留日期

2.3 核心原理

TRUNC 函数的本质是向下舍入:将指定精度以下的所有时间单位清零,返回该精度单位的起始点。它不进行四舍五入,而是直接截断。

重要限制 :Hive 的 TRUNC 函数不支持 小时、分钟、秒等更精细的时间单位截断。如需对时间戳进行更精细的截断(如按小时、分钟),Hive 自身没有对应的原生函数,而 Presto/Trino 的 date_trunc 函数则支持这些粒度。

2.4 使用示例

sql 复制代码
-- 假设当前日期为:2022-11-02

-- 1. 截断到月:返回当月第一天
SELECT TRUNC('2022-11-02', 'MM');    
-- 结果: 2022-11-01

-- 2. 截断到年:返回当年第一天
SELECT TRUNC('2022-11-02', 'YY');    
-- 结果: 2022-01-01

SELECT TRUNC('2022-11-02', 'YYYY');  
-- 结果: 2022-01-01

-- 3. 截断到季度:返回当前季度第一天
SELECT TRUNC('2022-11-02', 'Q');     
-- 结果: 2022-10-01

-- 4. 省略 fmt 参数:去除时间部分(截断到天)
SELECT TRUNC('2022-11-02 15:30:45'); 
-- 结果: 2022-11-02

3. LAST_DAY 函数详解

3.1 语法定义

sql 复制代码
LAST_DAY(date)
  • 引入版本:Hive 1.1.0 开始支持
  • 返回值类型DATESTRING
  • 参数说明date 可以是 DATE 类型或符合 yyyy-MM-dd HH:mm:ssyyyy-MM-dd 格式的字符串
  • 功能:返回指定日期所在月份的最后一天

3.2 核心原理与闰年处理

LAST_DAY 函数在 Hive 1.1.0 之前并不存在,在此之前开发者需要编写复杂的字符串拼接和日期运算公式来模拟月末计算。LAST_DAY 的引入极大简化了 BI 报表中的周期截止日期计算。

该函数能够自动识别闰年,正确处理 2 月的天数。

3.3 使用示例

sql 复制代码
-- 1. 基础用法:获取指定日期所在月份的最后一天
SELECT LAST_DAY('2015-01-14');
-- 结果: '2015-01-31'

-- 2. 闰年 2 月自动处理
SELECT LAST_DAY('2016-02-01');
-- 结果: '2016-02-29'

-- 3. 结合 CURRENT_DATE 获取当月最后一天
SELECT LAST_DAY(CURRENT_DATE());

-- 4. 获取当月天数(结合 DAY 函数)
SELECT DAY(LAST_DAY(CURRENT_DATE())) AS days_in_month;
-- 结果: 当月实际天数

-- 5. 获取上月最后一天
SELECT LAST_DAY(ADD_MONTHS(CURRENT_DATE(), -1));

-- 6. 获取当月第一天(配合 TRUNC)
SELECT TRUNC(CURRENT_DATE(), 'MM') AS first_day_of_month;

4. NEXT_DAY 函数详解

4.1 语法定义

sql 复制代码
NEXT_DAY(start_date, day_of_week)
  • 引入版本:Hive 1.2.0 开始支持
  • 返回值类型DATESTRING
  • 功能 :返回 start_date 之后(不包含当天)的第一个指定星期几的日期

4.2 参数详解

参数 类型 描述
start_date DATE / TIMESTAMP / STRING 起始日期。如果包含时间部分,则时间部分会被忽略
day_of_week STRING 目标星期几,支持 2 字母、3 字母或完整的星期名称,不区分大小写

day_of_week 取值示例:

  • 2 字母'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'
  • 3 字母'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'
  • 完整名称'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'

4.3 核心原理

NEXT_DAY 的核心规则:返回的日期严格大于 start_date 。如果 start_date 本身恰好是指定的星期几,返回的将是下周的同一天,而不是当天。

4.4 使用示例

sql 复制代码
-- 1. 基础用法:获取 2015-01-14 之后的下一个周二
SELECT NEXT_DAY('2015-01-14', 'TU');
-- 结果: 2015-01-20

-- 2. 三种命名方式等价(不区分大小写)
SELECT NEXT_DAY('2020-05-01', 'Fri');    -- 结果: 2020-05-08
SELECT NEXT_DAY('2020-05-01', 'FRIDAY'); -- 结果: 2020-05-08
SELECT NEXT_DAY('2020-05-01', 'FR');     -- 结果: 2020-05-08

-- 3. 获取下周一
SELECT NEXT_DAY('2020-06-14', 'MO');     -- 结果: 2020-06-15

-- 4. 获取当前日期之后的第一个周五
SELECT NEXT_DAY(CURRENT_DATE(), 'FRIDAY');

5. 跨引擎行为差异与迁移指南

5.1 Hive vs Spark SQL vs Presto/Trino vs MySQL

引擎 TRUNC 支持 LAST_DAY 支持 NEXT_DAY 支持 关键差异
Hive TRUNC(date, fmt) LAST_DAY(date) NEXT_DAY(date, dow) 三者均完整支持(Hive 1.2.0+)
Spark SQL ✅ 与 Hive 高度兼容 ✅ 与 Hive 高度兼容 ✅ 与 Hive 高度兼容 语法基本完全兼容 Hive
Presto/Trino ❌ 不支持 TRUNC LAST_DAY_OF_MONTH(date) ❌ 不支持 NEXT_DAY 使用 date_trunc('month', date) 替代 TRUNC
MySQL ❌ 不支持 TRUNC LAST_DAY(date) ❌ 不支持 NEXT_DAY 使用 DATE_FORMAT 或字符串拼接替代

Presto/Trino 中的 date_trunc 函数

Presto/Trino 使用 date_trunc 函数实现日期截断,其语法和参数与 Hive 的 TRUNC 不同,但功能相似且支持的精度单位更丰富(包括 hourminutesecond 等)。

sql 复制代码
-- Presto/Trino 写法:截断到月份
SELECT date_trunc('month', DATE '2022-11-02');
-- 结果: 2022-11-01 00:00:00.000

-- 对应的 Hive 写法
SELECT TRUNC('2022-11-02', 'MM');
-- 结果: 2022-11-01

5.2 迁移检查清单

迁移方向 需检查事项 改写建议
Hive → Presto/Trino TRUNC 函数不兼容 改为 date_trunc('month', date)date_trunc('year', date)
Hive → Presto/Trino NEXT_DAY 函数不兼容 使用 date_add + 模运算自行实现,或改用自定义 UDF
Presto/Trino → Hive LAST_DAY_OF_MONTHLAST_DAY 函数名不同,功能相同,直接替换即可
MySQL → Hive TRUNCNEXT_DAY 不支持 按 Hive 语法改写,MySQL 中通常用 DATE_FORMAT 模拟

6. 性能优化与常见问题

6.1 性能优化建议

  1. 避免在分区字段上使用函数

    sql 复制代码
    -- ❌ 不推荐:分区裁剪失效
    SELECT * FROM logs WHERE TRUNC(dt, 'MM') = '2026-04-01';
    
    -- ✅ 推荐:预先计算好日期范围
    SELECT * FROM logs WHERE dt >= '2026-04-01' AND dt < '2026-05-01';
  2. 物化计算结果:对于频繁使用的周期计算,在 ETL 阶段预先计算并存储,避免每次查询重复计算。

  3. 组合使用提高效率

    sql 复制代码
    -- 利用 LAST_DAY 和 TRUNC 快速获取月初和月末
    SELECT 
        TRUNC(CURRENT_DATE(), 'MM') AS month_start,
        LAST_DAY(CURRENT_DATE()) AS month_end;

6.2 常见问题与避坑指南

问题 原因 解决方案
TRUNC 不支持小时/分钟精度 Hive 的 TRUNC 只支持 YEAR、MONTH、DAY 等级别 如需更精细精度,使用 TO_DATE 或自定义 UDF
NEXT_DAYstart_date 恰好是目标星期几时返回下周 函数定义为返回之后的第一个匹配日期 这是正常行为,如需包含当天,使用 CASE WHEN 判断
LAST_DAY 返回 NULL 输入日期格式不符合 yyyy-MM-dd 先用 FROM_UNIXTIME + UNIX_TIMESTAMP 转换格式
跨引擎迁移时 TRUNC 报错 Presto/Trino 不支持 TRUNC 改用 date_trunc 函数
NEXT_DAY 在 Presto/Trino 中报错 Presto/Trino 不支持该函数 使用 date_add + 模运算自行实现

7. 总结

  • TRUNC :将日期截断到指定精度单位的起始点。支持 'MM'(月)、'YY'(年)、'Q'(季度)和省略时的 'DD'(天)。Hive 1.2.0 引入,不支持小时/分钟等更精细精度。
  • LAST_DAY:返回指定日期所在月份的最后一天。Hive 1.1.0 引入,自动处理闰年,是 BI 报表中周期计算的常用函数。
  • NEXT_DAY:返回指定日期之后的下一个指定星期几。Hive 1.2.0 引入,支持 2 字母、3 字母或完整星期名称,不区分大小写。
  • 跨引擎迁移注意事项 :Spark SQL 与 Hive 高度兼容;Presto/Trino 使用 date_trunc 替代 TRUNC,不支持 NEXT_DAY;MySQL 仅支持 LAST_DAY
  • 性能核心原则:避免在分区字段上直接使用这些函数,以免导致分区裁剪失效。
  • 实战组合TRUNC + LAST_DAY 可快速获取任意月份的起止日期;配合 ADD_MONTHS 可实现前后月份的周期计算。
相关推荐
独隅2 小时前
Git误操作急救手册
大数据·git·elasticsearch
隐于花海,等待花开2 小时前
17.DATE_FORMAT 函数深度解析
大数据·hive
珠海西格电力2 小时前
零碳园区管理系统如何守护能源与数据安全?
大数据·人工智能·分布式·架构·能源
徐礼昭|商派软件市场负责人2 小时前
2026年“服饰行业全渠道OMS系统”库存/订单运营策略:以“一盘货+分渠分级”驱动销售最大化
大数据·人工智能·oms系统·服饰行业库存管理
试剂界的爱马仕2 小时前
AI学习实现:如何给基金实时估值?
大数据·人工智能·科技·学习·机器学习
隐于花海,等待花开3 小时前
15.TO_DATE 函数深度解析
大数据·hive
小的~~3 小时前
排查Flink状态膨胀导致Checkpoint超时的问题
大数据·flink
数智化精益手记局3 小时前
什么是安全生产?解读安全生产的基本方针与核心要求
大数据·运维·人工智能·安全·信息可视化·自动化·精益工程
一个程序猿老马3 小时前
013、推送与拉取:git push与git pull的协作流程
大数据·git·elasticsearch