news 2026/9/19 9:58:02

StarRocks `years_add` 日期时间函数完全指南:语法、示例与源码实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
StarRocks `years_add` 日期时间函数完全指南:语法、示例与源码实现解析

StarRocksyears_add日期时间函数完全指南:语法、示例与源码实现解析

【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks

导读

years_add是 StarRocks 内置的日期时间函数之一,用于在给定日期时间表达式上累加指定年数,广泛服务于数据仓库中的时间窗口计算、滚动年同比分析、计划表日期推算等场景。本文以官方文档为核心,结合 BE(Backend)与 FE(Frontend)源码,讲解其语法、返回类型、NULL 语义、常量折叠优化以及同系列日期加减函数的用法,帮助你准确、高效地使用这一函数。

函数签名与语义

语法

DATETIME YEARS_ADD(DATETIME expr1, INT expr2)
  • expr1:一个合法的日期时间表达式,类型为DATETIME(也支持DATE类型输入,见下文源码说明)。
  • expr2:要累加的年数,类型为INT,可以为正数、负数或 0。

函数返回在expr1基础上增加expr2年后的日期时间,时间单位为expr2为负数时等价于做减法——这也是 BE 源码中years_subyears_add共用同一套实现的原因(见「源码实现解析」一节)。

返回值

  • 输入为DATETIME时,返回DATETIME
  • 输入为DATE时,返回DATE(FE 侧常量折叠路径中专门为{DATE, INT}组合注册了returnType = DATE的重载,见 ScalarOperatorFunctions.java)。

边界行为

  • expr1expr2为 NULL,则结果为 NULL;
  • 若结果日期超出合法范围(如0001-01-01减去多年、9999-12-31加上多年),函数返回 NULL。BE 侧在宏DEFINE_TIME_CALC_FN中通过date_valid<RESULT_TYPE>(p)对计算结果做合法性校验,不合法的时间值会被置空,参见 time_functions.cpp。

使用示例

以下示例来自官方文档,可直接在 StarRocks 中执行验证。

示例一:对完整 DATETIME 累加年份

select years_add('2010-11-30 23:50:50', 2); +-------------------------------------+ | years_add('2010-11-30 23:50:50', 2) | +-------------------------------------+ | 2012-11-30 23:50:50 | +-------------------------------------+

可以看到,日期部分由2010变为2012,时分秒23:50:50保持不变。

示例二:对仅含日期(DATE)的输入累加年份

select years_add('2010-11-30', 2); +----------------------------+ | years_add('2010-11-30', 2) | +----------------------------+ | 2012-11-30 00:00:00 | +----------------------------+

只提供日期时,函数按DATETIME语义处理,时间部分补零为00:00:00

更多实用写法

  • 负年数做回退计算:SELECT years_add('2024-02-29 10:00:00', -4);返回2020-02-29 10:00:00
  • 与当前时间结合:SELECT years_add(now(), 1);返回一年后的此刻。
  • 结合聚合做同比:SELECT years_add(event_date, -1) AS last_year_date, SUM(amount) FROM sales GROUP BY years_add(event_date, -1);可将本年度数据对齐到上一年同期进行比较。

源码实现解析

BE 端:向量化执行

years_add在 BE 端由宏展开生成,位于 time_functions.cpp:

template <TimeUnit UNIT> TimestampValue timestamp_add(TimestampValue tsv, int count) { return tsv.add<UNIT>(count); } #define DEFINE_TIME_ADD_FN(FN, UNIT) \ DEFINE_BINARY_FUNCTION_WITH_IMPL(FN##Impl, timestamp, value) { return timestamp_add<UNIT>(timestamp, value); } \ DEFINE_TIME_CALC_FN(FN, TYPE_DATETIME, TYPE_INT, TYPE_DATETIME); #define DEFINE_TIME_ADD_AND_SUB_FN(FN_PREFIX, UNIT) \ DEFINE_TIME_ADD_FN(FN_PREFIX##_add, UNIT); \ DEFINE_TIME_SUB_FN(FN_PREFIX##_sub, UNIT); // years_add // years_sub DEFINE_TIME_ADD_AND_SUB_FN(years, TimeUnit::YEAR);

要点:

  • years_add被展开为TimeFunctions::years_add向量化函数,输入为TYPE_DATETIMETYPE_INT,输出TYPE_DATETIME,通过VectorizedStrictBinaryFunction对整列数据进行批处理,满足 StarRocks 向量化执行引擎的要求;
  • years_subyears_add共用timestamp_add,只是将count取负,即timestamp_add<UNIT>(timestamp, -value)
  • 同一套宏还生成了quarters_add/submonths_add/subweeks_add/subdays_add/subhours_add/subminutes_add/subseconds_add/submillis_add/submicros_add/sub等全套时间加减函数,时间单位由TimeUnit枚举控制。

TimestampValue::add的底层实现位于 timestamp_value.h:

TimestampValue add(int count) const { return TimestampValue{timestamp::add<UNIT>(_timestamp, count)}; }

它直接调用timestamp::add<UNIT>完成年月日时分秒的进位/借位运算(如闰年 2 月 29 日加 4 年仍映射到 2 月 29 日、加 1 年则映射到 2 月 28 日),并在宏DEFINE_TIME_CALC_FN中通过date_valid检查结果的合法性,非法时间返回 NULL。

FE 端:常量折叠与单调性标记

在查询优化阶段,FE 会对常量输入做预计算(constant folding)。years_add的常量折叠实现位于 ScalarOperatorFunctions.java:

@ConstantFunction.List(list = { @ConstantFunction(name = "years_add", argTypes = {DATETIME, INT}, returnType = DATETIME, isMonotonic = true), @ConstantFunction(name = "years_add", argTypes = {DATE, INT}, returnType = DATE, isMonotonic = true) }) public static ConstantOperator yearsAdd(ConstantOperator date, ConstantOperator year) { if (date.getType().isDate()) { return ConstantOperator.createDateOrNull(date.getDatetime().plusYears(year.getInt())); } else { return ConstantOperator.createDatetimeOrNull(date.getDatetime().plusYears(year.getInt())); } }

两点值得注意:

  1. 双重载{DATETIME, INT} → DATETIME{DATE, INT} → DATE两个签名同时注册,保证 DATE 输入不会丢失日期语义;
  2. isMonotonic = true:标记该函数单调递增,优化器可据此对分区裁剪、排序等做更激进的优化,例如在范围查询中推导出更紧的谓词边界。

执行链路小结

从 SQL 到结果的整体链路为:SQL 解析 → FE 优化器(命中常量则走ScalarOperatorFunctions.yearsAdd直接算出结果)→ 生成执行计划下发 BE → BE 向量化执行TimeFunctions::years_addtimestamp::add<TimeUnit::YEAR>完成计算 →date_valid校验后返回。

常见问题与注意事项

  1. 类型匹配expr2必须是整数;传入小数需要先做类型转换或使用支持小数的函数,否则报错。
  2. 闰年边界years_add('2024-02-29', 1)的结果为2025-02-28,而不是2025-02-29(该日不存在),StarRocks 会做合理的日期归一化。
  3. NULL 传播:任一参数为 NULL 时结果为 NULL;非法日期结果同样返回 NULL,而非抛出异常。
  4. date_add/date_sub的差异years_add固定以「年」为单位,语义明确;如需灵活指定多种单位(年/月/日/时/分/秒),可考虑使用date_add(expr, INTERVAL n YEAR)形式的通用函数。

小结

years_add虽然语法简单,但其背后是 BE 向量化实现、时间单位模板化宏、FE 常量折叠与单调性优化等一整套工程机制。掌握它的签名、边界行为与源码路径,可以让你在实际查询中放心使用,并在需要时快速定位问题(如结果意外为 NULL 时优先检查日期合法性)。

如需了解完整函数族,可查阅 date-time-functions 目录下的各函数文档,或直接阅读 time_functions.cpp 中的宏定义部分。

【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 9:56:24

预装Office 2019失踪怎么办?微软账户授权找回、下载与激活完整指南

买电脑时随机器送的 Office 家庭和学生版 2019&#xff0c;很多人以为就是个图标&#xff0c;点了就能用。真到自己要交作业、打简历的时候&#xff0c;打开 Word 却发现要么提示“需要激活”&#xff0c;要么干脆图标都没了&#xff0c;这才慌了神。更尴尬的是&#xff0c;当时…

作者头像 李华
网站建设 2026/9/19 9:55:52

铝镁合金装配视觉检测设备方案:光学设计与产线集成实战

做汽车零部件装配视觉检测这几年&#xff0c;我最大的感受是&#xff1a;真正难的从来不是算法&#xff0c;而在于光学方案怎么定、现场怎么装、产线节拍怎么配合。今天要讲的这套铝镁合金装配产品视觉检测设备&#xff0c;就是我们团队在多个汽车零部件项目里反复打磨出来的在…

作者头像 李华
网站建设 2026/9/19 9:54:43

Word字体安装全攻略:系统字体库、安装流程与排错指南

你是不是也遇到过这种情况&#xff1a;在网上下载了一份挺漂亮的简历模板&#xff0c;打开一看&#xff0c;里面的字体全是方框和乱码&#xff1b;或者同事发来一份汇报文档&#xff0c;标题用了一种你没见过的字体&#xff0c;本地打开直接变成了宋体&#xff0c;排版全乱。其…

作者头像 李华
网站建设 2026/9/19 9:54:39

Qwen3.8本地部署失败原因与llama.cpp代理方案

1. 为什么“本地部署 Qwen3.8”会成为近期最密集的翻车现场&#xff1f;最近两周&#xff0c;我在三个不同技术群、两个私有知识库和一个硬件开发者论坛里&#xff0c;反复看到同一类求助帖&#xff1a;“no lm runtime found for model format gguf!”、“ollama run qwen3.8:…

作者头像 李华
网站建设 2026/9/19 9:54:30

鸿蒙适配React Native:绝对定位实现稳定模态框方案

1. 为什么鸿蒙上的RN模态框要用绝对定位硬怼先说结论&#xff1a;在React Native跨平台应用跑到鸿蒙设备上之后&#xff0c;你会发现Modal组件有时候就是不听使唤——要么盖不住状态栏&#xff0c;要么弹出来之后页面还能在底下滑动&#xff0c;严重的时候直接在部分机型上白屏…

作者头像 李华