鸿蒙ArkTS日期处理:从解析到格式化
一、前言
在上一篇文章《用 ArkTS 实现一个生肖查询小工具》中,我们从零搭建了一个完整的交互页面,学习了 @State、Column、TextInput、Button、Text 这五个最核心的 API。这篇文章延续同一个风格,用日期查星期这个小工具,带大家掌握 ArkTS 中日期处理的完整流程。
日期处理是移动端开发中的高频场景:
- 日历 App 需要根据日期计算星期
- 备忘录 / 待办需要显示创建时间
- 聊天记录需要展示"今天 / 昨天 / 前天 / 周几"这样的友好格式
- 统计页面需要按周聚合数据
本篇文章将围绕 Date 对象的解析、校验、格式化,结合 ArkTS 的声明式 UI,完成一个开箱即用的日期查询组件。

二、完整代码展示
先上完整代码,建立整体印象:
@Entry
@Component
struct Index {
@State inputDate: string = ""
@State weekResult: string = "请输入日期 格式:2026-06-14"
checkWeek() {
let dateStr = this.inputDate
let date = new Date(dateStr)
if (isNaN(date.getTime())) {
this.weekResult = "日期格式错误,请重输"
return
}
const weekArr = ["周日","周一","周二","周三","周四","周五","周六"]
let week = weekArr[date.getDay()]
this.weekResult = `${dateStr} 是 ${week}`
}
build() {
Column({ space: 25 }) {
TextInput({text: this.inputDate, placeholder: "例如:2026-06-14"})
.width("85%")
.height(50)
.onChange(val => this.inputDate = val)
Button("查询星期")
.width(130)
.onClick(() => this.checkWeek())
Text(this.weekResult)
.fontSize(20)
.textAlign(TextAlign.Center)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
.padding(15)
}
}
typescript
@State inputDate: string = ""
@State weekResult: string = "请输入日期 格式:2026-06-14"
和上一期的生肖查询完全一致的模式:
inputDate—— 绑定 TextInput 的输入内容,类型为stringweekResult—— 展示计算结果,初始值为提示文字
这里有一个值得注意的设计细节:初始值就是占位说明。用户还没操作时,结果区域显示的文本直接告诉用户该做什么、格式是什么样的。这种设计比空白区域更友好,减少了用户的学习成本。
从架构角度看,@State 的使用模式可以总结为:
typescript checkWeek() { let dateStr = this.inputDate let date = new Date(dateStr) if (isNaN(date.getTime())) { this.weekResult = "日期格式错误,请重输" return } const weekArr = ["周日","周一","周二","周三","周四","周五","周六"] let week = weekArr[date.getDay()] this.weekResult = ${dateStr} 是 ${week} }
这段代码做了三件事:**解析 → 校验 → 计算输出**。
#### 4.2.1 日期解析:new Date(dateStr)
JavaScript / TypeScript 的 `Date` 构造函数支持多种字符串格式:
| 输入格式 | 示例 | 是否有效 | 说明 |
|----------|------|:--------:|------|
| YYYY-MM-DD | `2026-06-14` | ✅ | 标准 ISO 8601 格式 |
| YYYY/MM/DD | `2026/06/14` | ✅ 大部分浏览器支持 | 兼容性良好 |
| YYYY.MM.DD | `2026.06.14` | ❌ 部分引擎不支持 | 不推荐 |
| YYYYMMDD | `20260614` | ❌ | 会被当作数字 |
| MM/DD/YYYY | `06/14/2026` | ✅ 但易混淆 | 非中国习惯格式 |
最简单的方案就是强制要求 `YYYY-MM-DD` 格式,这也是最安全、最通用的写法。
值得注意的是,`new Date()` 对带连接符的 ISO 字符串解析时会将其**当作 UTC 时间**,而不是本地时间。但对我们这种只需要获取日期的场景来说,影响可以忽略——因为无论时区如何,`getDay()` 得到的星期几是一致的。
#### 4.2.2 日期校验:isNaN(date.getTime())
在 JavaScript/TypeScript 中,`new Date('abc')` 并不会抛出异常,而是创建一个**无效的 Date 对象**。无效的 Date 对象仍然有方法,但调用 `getTime()` 会返回 `NaN`。
所以标准做法是:
```typescript
if (isNaN(date.getTime())) {
// 日期无效
}
这是 JavaScript 中校验日期的标准惯用法,ArkTS 完全沿用这个模式。
常见几种校验方式的对比:
| 方式 | 代码 | 是否能检测"2026-13-01" | 是否能检测"2026-02-30" |
|---|---|---|---|
| isNaN(date.getTime()) | ✅ 一检测就死 | ✅ 月份超了变 NaN | ✅ 天数超了变 NaN |
| 正则匹配格式 | 复杂且不全 | ❌ 放过 | ❌ 放过 |
| 手动解析年月日 | 啰嗦 | ✅ | 需要自己实现 |
所以 isNaN(date.getTime()) 是最简洁且有效的兜底方案。
2.1 星期映射:getDay() 与中文星期
const weekArr = ["周日","周一","周二","周三","周四","周五","周六"]
let week = weekArr[date.getDay()]
typescript
const WEEK_DAYS = ["周日","周一","周二","周三","周四","周五","周六"] as const
as const 让 TypeScript 知道这个数组的元素类型是字面量联合类型,类型更加精确。
2.1.1 模板字符串:${}
this.weekResult = `${dateStr} 是 ${week}`
ArkTS 继承了 TypeScript 的模板字符串能力,用反引号和 ${} 语法做字符串插值。这比字符串拼接更清晰:
// 旧式拼接(可读性差)
this.weekResult = dateStr + " 是 " + week
// 模板字符串(清晰直接)
this.weekResult = `${dateStr} 是 ${week}`
模板字符串还支持多行和表达式:
this.weekResult = `日期:${dateStr}
星期:${week}
距离今天还有:${Math.ceil((date.getTime() - Date.now()) / 86400000)} 天`
2.2 建:build() 方法
build() {
Column({ space: 25 }) {
TextInput({text: this.inputDate, placeholder: "例如:2026-06-14"})
.width("85%")
.height(50)
.onChange(val => this.inputDate = val)
Button("查询星期")
.width(130)
.onClick(() => this.checkWeek())
Text(this.weekResult)
.fontSize(20)
.textAlign(TextAlign.Center)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
.padding(15)
}
2.2.1 Column 属性
{ space: 25 }—— 比上一期少 5,子组件间距更紧凑.padding(15)—— 比上一期少 5,整体布局更紧凑
这种微调反映了 UI 开发的常态——没有标准答案,只有适合场景的选择。间距大小取决于页面的整体视觉风格和信息密度。
2.2.2 TextInput 属性
TextInput({text: this.inputDate, placeholder: "例如:2026-06-14"})
.width("85%")
.height(50)
.onChange(val => this.inputDate = val)
这次 placeholder 写的是具体示例:"例如:2026-06-14",比上一期"输入出生年份"更具体。这是有意为之——日期格式比年份更复杂,用户可能不知道应该输入什么格式,直接给范例可以大大降低出错率。
这种设计模式叫 placeholder 即模板——占位符不再是空泛的说明,而是直接展示一个可参考的样例。
2.2.3 Button 属性
Button("查询星期")
.width(130)
.onClick(() => this.checkWeek())
和上一期几乎一致,区别是宽度设为 130(上期为 120)。因为"查询星期"比"查询生肖"多了一个字,稍微放宽了一些。ArkTS 的 Button 文字会居中显示,宽度不够时文字会被截断,所以需要根据文字长度调整。
2.2.4 Text 属性
Text(this.weekResult)
.fontSize(20)
.textAlign(TextAlign.Center)
新增了 .textAlign(TextAlign.Center)。因为结果字符串长度不固定:
- 初始状态:"请输入日期 格式:2026-06-14"(较长,17 字)
- 正常结果:"2026-06-14 是 周日"(适中)
- 错误提示:"日期格式错误,请重输"(9 字)
居中显示可以保证不同长度的文本在视觉上保持一致的对齐方式。
TextAlign 枚举值:
| 值 | 效果 |
|---|---|
Start |
左对齐(默认) |
Center |
居中对齐 |
End |
右对齐 |
三、与上期生肖查询的对比
把两期的代码放在一起对比,能看出 ArkTS 组件的通用模式:
| 维度 | 生肖查询 | 日期查星期 |
|---|---|---|
| @State 数量 | 2 个 (year, zodiac) | 2 个 (inputDate, weekResult) |
| UI 组件 | TextInput + Button + Text | TextInput + Button + Text |
| 布局容器 | Column | Column |
| 核心方法 | getZodiac() | checkWeek() |
| 核心逻辑 | (year-4)%12 索引数组 |
date.getDay() 索引数组 |
| 校验方式 | isNaN(parseInt(...)) |
isNaN(date.getTime()) |
| 代码行数 | 38 行 | 30 行 |
| 间距 | space: 30 | space: 25 |
| 内边距 | padding: 20 | padding: 15 |
这揭示了一个重要规律:ArkTS 的交互组件具有非常固定的模板结构。在学习新组件时,你只需要关注三件事:
- 状态定义 —— 需要几个
@State?类型是什么? - 业务方法 —— 核心计算逻辑怎么写?边界情况怎么处理?
- UI 编排 —— 哪些组件?怎么排列?样式参数怎么调?
一旦掌握了这个模板,无论是写生肖查询、日期查星期、BMI 计算器、单位换算、还是密码生成器,本质上都是换不同的业务逻辑而已。
四、扩展与进阶
基础版本比较简单,下面给出几个有价值的扩展方向。
4.1 输入实时校验
用户输入过程中,可以实时检查日期是否合法,而不是等到点击按钮才校验:
@State inputError: string = ""
onDateChange(val: string) {
this.inputDate = val
if (val.length === 10) { // YYYY-MM-DD 固定 10 字符
let date = new Date(val)
if (isNaN(date.getTime())) {
this.inputError = "日期格式错误"
} else {
this.inputError = ""
}
} else {
this.inputError = ""
}
}
UI 中增加错误提示:
Text(this.inputError)
.fontSize(14)
.fontColor("#e74c3c")
.visible(this.inputError !== "")
这种"输入即校验"的模式,在表单类页面中非常常见——用户不需要等点击提交才发现问题,在输入过程中就能获得即时反馈。
4.2 支持多种日期格式
很多用户输入日期时不会严格遵守 YYYY-MM-DD 格式,可能输入 20260614、2026/06/14、2026.06.14。可以加一个格式化预处理:
normalizeDate(input: string): string {
// 去掉所有非数字字符
const digits = input.replace(/\D/g, "")
if (digits.length !== 8) return input // 不是有效日期长度
// 格式化为 YYYY-MM-DD
const year = digits.substring(0, 4)
const month = digits.substring(4, 6)
const day = digits.substring(6, 8)
return `${year}-${month}-${day}`
}
然后在 checkWeek() 中调用:
checkWeek() {
let dateStr = this.normalizeDate(this.inputDate)
// ... 后续不变 ...
}
这样用户输入 20260614 后,自动被转为 2026-06-14,体验更加友好。
4.3 显示更多日期信息
查星期只是一个开始,可以扩展显示更多信息:
checkWeek() {
let dateStr = this.inputDate
let date = new Date(dateStr)
if (isNaN(date.getTime())) {
this.weekResult = "日期格式错误,请重输"
return
}
const weekArr = ["周日","周一","周二","周三","周四","周五","周六"]
const week = weekArr[date.getDay()]
// 额外信息
const today = new Date()
const diffDays = Math.ceil((date.getTime() - today.getTime()) / 86400000)
const isToday = date.toDateString() === today.toDateString()
const isPast = diffDays < 0
const isFuture = diffDays > 0
let extra = ""
if (isToday) {
extra = "(就是今天!)"
} else if (isPast && diffDays > -7) {
extra = `(${-diffDays} 天前)`
} else if (isFuture && diffDays < 7) {
extra = `(${diffDays} 天后)`
} else if (isPast) {
extra = `(${-diffDays} 天前)`
} else {
extra = `(${diffDays} 天后)`
}
this.weekResult = `${dateStr} 是 ${week} ${extra}`
}
这样用户输入一个日期后,不仅知道星期几,还能直观地知道离今天有多远。
4.4 农历日期显示(扩展思路)
如果需要同时显示农历,可以引入一个农历转换库。不过 ArkTS 目前没有内置的农历支持,需要自己实现或者引入第三方计算表。
最简方案:准备一段 1900-2100 年的农历数据表(通过 codegen 生成):
// 简化版:只做月日映射
const LUNAR_MONTH_NAMES = ["正","二","三","四","五","六","七","八","九","十","冬","腊"]
const LUNAR_DAY_NAMES = [
"初一","初二","初三","初四","初五","初六","初七","初八","初九","初十",
"十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
"廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"
]
// 配合每年的农历偏移数据表使用
实现完整的农历查算是比较复杂的,这里仅作思路提示,具体实现不展开。
4.5 日期选择器替代输入框
ArkTS 提供了原生的 DatePicker 组件,可以替代手动输入:
@State selectedDate: Date = new Date()
@State dateString: string = ""
build() {
Column({ space: 25 }) {
DatePicker({
start: new Date("1900-01-01"),
end: new Date("2100-12-31"),
selected: this.selectedDate
})
.onChange((date) => {
this.selectedDate = date
this.dateString = this.formatDate(date)
this.checkWeekWithDate(date)
})
Button("查询星期")
.width(130)
.onClick(() => this.checkWeekWithDate(this.selectedDate))
Text(this.weekResult)
.fontSize(20)
}
}
typescript
new Date("2026-06-14")
在 ArkTS 运行时(方舟运行时)中,这种行为是标准化的。但在 Web 端开发时,不同浏览器对 Date 构造函数的参数解析存在细微差异。ArkTS 的方舟运行时遵循 ECMAScript 标准,表现为:
YYYY-MM-DD格式被解析为UTC 时间 00:00:00YYYY/MM/DD格式被解析为本地时间 00:00:00
这种差异对于 getDay() 计算星期没有影响,但如果后续要计算时间差(如 "距离今天还有 X 天"),就需要考虑时区问题。
修复方案:显式指定本地时间构造:
function createLocalDate(dateStr: string): Date {
const parts = dateStr.split("-")
return new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]))
}
这里的 parseInt(parts[1]) - 1 是因为 JavaScript 的月份是从 0 开始计数的(0=一月,11=十二月),这是 JavaScript 设计中常被诟病的坑。
4.6空字符串处理
当用户清空输入框时,this.inputDate 变成空字符串,new Date("") 会返回一个有效日期(有些浏览器解析为 Invalid Date,但部分引擎中 new Date("") 的行为不一致)。
所以建议在 checkWeek() 方法开头增加空字符串检查:
if (this.inputDate.trim() === "") {
this.weekResult = "请输入日期"
return
}
各个引擎对 new Date("") 的行为:
| 引擎 | new Date("") 结果 |
isNaN(date.getTime()) |
|---|---|---|
| V8 (Chrome/Edge) | Invalid Date |
true (安全) |
| SpiderMonkey (Firefox) | Invalid Date |
true (安全) |
| JavaScriptCore (Safari) | Invalid Date |
true (安全) |
| 方舟运行时 | Invalid Date |
true (安全) |
从表格看,主流引擎都会把空字符串解析为无效日期,所以即使不加空字符串检查,也能被 isNaN 捕获。但显式检查的代码意图更清晰,可读性更好。
4.7日期格式未尾的空格
用户在输入时可能在末尾不小心输入了空格,比如 2026-06-14 。
处理方式:
let dateStr = this.inputDate.trim() // 去掉首尾空格
typescript
// 按周一开始的排列
const weekArrMonStart = ["周一","周二","周三","周四","周五","周六","周日"]
// date.getDay() 返回 0=周日, 1=周一, ..., 6=周六
// 映射:周日→周日(索引6),周一→周一(索引0),... 周六→周六(索引5)
function getWeekIndex(day: number): number {
return day === 0 ? 6 : day - 1 // 周日映射到6,其余减1
}
let week = weekArrMonStart[getWeekIndex(date.getDay())]
两种排列方式各有各的用户习惯,建议提供切换选项,或者在页面中同时显示"周日"和"一周第X天"。
五、单元测试思路
虽然 ArkTS 的单元测试框架还在演进中,但我们可以从纯逻辑层面拆出可测试的函数:
// 将纯逻辑提取为独立函数(不依赖 @State,不依赖 UI)
export function getWeekdayString(dateStr: string): string {
const date = new Date(dateStr)
if (isNaN(date.getTime())) {
return "日期格式错误,请重输"
}
const weekArr = ["周日","周一","周二","周三","周四","周五","周六"]
const week = weekArr[date.getDay()]
return `${dateStr} 是 ${week}`
}
然后用常规的 JavaScript 测试框架就可以测试:
// 测试用例示例
describe("getWeekdayString", () => {
test("正常日期返回正确星期", () => {
expect(getWeekdayString("2026-06-14")).toBe("2026-06-14 是 周日")
})
test("无效日期返回错误提示", () => {
expect(getWeekdayString("abc")).toBe("日期格式错误,请重输")
})
test("闰年日期正常", () => {
expect(getWeekdayString("2024-02-29")).toBe("2024-02-29 是 周四")
})
test("空字符串返回错误", () => {
expect(getWeekdayString("")).toBe("日期格式错误,请重输")
})
test("跨年边界", () => {
// 2026-01-01 是周四
expect(getWeekdayString("2026-01-01")).toBe("2026-01-01 是 周四")
})
})
将纯逻辑从 UI 组件中剥离出来,是 ArkTS 应用架构中值得养成的习惯。它让代码更容易测试、更容易复用、也更容易理解。
六、总结
6.1 本期新增知识点
通过日期查星期这个项目,除了巩固上期学到的 @State、Column、TextInput、Button、Text 之外,新增了以下知识点:
Date对象处理:构造、解析、校验、getDay()方法isNaN()校验模式:不是校验数字,而是校验 Date 是否有效textAlign属性:控制文本对齐方式- 日期格式化:标准 ISO 格式的使用
- 边界处理扩展:空字符串、空格、非法格式等场景
6.2 从代码量看学习曲线
| 项目 | 代码行数 | 知识点 |
|---|---|---|
| Hello World | 15 | @Entry, @Component, build, Text |
| 生肖查询 | 38 | @State, TextInput, Button, 数组索引, parseInt |
| 日期查星期 | 30 | Date对象, getDay, isNaN校验, textAlign |
代码量不大,但每一步都在夯实对 ArkTS 核心机制的理解。掌握这两个小项目的基础,已经可以写出大部分简单交互页面了。



更多推荐



所有评论(0)