当前位置: 首页 > news >正文

HarmonyOs应用《重要日》开发第7篇 - 日期处理:dayjs 集成与 DateUtil 封装

本篇深入讲解 ImportantDays 项目中日期处理的核心工具类 DateUtil,它基于 dayjs 库封装了所有日期计算逻辑,包括倒数计算、重复事件处理、日期格式化等。

一、为什么选择 dayjs?

1.1 dayjs 简介

dayjs 是一个轻量级的 JavaScript 日期处理库,API 设计与 moment.js 兼容,但体积只有 2KB。在 HarmonyOS 的 ArkTS 环境中,dayjs 通过 OpenHarmony 包管理器安装使用。

1.2 对比原生 Date API

// 原生 Date:计算两个日期相差天数constdiff=Math.floor((newDate('2026-03-15').getTime()-newDate('2026-01-01').getTime())/86400000);// dayjs:同样的计算constdiff=dayjs('2026-03-15').diff(dayjs('2026-01-01'),'day');

dayjs 的优势:

  • API 简洁:链式调用,代码可读性高
  • 功能丰富:日期加减、比较、格式化一站式解决
  • 不可变性:操作返回新对象,不修改原对象
  • 轻量:压缩后仅 2KB

二、DateUtil 工具类

2.1 完整实现

// utils/DateUtil.etsimportdayjsfrom'dayjs';import{YearMonth}from'../types/Types';exportclassDateUtil{// 获取今天的日期字符串statictoday():string{returndayjs().format('YYYY-MM-DD');}// 格式化日期staticformatDate(date:string,format:string='YYYY-MM-DD'):string{returndayjs(date).format(format);}// 计算两个日期之间的天数差staticdaysBetween(fromDate:string,toDate:string):number{constfrom=dayjs(fromDate);constto=dayjs(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{constd=dayjs().add(offset,'month');return{year:d.year(),month:d.month()+1};}// 从日期字符串获取年月staticgetYearMonthFromDate(date:string):YearMonth{constd=dayjs(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{constd=dayjs(date);return`${d.year()}${d.month()+1}${d.date()}`;}// 获取下一次重复日期staticgetNextOccurrence(date:string,repeatType:number):string{consttarget=dayjs(date);constnow=dayjs();if(repeatType===1){// 每年letnext=target.year(now.year());if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.year(now.year()+1);}returnnext.format('YYYY-MM-DD');}elseif(repeatType===2){// 每月letnext=target.year(now.year()).month(now.month());if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.add(1,'month');}returnnext.format('YYYY-MM-DD');}returndate;}// 获取星期标签staticgetWeekLabel(date:string):string{constday=dayjs(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{constfrom=dayjs(fromDate);constto=dayjs(toDate);returnto.diff(from,'day');}

返回值含义:

  • 正数:目标日期在未来(还有 X 天)
  • 负数:目标日期在过去(已过 X 天)
  • :就是今天

这个方法是整个应用倒数/正数功能的基础。

3.2 重复事件的下一次日期

staticgetNextOccurrence(date:string,repeatType:number):string{consttarget=dayjs(date);constnow=dayjs();if(repeatType===1){// 每年重复letnext=target.year(now.year());// 替换为今年if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.year(now.year()+1);// 如果今年已过或就是今天,推到明年}returnnext.format('YYYY-MM-DD');}if(repeatType===2){// 每月重复letnext=target.year(now.year()).month(now.month());// 替换为本月if(next.isBefore(now,'day')||next.isSame(now,'day')){next=next.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-15'

3.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{constd=dayjs(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()consteffectiveDate=this.getEffectiveDate(day);constdays=DateUtil.daysFromToday(effectiveDate);// days > 0: "X天后"// days < 0: "X天前"// days === 0: "今天"

4.2 日历页:生成月份数据

// CalendarDataSource.generateMonth()constdaysInMonth=DateUtil.getDaysInMonth(d.year,d.month);constfirstDayOfWeek=DateUtil.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.repeatType===RepeatType.YEARLY){constdayMonth=DateUtil.formatDate(day.date,'MM-DD');consttargetMonth=DateUtil.formatDate(date,'MM-DD');returndayMonth===targetMonth;}

五、dayjs 在 ArkTS 中的注意事项

5.1 导入方式

importdayjsfrom'dayjs';

在 oh-package.json5 中声明依赖:

{ "dependencies": { "dayjs": "^1.11.13" } }

5.2 链式调用

dayjs 支持链式调用,但需要注意 ArkTS 的类型推断:

// 正确:分步调用constd=dayjs().year(year).month(month-1);constdays=d.daysInMonth();// 也可以:链式调用constdays=dayjs().year(year).month(month-1).daysInMonth();

5.3 不可变性

dayjs 对象是不可变的,每次操作返回新对象:

consta=dayjs('2026-01-01');constb=a.add(1,'month');// a 仍然是 2026-01-01// b 是 2026-02-01

这在 ArkUI V2 的响应式系统中很重要——不会意外修改被@Trace观察的对象。

六、扩展思考

6.1 时区处理

当前项目没有考虑时区问题。如果需要国际化,可以使用 dayjs 的 UTC 插件:

importutcfrom'dayjs/plugin/utc';dayjs.extend(utc);constutcDate=dayjs.utc('2026-03-15');

6.2 相对时间

如果需要显示"3小时后"这样的相对时间,可以使用 dayjs 的 relativeTime 插件。但本项目只精确到天,不需要。

6.3 自定义解析

dayjs 默认能解析YYYY-MM-DD格式。如果需要解析其他格式:

dayjs('2026年3月15日','YYYY年M月D日');

七、小结

DateUtil 作为项目的日期处理核心,封装了 dayjs 的常用操作,提供了简洁的静态方法接口。从倒数计算到重复事件处理,从日期格式化到日历数据生成,所有日期相关的逻辑都集中在这里,提高了代码的可维护性和可测试性。

http://www.jsqmd.com/news/1196863/

相关文章:

  • 计算机毕业设计之jsp学生宿舍管理系统
  • 数字IC验证面试核心考点深度剖析与实战应对
  • 宝珀中国官方售后服务中心|官方热线及网点地址权威信息公示(2026年7月最新) - 宝珀官方售后服务中心
  • Cursor AI布局切换实战手册(从VS Code迁移者必读):12个真实项目踩坑复盘与标准化配置模板
  • 2026年7月最新宁波天梭官方售后服务热线与网点地址查询 - 天梭服务中心
  • 流程引擎宕机后流程全丢?Spring Boot 工作流持久化恢复实战,让你的业务永不“断片”
  • MOS管从入门到实战:5分钟掌握核心原理与应用技巧
  • 【初阶·安全】大模型常见攻击向量认知深度解析:Prompt Injection、越狱攻击与数据投毒的攻防全景
  • 44.嵌入式C语言工程实践:最危险的bug——代码能跑,但逻辑已经错了
  • 2026年华东地区芝麻灰路沿石订购靠谱厂家联系方式汇总 - 热点品牌推荐
  • 安徽周边采购水平移载装箱机筛选靠谱供应厂家品牌 - 热点品牌推荐
  • Python实现跨境电商商品图批量翻译教程
  • 天津积家回收价格查询和靠谱回收平台实测排行(2026年7月最新) - 积家官方售后服务中心
  • JDK 11 新特性详解
  • 实战:在CentOS7上绕过GLIBC限制,安全运行高版本Node.js
  • 叠石桥墙内水管漏水检测维修师傅电话及优质服务商家盘点 - 热点品牌推荐
  • 深信服防火墙开局+访问控制策略+SNAT+DNAT+策略路由配置
  • C++引用详解:从本质到实战,安全高效的变量别名
  • AI聚合平台实战:多模型集成与开发效率提升方案
  • 工业打码机怎么选?避坑指南 + 机型详解 - 资讯焦点
  • A--10 Codex Review与GitHub PR工作流实战指南:从代码审查到安全合并
  • # 2026年运城刑事律师实力对比 5位资深刑辩律师各有特色 - 本地品牌推荐
  • 贵州黄金护栏生产厂家选型采购及配套服务实用指南 - 热点品牌推荐
  • 陇西黄金回收 2026 新规全解:持证门店避坑指南,本地三大合规变现渠道实测 - 福金阁黄金回收
  • 2026 通渭黄金回收正规门店指南|县域乡镇上门变现避坑全攻略 - 福金阁黄金回收
  • IndexNow 实战指南:告别漫长等待,让搜索引擎秒抓你的博客更新 - PC2005
  • 跨境电商多语言商品图翻译方案实现
  • 菏泽小区绿化路沿石批发商选购指南与行业优质供应商盘点 - 热点品牌推荐
  • 遗传算法解5皇后问题:从Hello World到工业优化的进化实验室
  • RAG系统的高可用架构:从单点检索到分布式语义搜索的演进