HarmonyOs应用《重要日》开发第7篇 - 日期处理:dayjs 集成与 DateUtil 封装
本篇深入讲解 ImportantDays 项目中日期处理的核心工具类 DateUtil它基于 dayjs 库封装了所有日期计算逻辑包括倒数计算、重复事件处理、日期格式化等。一、为什么选择 dayjs1.1 dayjs 简介dayjs 是一个轻量级的 JavaScript 日期处理库API 设计与 moment.js 兼容但体积只有 2KB。在 HarmonyOS 的 ArkTS 环境中dayjs 通过 OpenHarmony 包管理器安装使用。1.2 对比原生 Date API// 原生 Date计算两个日期相差天数constdiffMath.floor((newDate(2026-03-15).getTime()-newDate(2026-01-01).getTime())/86400000);// dayjs同样的计算constdiffdayjs(2026-03-15).diff(dayjs(2026-01-01),day);dayjs 的优势API 简洁链式调用代码可读性高功能丰富日期加减、比较、格式化一站式解决不可变性操作返回新对象不修改原对象轻量压缩后仅 2KB二、DateUtil 工具类2.1 完整实现// utils/DateUtil.etsimportdayjsfromdayjs;import{YearMonth}from../types/Types;exportclassDateUtil{// 获取今天的日期字符串statictoday():string{returndayjs().format(YYYY-MM-DD);}// 格式化日期staticformatDate(date:string,format:stringYYYY-MM-DD):string{returndayjs(date).format(format);}// 计算两个日期之间的天数差staticdaysBetween(fromDate:string,toDate:string):number{constfromdayjs(fromDate);consttodayjs(toDate);returnto.diff(from,day);}// 计算从今天到目标日期的天数正未来负过去staticdaysFromToday(targetDate:string):number{returnDateUtil.daysBetween(DateUtil.today(),targetDate);}// 判断是否是今天staticisToday(date:string):boolean{returndayjs(date).isSame(dayjs(),day);}// 判断是否在本月staticisThisMonth(date:string):boolean{returndayjs(date).isSame(dayjs(),month);}// 根据偏移量获取年月staticgetYearMonth(offset:number):YearMonth{constddayjs().add(offset,month);return{year:d.year(),month:d.month()1};}// 从日期字符串获取年月staticgetYearMonthFromDate(date:string):YearMonth{constddayjs(date);return{year:d.year(),month:d.month()1};}// 获取某月的天数staticgetDaysInMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).daysInMonth();}// 获取某月第一天是星期几0周日6周六staticgetFirstDayOfMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).date(1).day();}// 格式化年月显示staticformatYearMonth(year:number,month:number):string{return${year}年${month}月;}// 格式化中文日期staticformatDateChinese(date:string):string{constddayjs(date);return${d.year()}年${d.month()1}月${d.date()}日;}// 获取下一次重复日期staticgetNextOccurrence(date:string,repeatType:number):string{consttargetdayjs(date);constnowdayjs();if(repeatType1){// 每年letnexttarget.year(now.year());if(next.isBefore(now,day)||next.isSame(now,day)){nextnext.year(now.year()1);}returnnext.format(YYYY-MM-DD);}elseif(repeatType2){// 每月letnexttarget.year(now.year()).month(now.month());if(next.isBefore(now,day)||next.isSame(now,day)){nextnext.add(1,month);}returnnext.format(YYYY-MM-DD);}returndate;}// 获取星期标签staticgetWeekLabel(date:string):string{constdaydayjs(date).day();constlabels[周日,周一,周二,周三,周四,周五,周六];returnlabels[day];}// 日期加减天数staticaddDays(date:string,days:number):string{returndayjs(date).add(days,day).format(YYYY-MM-DD);}// 生成唯一IDstaticgenerateId():string{return${Date.now()}_${Math.floor(Math.random()*10000)};}}三、核心方法详解3.1 日期差计算staticdaysFromToday(targetDate:string):number{returnDateUtil.daysBetween(DateUtil.today(),targetDate);}staticdaysBetween(fromDate:string,toDate:string):number{constfromdayjs(fromDate);consttodayjs(toDate);returnto.diff(from,day);}返回值含义正数目标日期在未来还有 X 天负数目标日期在过去已过 X 天零就是今天这个方法是整个应用倒数/正数功能的基础。3.2 重复事件的下一次日期staticgetNextOccurrence(date:string,repeatType:number):string{consttargetdayjs(date);constnowdayjs();if(repeatType1){// 每年重复letnexttarget.year(now.year());// 替换为今年if(next.isBefore(now,day)||next.isSame(now,day)){nextnext.year(now.year()1);// 如果今年已过或就是今天推到明年}returnnext.format(YYYY-MM-DD);}if(repeatType2){// 每月重复letnexttarget.year(now.year()).month(now.month());// 替换为本月if(next.isBefore(now,day)||next.isSame(now,day)){nextnext.add(1,month);// 如果本月已过或就是今天推到下月}returnnext.format(YYYY-MM-DD);}returndate;// 不重复返回原日期}逻辑流程以每年重复为例原始日期: 2020-03-15今天: 2026-07-15 1. target dayjs(2020-03-15) 2. next target.year(2026) 2026-03-15 3. 2026-03-15 2026-07-15已过→ next next.year(2027) 2027-03-15 4. 返回 2027-03-153.3 闰年处理staticgetDaysInMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).daysInMonth();}dayjs 内部自动处理闰年。例如DateUtil.getDaysInMonth(2024,2);// 29闰年DateUtil.getDaysInMonth(2025,2);// 28平年3.4 月初星期计算staticgetFirstDayOfMonth(year:number,month:number):number{returndayjs().year(year).month(month-1).date(1).day();}返回值 0-6 对应周日到周六。用于日历视图中确定第一行需要留多少空位。3.5 中文格式化staticformatDateChinese(date:string):string{constddayjs(date);return${d.year()}年${d.month()1}月${d.date()}日;}staticformatYearMonth(year:number,month:number):string{return${year}年${month}月;}注意 dayjs 的month()返回 0-11所以需要 1。四、在项目中的使用场景4.1 列表页计算倒数天数// MainViewModel.getCountText()consteffectiveDatethis.getEffectiveDate(day);constdaysDateUtil.daysFromToday(effectiveDate);// days 0: X天后// days 0: X天前// days 0: 今天4.2 日历页生成月份数据// CalendarDataSource.generateMonth()constdaysInMonthDateUtil.getDaysInMonth(d.year,d.month);constfirstDayOfWeekDateUtil.getFirstDayOfMonth(d.year,d.month);// 用这些数据生成 42 格日历6行 x 7列4.3 日历页标记今天// CalendarGridView.dayCell()privateisToday(date:string):boolean{returnDateUtil.isToday(date);}4.4 统计本月重要日// MainViewModel.getStats()if(DateUtil.isThisMonth(effectiveDate)){thisMonth;}4.5 日历查询按月日匹配// MainViewModel.getDaysForDate()if(day.repeatTypeRepeatType.YEARLY){constdayMonthDateUtil.formatDate(day.date,MM-DD);consttargetMonthDateUtil.formatDate(date,MM-DD);returndayMonthtargetMonth;}五、dayjs 在 ArkTS 中的注意事项5.1 导入方式importdayjsfromdayjs;在 oh-package.json5 中声明依赖{ dependencies: { dayjs: ^1.11.13 } }5.2 链式调用dayjs 支持链式调用但需要注意 ArkTS 的类型推断// 正确分步调用constddayjs().year(year).month(month-1);constdaysd.daysInMonth();// 也可以链式调用constdaysdayjs().year(year).month(month-1).daysInMonth();5.3 不可变性dayjs 对象是不可变的每次操作返回新对象constadayjs(2026-01-01);constba.add(1,month);// a 仍然是 2026-01-01// b 是 2026-02-01这在 ArkUI V2 的响应式系统中很重要——不会意外修改被Trace观察的对象。六、扩展思考6.1 时区处理当前项目没有考虑时区问题。如果需要国际化可以使用 dayjs 的 UTC 插件importutcfromdayjs/plugin/utc;dayjs.extend(utc);constutcDatedayjs.utc(2026-03-15);6.2 相对时间如果需要显示3小时后这样的相对时间可以使用 dayjs 的 relativeTime 插件。但本项目只精确到天不需要。6.3 自定义解析dayjs 默认能解析YYYY-MM-DD格式。如果需要解析其他格式dayjs(2026年3月15日,YYYY年M月D日);七、小结DateUtil 作为项目的日期处理核心封装了 dayjs 的常用操作提供了简洁的静态方法接口。从倒数计算到重复事件处理从日期格式化到日历数据生成所有日期相关的逻辑都集中在这里提高了代码的可维护性和可测试性。

相关新闻

HarmonyOs应用《重要日》开发第6篇 - 数据持久化存储

HarmonyOs应用《重要日》开发第6篇 - 数据持久化存储

本篇深入剖析 ImportantDays 项目的数据持久化方案——基于 HarmonyOS ArkData 模块的 Preferences 轻量级存储,以及 PreferenceUtil 工具类的单例封装。一、HarmonyOS 数据存储方案对比 HarmonyOS 提供了多种数据存储方案:方案适用场景特点Preferences轻…

2026/7/16 0:10:39阅读更多 →
MT25QL512ABB8ESF-0SIT选型指南:工业级vs车规级NOR闪存对比与应用选型建议

MT25QL512ABB8ESF-0SIT选型指南:工业级vs车规级NOR闪存对比与应用选型建议

MT25QL512ABB8ESF-0SIT:美光工业级512Mb串行NOR闪存深度解析在工业控制、通信设备、医疗仪器以及物联网网关等对存储容量、数据可靠性和工作温度范围有综合要求的应用领域,系统设计需要在存储性能、引脚数量和长期供货保障之间进行权衡。与车规级版本相比…

2026/7/16 0:10:39阅读更多 →
鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析

鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析

鸿蒙 ArkTS 实战:Car Wash Weather Table 从出行记录到状态反馈完整解析 前言 Car Wash Weather Table 是一个面向 出行管理与通勤习惯 的鸿蒙 ArkTS 小应用。记录出行条目、站点信息和提醒备注,适合日常出行复盘。 本文基于 entry/src/main/ets/pages…

2026/7/16 0:10:39阅读更多 →
独立站建设与外贸GEO:海外流量渠道演变中的两个基础模块

独立站建设与外贸GEO:海外流量渠道演变中的两个基础模块

外贸企业在拓展海外市场时,线上营销渠道的选择日益多样。独立站建设和外贸GEO作为当前被较多讨论的两个方向,分别对应着不同的流量场景。乐云SEO在服务出海企业的过程中注意到,理解这两个模块各自的作用以及它们之间的关联,有助于…

2026/7/16 1:20:50阅读更多 →
从官方到自研:MateBook X Pro 2020 升级 1T 固态的决策、拆解与兼容性验证

从官方到自研:MateBook X Pro 2020 升级 1T 固态的决策、拆解与兼容性验证

1. 官方服务 vs 自行动手:升级决策的关键考量刚拿到MateBook X Pro 2020时,512GB的存储空间对于日常办公看似够用,但当我开始安装专业软件、存放项目文件后,存储焦虑就来了。这时候面临两个选择:走官方渠道花3000元升级…

2026/7/16 1:20:50阅读更多 →
炉石传说脚本:7倍效率提升的智能自动化游戏助手

炉石传说脚本:7倍效率提升的智能自动化游戏助手

炉石传说脚本:7倍效率提升的智能自动化游戏助手 【免费下载链接】Hearthstone-Script Hearthstone script(炉石传说脚本) 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script Hearthstone-Script是一款基于Java和Kotlin…

2026/7/16 1:20:50阅读更多 →
现代C++学习指南:从核心概念到实战项目开发

现代C++学习指南:从核心概念到实战项目开发

1. 为什么是C?一个老兵的视角如果你点开这篇文章,大概率是想知道“C到底值不值得学”,或者“从零开始学C,会不会太难”。作为一个写了十几年C,从单片机驱动写到大型游戏引擎的老兵,我的答案是:值…

2026/7/16 1:20:50阅读更多 →
ECS架构深度解析:从数据局部性到高性能游戏场景管理

ECS架构深度解析:从数据局部性到高性能游戏场景管理

1. 项目概述与核心价值最近在和朋友聊起游戏引擎架构时,总是绕不开ECS这个话题。无论是Unity的DOTS,还是Unreal Engine 5在底层做的各种数据导向优化,ECS似乎成了现代高性能游戏开发的“标配”。但说实话,很多资料要么讲得太理论&…

2026/7/16 1:20:50阅读更多 →
多Agent协同系统设计:从单模型到可调度数字产线

多Agent协同系统设计:从单模型到可调度数字产线

1. 项目概述:这不是“调用API”,而是构建一个能自主协同的数字工人班组你有没有试过让一个AI助手帮你查资料、写周报、整理会议纪要——结果它卡在“把Excel里第三列数据按日期倒序排列”这一步,反复确认格式,最后还漏掉了两行&am…

2026/7/16 1:15:49阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/15 6:42:19阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/15 6:12:45阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/15 10:54:00阅读更多 →
A--10 Codex Review与GitHub PR工作流实战指南:从代码审查到安全合并

A--10 Codex Review与GitHub PR工作流实战指南:从代码审查到安全合并

摘要:本文系统讲解如何利用Codex App的Review功能与GitHub PR工作流,实现从代码修改到安全合并的完整流程。涵盖Review面板深度使用、/review命令实战、GitHub Connector配置、PR描述撰写技巧,以及常见问题排查方法。通过多个实战案例和流程图,帮助开发者建立高效的AI辅助代…

2026/7/16 0:00:38阅读更多 →
遗传算法解5皇后问题:从Hello World到工业优化的进化实验室

遗传算法解5皇后问题:从Hello World到工业优化的进化实验室

1. 项目概述:为什么用遗传算法解5皇后问题,而不是直接回溯?我带过十几届算法课,也给不少初创团队做过AI架构咨询。每次讲到组合优化问题,学生和工程师的第一反应永远是“写个回溯试试”。这没错——55棋盘上找所有合法…

2026/7/16 0:00:38阅读更多 →
5.1V稳压管输出为何只有4.7V?工作电流与负载影响分析

5.1V稳压管输出为何只有4.7V?工作电流与负载影响分析

前几天调试一个简单的电源模块,用到了5.1V稳压管。电路接好,上电测试,万用表一量——输出居然只有4.7V。第一反应是稳压管坏了,换了一个新的,结果还是4.7V。这让我想起很多初学者都会遇到的困惑:明明标称5.…

2026/7/16 0:00:38阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/15 15:50:47阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/15 8:52:38阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/15 14:06:23阅读更多 →