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

HarmonyOS ArkTS DateUtil 日期增减与日历计算完整指南

文章目录

    • 背景
    • 一、引言
    • 二、日期增减方法详解
      • 使用示例
    • 三、日历计算方法详解
    • 四、Demo 演示:日期增减结果展示
    • 五、Demo 演示:月历视图完整实现
    • 六、日历视图关键点解析
      • 为什么要填充前置空格?
      • getLastDayOfMonth 的实现技巧
    • 七、小结

背景

近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦

案例demo导航展示

↓↓↓↓↓↓接下来言归正传 ↓↓↓↓

一、引言

在日历、任务管理、预约系统等应用中,经常需要:

  • 计算明天/昨天/N天后的日期
  • 判断是否为闰年
  • 获取某月的天数
  • 构建月视图日历(本月第一天是星期几、本月有几天)

DateUtil提供了一套完整的日期增减与日历计算方法。

二、日期增减方法详解

// DateUtil.ets(工具类源码)// 获取前几天或后几天的日期staticgetAmountDay(date:number|string|Date,amount:number):Date{letrelativeDate=DateUtil.getFormatDate(date);relativeDate.setDate(relativeDate.getDate()+amount);// 正数=后,负数=前returnrelativeDate;}// 获取前几天或后几天的日期,返回字符串staticgetAmountDayStr(date:number|string|Date,amount:number,format:string=DATE_FORMAT4):string{returnDateUtil.getFormatDateStr(DateUtil.getAmountDay(date,amount),format);}// 获取前一天日期staticgetBeforeDay(date:number|string|Date):Date{returnDateUtil.getAmountDay(date,-1);}// 获取前一天日期,返回字符串staticgetBeforeDayStr(date:number|string|Date,format:string=DATE_FORMAT4):string{returnDateUtil.getAmountDayStr(date,-1,format);}// 获取后一天日期staticgetAfterDay(date:number|string|Date):Date{returnDateUtil.getAmountDay(date,1);}// 获取后一天日期,返回字符串staticgetAfterDayStr(date:number|string|Date,format:string=DATE_FORMAT4):string{returnDateUtil.getAmountDayStr(date,1,format);}

使用示例

constnow=newDate();// 假设今天是 2026-05-19DateUtil.getBeforeDayStr(now)// "2026-05-18"(昨天)DateUtil.getAfterDayStr(now)// "2026-05-20"(明天)DateUtil.getAmountDayStr(now,-7)// "2026-05-12"(7天前)DateUtil.getAmountDayStr(now,30)// "2026-06-18"(30天后)DateUtil.getAmountDayStr(now,-365)// "2025-05-19"(去年今天)

三、日历计算方法详解

// DateUtil.ets(工具类源码)// 判断是否是闰年staticisLeapYear(year:number|Date=newDate()):boolean{year=yearinstanceofDate?year.getFullYear():year;return(year%4===0&&year%100!==0)||year%400===0;}// 获取指定年份的天数(闰年366,平年365)staticgetDaysByYear(year:number):number{if(DateUtil.isLeapYear(year)){return366;}else{return365;}}// 获取指定月份的天数staticgetDaysByMonth(year:number,month:number):number{if(month==2){if(DateUtil.isLeapYear(year)){return29;}else{return28;}}elseif(month==1||month==3||month==5||month==7||month==8||month==10||month==12){return31;}else{return30;}}// 获取给定年份和月份的最后一天是几号staticgetLastDayOfMonth(year:number,month:number):number{returnnewDate(year,month,0).getDate();}// 获取给定日期是星期几(0=周日,6=周六)staticgetWeekDay(date:number|string|Date):number{returnDateUtil.getFormatDate(date).getDay();}// 获取给定日期是当月的第几周staticgetWeekOfMonth(date:number|string|Date):number{letcurrentDate=DateUtil.getFormatDate(date);letfirstDayOfMonth=newDate(currentDate.getFullYear(),currentDate.getMonth(),1);letfirstDayOfWeek=firstDayOfMonth.getDay();// 当月第一天是星期几letweekNumber=Math.ceil((currentDate.getDate()+firstDayOfWeek)/7);returnweekNumber;}

四、Demo 演示:日期增减结果展示

效果演示

// DateUtilDemoPage.ets(Demo 源码)getDateCalcResults():DateCalcResult[]{constnow=newDate();return[{label:'昨天',value:DateUtil.getBeforeDayStr(now),color:'#FF9800'},{label:'明天',value:DateUtil.getAfterDayStr(now),color:'#00C853'},{label:'7天前',value:DateUtil.getAmountDayStr(now,-7),color:'#555'},{label:'30天后',value:DateUtil.getAmountDayStr(now,30),color:'#555'},{label:'本周第几周',value:DateUtil.getWeekOfMonth(now).toString(),color:'#4080FF'},{label:'本月最后一天',value:DateUtil.getLastDayOfMonth(DateUtil.getNowYear(),DateUtil.getNowMonth()).toString()+' 号',color:'#FF9800'},];}
// UI 展示ForEach(this.getDateCalcResults(),(r:DateCalcResult)=>{Row(){Text(r.label).fontSize(12).fontColor('#888').width(100)Text(r.value).fontSize(12).fontColor(r.color).fontWeight(FontWeight.Medium)}.width('100%').padding({top:5,bottom:5})},(r:DateCalcResult)=>r.label)

五、Demo 演示:月历视图完整实现

这是 Demo 中最精彩的部分——用DateUtil实现一个可切换月份的月历视图:

// DateUtilDemoPage.ets(Demo 源码)@StatecalendarYear:number=2026;@StatecalendarMonth:number=5;// 构建日历格子数据getCalendarCells():CalendarCell[]{constcells:CalendarCell[]=[];// 获取当月第一天是星期几(0=周日)constfirstDay=newDate(this.calendarYear,this.calendarMonth-1,1).getDay();// 获取当月总天数constdaysInMonth=DateUtil.getLastDayOfMonth(this.calendarYear,this.calendarMonth);// 填充首行空格(月份前的空白格)for(leti=0;i<firstDay;i++){cells.push({day:0,isToday:false,isWeekend:false});}consttoday=newDate();for(letd=1;d<=daysInMonth;d++){constisToday=d===today.getDate()&&this.calendarMonth===today.getMonth()+1&&this.calendarYear===today.getFullYear();// 用 DateUtil.isWeekend 判断是否为周末constisWeekend=DateUtil.isWeekend(newDate(this.calendarYear,this.calendarMonth-1,d));cells.push({day:d,isToday,isWeekend});}returncells;}
// 日历 UI 组件Column(){// 月份切换导航Row(){Button('<').fontSize(16).height(36).width(44).backgroundColor('#F5F6FA').fontColor('#333').onClick(()=>{if(this.calendarMonth===1){this.calendarMonth=12;this.calendarYear--;}else{this.calendarMonth--;}})Text(`${this.calendarYear}${this.calendarMonth}`).fontSize(16).fontWeight(FontWeight.Bold).fontColor('#1a1a1a').layoutWeight(1).textAlign(TextAlign.Center)Button('>').fontSize(16).height(36).width(44).backgroundColor('#F5F6FA').fontColor('#333').onClick(()=>{if(this.calendarMonth===12){this.calendarMonth=1;this.calendarYear++;}else{this.calendarMonth++;}})}.width('100%').margin({bottom:8})// 本月信息Text(`本月${this.getMonthDays(this.calendarYear,this.calendarMonth)}天,第${DateUtil.getWeekOfMonth(newDate(this.calendarYear,this.calendarMonth-1,1))}周开始`).fontSize(11).fontColor('#888').margin({bottom:8})// 星期标题行Row(){ForEach(['日','一','二','三','四','五','六'],(d:string)=>{Text(d).fontSize(12).fontWeight(FontWeight.Medium).fontColor(d==='六'||d==='日'?'#FF5252':'#888').width('14.28%').textAlign(TextAlign.Center)})}.width('100%').margin({bottom:4})// 日期格子Flex({wrap:FlexWrap.Wrap}){ForEach(this.getCalendarCells(),(cell:CalendarCell)=>{if(cell.day===0){Text('').width('14.28%').height(40)// 空格}else{Column(){Text(cell.day.toString()).fontSize(14).fontColor(cell.isToday?'#FFF':cell.isWeekend?'#FF5252':'#333').fontWeight(cell.isToday?FontWeight.Bold:FontWeight.Normal)}.width('14.28%').height(40).justifyContent(FlexAlign.Center).backgroundColor(cell.isToday?'#4080FF':'transparent')// 今日高亮.borderRadius(20)}},(cell:CalendarCell)=>cell.day.toString()+cell.isToday.toString())}}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)

六、日历视图关键点解析

为什么要填充前置空格?

月历的每一行是 7 列(周日到周六)。比如 2026 年 5 月 1 日是周五(getDay()= 5),所以前面需要填充 5 个空格,让 1 号出现在第 6 列。

日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 ...

getLastDayOfMonth 的实现技巧

staticgetLastDayOfMonth(year:number,month:number):number{returnnewDate(year,month,0).getDate();// 下个月第0天 = 本月最后一天}// new Date(2026, 5, 0) → 2026年5月0日 → 实际上是4月30日// 所以 getLastDayOfMonth(2026, 4) = 30(四月有30天)

七、小结

方法说明典型应用场景
getAmountDay(date, n)增减 n 天,负数为减计算任意相对日期
getBeforeDay/getAfterDay前后一天日历翻页
isLeapYear(year)判断闰年校验日期合法性
getDaysByMonth(y, m)获取月份天数日历构建
getLastDayOfMonth(y, m)获取月末日期日历边界判断
getWeekDay(date)获取星期几日历列定位
getWeekOfMonth(date)获取第几周周视图日历
isWeekend(date)判断是否周末日历颜色标注
http://www.jsqmd.com/news/886901/

相关文章:

  • 我靠这个测试设计方法,把漏测率降低了80%
  • 2026年5月制氮机产氮能力排行:变压吸附制氮机/工业制氮机/氨分解发生炉/氨分解纯化/稀土行业用氨分解/立方制氮装置/选择指南 - 优质品牌商家
  • 2026年5月苏州高端装修公司推荐榜:昆山老槐树装饰领衔,别墅大平层装修厂家选择指南 - 海棠依旧大
  • 炉石传说自动对战助手:5分钟上手,彻底解放双手的终极指南
  • 从BUG()到panic:深入Linux 5.4内核,看异常处理如何层层递进
  • 服务注册中心选型生死局:Eureka vs Nacos vs Claude自研轻量注册中心(压测数据全公开)
  • 2026定制软连接选型指南:浸漆铜排、浸粉铜排、软连接定制、软铜排定制、铜排浸漆、铜排浸粉、铜排软连接、铜箔软连接选择指南 - 优质品牌商家
  • PLC厂家怎么选?2026年5月推荐十大品牌评测物流分拣场景降低故障率口碑对比 - 品牌推荐
  • 基于ATmega2560与ISD1700的智能语音时钟:硬件选型、软件架构与避坑指南
  • 绝了!输入题目,这几款AI论文写作软件就能生成图文并茂的毕业论文
  • 企业知识库怎么搭建:2026年从需求分析到AI接入的完整路径 - 广州矩阵架构科技公司
  • 全链路压测实战:双十一级别的流量,我是这样扛住的
  • 告别浪费!SolidWorks企业级共享方案,实现降本增效全攻略
  • 告别繁琐操作:淘金币自动脚本如何为你每天节省25分钟
  • 保姆级教程:用CesiumLab和Nginx搞定离线地形切片,告别网络依赖
  • 业内聚焦:2026年5月成都铝镁锰板批发优选服务商深度解析 - 2026年企业推荐榜
  • 2026年5月,如何在河北地区选择优质的水洗砂地坪等各类装饰混凝土地坪厂家? - 2026年企业推荐榜
  • FM3773 低功耗离线式恒流/恒压 PSR 控制器
  • 2026年5月值得信赖的氨基酸洗面奶生产厂家哪家权威厂家推荐榜,氨基酸洁面泡、敏感肌洁面乳、保湿养肤洁面霜厂家选择指南 - 海棠依旧大
  • 基于放射性衰变的真随机数生成器:从量子物理到嵌入式实现
  • 解决Claude Code Token不足问题并享受Taotoken活动价
  • 解锁生命时钟:BioAge生物年龄评估工具全面解析
  • VMware ESXi 9.1.0.0集成NVME+网卡驱动版发布|新特性+驱动集成+部署升级+FAQ全指南
  • 长期使用Taotoken聚合服务对项目月度账单的可预测性提升
  • [智能体-81]:工程化智能体 = 模型做脑力拆解 + 框架做流程落地。前者是决策者,后者是管理者,tools/function call是内部员工;mcp server是外部资源;
  • 2026年5月北京家装公司推荐:五家专业评测夜间施工防噪音排名 - 品牌推荐
  • 【SSD】闪存数据完整性 重读 ECC纠错 RAID 数据随机化简述
  • 2026年Q2铜排浸粉技术解析与靠谱供应商实测参考:柔性软连接、浸漆铜排、浸粉铜排、软连接定制、软铜排定制、铜排浸漆选择指南 - 优质品牌商家
  • 华硕笔记本终极性能控制指南:用G-Helper完全替代Armoury Crate
  • 开启Python GUI开发新纪元:Tkinter Designer可视化界面自动化生成终极指南