- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
导读
本文面向仓颉(Cangjie)编程语言开发者,系统讲解标准库std.time包中两个核心结构体 DateTime 与 MonoTime 的完整 API 用法。DateTime是描述具体时间点(携带时区)的不可变类型,支持读取、计算、比较、时区转换、格式化与解析;MonoTime是单调递增的计时类型,适合性能测量、超时控制等不受系统时间调整影响的场景。阅读本文后,你将能够熟练使用DateTime完成业务时间处理,并借助MonoTime实现高精度计时。
结构体总览
std.time包对外提供的结构体共两个,它们与time包内的 DateTimeFormat(时间格式)、TimeZone(时区)两个类,以及 DayOfWeek、Month 两个枚举、两个异常类共同构成完整的时间处理体系(参见 std.time 包介绍)。
| 结构体 | 功能 |
|---|---|
| DateTime | 表示日期时间,描述某一时间点,提供基于时区的读取、计算、比较、转换以及序列化/反序列化功能 |
| MonoTime | 表示单调时间,类似一直运行的秒表,提供获取当前时间、计算和比较功能 |
一、DateTime:带时区的日期时间类型
1.1 类型声明与核心特性
public struct DateTime <: ToString & Hashable & Comparable<DateTime> & Formattable & Parsable<DateTime>DateTime是一个描述某一时间点的时间类型,具备以下核心特性:
- 不可变:
DateTime实例一旦创建,其包含的日期、时间和时区信息不可修改,所有"计算"操作均返回新的实例; - 表示范围:可表示
[-999,999,999-01-01T00:00:00.000000000, 999,999,999-12-31T23:59:59.999999999],该区间适用于任何合法时区,精度可达纳秒; - 时区感知:实例内同时保存"墙上时间"(日期时间字段)与所属时区,比较与相等判断基于 UTC 时间轴进行。
父类型说明(定义见 core 包接口 与 convert 包接口):
- ToString:提供字符串表示;
- Hashable:提供哈希能力;
- Comparable<DateTime>:提供排序比较;
- Formattable:支持按格式字符串生成;
- Parsable<DateTime>:支持从字符串解析。
1.2 获取当前时间的系统调用
DateTime.now(timeZone)与DateTime.nowUTC()获取当前时间时,底层调用系统的clock_gettime函数并读取CLOCK_REALTIME时钟:
| 系统 | 系统调用函数 | 时钟类型 |
|---|---|---|
| Linux | clock_gettime | CLOCK_REALTIME |
| Windows | clock_gettime | CLOCK_REALTIME |
| macOS | clock_gettime | CLOCK_REALTIME |
由于CLOCK_REALTIME会随系统时间调整(如 NTP 同步、手动改时间)而变化,文档明确指出:若需要不受系统时间影响的计时场景,应使用 MonoTime.now() 替代。
1.3 静态属性与实例属性:读取日期时间信息
DateTime提供 1 个静态属性和 15 个实例属性,用于获取时间各组成部分。
静态属性 UnixEpoch
public static prop UnixEpoch: DateTime获取 Unix 时间纪元,即零时区1970年1月1日0时0分0秒0纳秒对应的DateTime实例。它是fromUnixTimeStamp、toUnixTimeStamp、ofEpoch等 Unix 时间戳换算的基准点。
日期相关属性
| 属性 | 类型 | 说明 |
|---|---|---|
| year | Int64 | 年份 |
| month | Month | 月份(枚举类型) |
| monthValue | Int64 | 数字形式月份(已标记 deprecated,未来版本废弃) |
| dayOfMonth | Int64 | 当前月第几日 |
| dayOfWeek | DayOfWeek | 当前周第几日(枚举类型) |
| dayOfYear | Int64 | 当前年份第几日 |
| date | (Int64, Month, Int64) | 年份、月份、当前月第几日(三元组) |
| isoWeek | (Int64, Int64) | 基于 ISO8601 标准的年份和基于年的周数(二元组) |
时间相关属性
| 属性 | 类型 | 说明 |
|---|---|---|
| hour | Int64 | 小时 |
| minute | Int64 | 分钟 |
| second | Int64 | 秒 |
| nanosecond | Int64 | 纳秒 |
| time | (Int64, Int64, Int64) | 时、分、秒(三元组) |
时区相关属性
| 属性 | 类型 | 说明 |
|---|---|---|
| zone | TimeZone | 实例关联的时区 |
| zoneId | String | 时区 ID(如 "Asia/Shanghai") |
| zoneOffset | Duration | 时区相对零时区的偏移量 |
属性读取示例(完整示例见 datetime_prop.md):
import std.time.* main() { let datetime = DateTime.of( year: 2024, month: May, dayOfMonth: 22, hour: 12, minute: 34, second: 56, nanosecond: 789000000, timeZone: TimeZone.load("Asia/Shanghai") ) let yr = datetime.year let mon = datetime.month let day = datetime.dayOfMonth let hr = datetime.hour let min = datetime.minute let sec = datetime.second let ns = datetime.nanosecond let zoneId = datetime.zoneId let offset = datetime.zoneOffset let dayOfWeek = datetime.dayOfWeek let dayOfYear = datetime.dayOfYear let (isoYear, isoWeek) = datetime.isoWeek println("datetime is ${yr}, ${mon}, ${day}, ${hr}, ${min}, ${sec}, ${ns}, ${zoneId}, ${offset}") println("datetime.toString() = ${datetime}") println("${dayOfWeek}, ${dayOfYear}th day, ${isoWeek}th week of ${isoYear}") }运行结果:
datetime is 2024, May, 22, 12, 34, 56, 789000000, Asia/Shanghai, 8h datetime.toString() = 2024-05-22T12:34:56.789+08:00 Wednesday, 143th day, 21th week of 20241.4 构造 DateTime 实例
DateTime提供多组静态构造方法,覆盖"当前时间""指定字段""Unix 时间戳""字符串解析"四条路径。
当前时间
public static func now(timeZone!: TimeZone = TimeZone.Local): DateTime public static func nowUTC(): DateTimenow(timeZone):获取指定时区的当前时间,参数timeZone为命名参数并带默认值TimeZone.Local(本地时区);nowUTC():获取 UTC 时区的当前时间。
两者均受系统时间影响,计时场景请改用MonoTime.now()。
按字段构造
DateTime提供两组of重载,区别仅在于月份参数使用Int64还是 Month 枚举:
public static func of( year!: Int64, month!: Int64, // 或 month!: Month dayOfMonth!: Int64, hour!: Int64 = 0, minute!: Int64 = 0, second!: Int64 = 0, nanosecond!: Int64 = 0, timeZone!: TimeZone = TimeZone.Local ): DateTime参数取值范围如下(超范围抛出 IllegalArgumentException):
| 参数 | 范围 | 说明 |
|---|---|---|
| year | [-999,999,999, 999,999,999] | 公元年 |
| month | [1, 12] | 或使用 Month 枚举 |
| dayOfMonth | [1, 31] | 最大取值需与 month 匹配(28/29/30/31) |
| hour | [0, 23] | 默认 0 |
| minute | [0, 59] | 默认 0 |
| second | [0, 59] | 默认 0 |
| nanosecond | [0, 999,999,999] | 默认 0 |
| timeZone | — | 默认 TimeZone.Local |
构造 UTC 时区实例
public static func ofUTC(year!: Int64, month!: Int64, dayOfMonth!: Int64, ...): DateTime public static func ofUTC(year!: Int64, month!: Month, dayOfMonth!: Int64, ...): DateTimeofUTC与of参数完全一致,区别在于构造出的实例固定为 UTC 时区,因此无需传时区参数。
从 Unix 时间戳构造
public static func ofEpoch(second!: Int64, nanosecond!: Int64): DateTime public static func fromUnixTimeStamp(d: Duration): DateTimeofEpoch(second, nanosecond):second表示自 UnixEpoch 起的秒部分,nanosecond表示纳秒部分,纳秒范围必须为 [0, 999,999,999],超范围抛出 IllegalArgumentException;结果超出表示范围抛出 ArithmeticException;fromUnixTimeStamp(d):参数d为 Duration 时间间隔,返回自UnixEpoch起该间隔后的日期时间。
从字符串解析
public static func parse(str: String): DateTime public static func parse(str: String, format: String): DateTime public static func tryParse(str: String): Option<DateTime>parse(str):按RFC3339的date-time格式解析,可包含小数秒,如"2023-04-10T08:00:00.123456+08:00"([]表示可选项);解析失败抛出 TimeParseException;parse(str, format):按format指定的格式解析,如"2023/04/10 08:00:00 +08:00"配合格式"yyyy/MM/dd HH:mm:ss OOOO"。格式说明见下文"时间字符串格式"一节;当无法解析、同一format出现多次取值时抛出 TimeParseException,format不合法时抛出 IllegalArgumentException;tryParse(str):解析失败不抛异常,返回 Option<DateTime>.None,适合不确定输入的业务场景。
此外,parse(String, DateTimeFormat)与toString(DateTimeFormat)两个以DateTimeFormat为参数的重载已被标记deprecated,官方建议统一改用parse(String, String)与format(String)。
格式化与解析示例(完整示例见 datetime_parse.md):
import std.time.* main() { let pattern = "yyyy/MM/dd HH:mm:ssSSS OO" let datetime = DateTime.of( year: 2024, month: May, dayOfMonth: 22, hour: 12, minute: 34, second: 56, nanosecond: 789000000, timeZone: TimeZone.load("Asia/Shanghai") ) let str = datetime.format(pattern) println(str) println(DateTime.parse(str, pattern)) }运行结果:
2024/05/22 12:34:56789000000 +08:00 2024-05-22T12:34:56.789+08:001.5 日期时间计算:add 系列方法
DateTime提供 8 个add方法,全部返回新的DateTime实例(不可变特性),原实例不受影响:
| 方法 | 语义 | 超出表示范围异常 |
|---|---|---|
| addDays(n) | n 天后 | ArithmeticException |
| addWeeks(n) | n 周后 | ArithmeticException |
| addMonths(n) | n 月后 | ArithmeticException |
| addYears(n) | n 年后 | ArithmeticException |
| addHours(n) | n 小时后 | ArithmeticException |
| addMinutes(n) | n 分钟后 | ArithmeticException |
| addSeconds(n) | n 秒后 | ArithmeticException |
| addNanoseconds(n) | n 纳秒后 | ArithmeticException |
其中addMonths与addYears需要特别留意月份/年份间隔不固定带来的日期溢出处理:
- 若 dt 表示
2020年3月31日,dt.addMonths(1)不会返回非法日期2020年4月31日,而是偏移到当月最后一天,返回2020年4月30日; - 若 dt 表示
2020年2月29日(闰年),dt.addYears(1)不会返回2021年2月29日,而是返回2021年2月28日。
1.6 比较与运算符重载
DateTime实现了完整的比较运算符与 Comparable 接口的compare方法。
public func compare(rhs: DateTime): Ordering- 大于返回 Ordering.GT,等于返回 EQ,小于返回 LT。
运算符==、!=、<、<=、>、>=的语义统一基于UTC 时间轴:
- 若两个
DateTime相等,则它们指向同一 UTC 时间(即使墙上时间或时区不同); - 指向更早 UTC 时间的实例更小,指向更晚 UTC 时间的实例更大。
这也意味着:不同时区下"看起来相同"的墙上时间并不相等,而"看起来不同"的时间点只要对应同一 UTC 时刻即相等。
跨时区比较示例(完整示例见 datetime_compare.md):
import std.time.* main() { let tzSH = TimeZone.load("Asia/Shanghai") let tzNY = TimeZone.load("America/New_York") // 2024-05-25T00:00:00Z let shanghai1 = DateTime.of(year: 2024, month: May, dayOfMonth: 25, hour: 8, timeZone: tzSH) let new_york1 = DateTime.of(year: 2024, month: May, dayOfMonth: 24, hour: 20, timeZone: tzNY) // 2024-05-25T01:00:00Z let shanghai2 = DateTime.of(year: 2024, month: May, dayOfMonth: 25, hour: 9, timeZone: tzSH) let new_york2 = DateTime.of(year: 2024, month: May, dayOfMonth: 24, hour: 21, timeZone: tzNY) println(shanghai1 == new_york1) // true,同一 UTC 时刻 println(shanghai1 != new_york2) // true println(shanghai1 <= new_york2) // true println(shanghai1 < new_york2) // true println(shanghai2 >= new_york1) // true println(shanghai2 > new_york1) // true }Duration 算术运算:DateTime与 Duration(时间间隔类型)之间的加减同样通过运算符实现:
| 运算 | 签名 | 返回值 |
|---|---|---|
| + | DateTime + Duration | DateTime |
| - | DateTime - Duration | DateTime |
| - | DateTime - DateTime | Duration(两者时间差) |
结果超出表示范围时抛出 ArithmeticException。
1.7 时区转换与序列化
时区转换:
public func inLocal(): DateTime public func inUTC(): DateTime public func inTimeZone(timeZone: TimeZone): DateTime三个方法分别返回同一时间点在本地时区、UTC 时区、指定时区下的表示(同一 UTC 时刻,墙上时间不同)。当返回的日期时间超出表示范围时抛出 ArithmeticException。
时区转换示例(完整示例见 datetime_tz.md):
import std.time.* main() { let datetime = DateTime.of(year: 2024, month: May, dayOfMonth: 22, hour: 12, timeZone: TimeZone.load("Asia/Shanghai")) println("CST: ${datetime}") println("UTC: ${datetime.inUTC()}") println("EDT: ${datetime.inTimeZone(TimeZone.load("America/New_York"))}") }运行结果:
CST: 2024-05-22T12:00:00+08:00 UTC: 2024-05-22T04:00:00Z EDT: 2024-05-22T00:00:00-04:00序列化与反序列化:
public func toString(): String public func format(fmt: String): String public func toUnixTimeStamp(): DurationtoString():返回RFC3339的date-time格式字符串;若纳秒信息不为零,会打印小数秒,例如2024-05-22T12:34:56.789+08:00;format(fmt):按fmt指定格式输出字符串(如"yyyy/MM/dd HH:mm:ss OOOO");若fmt不符合时间字符串格式规范,抛出 IllegalArgumentException;toUnixTimeStamp():返回自UnixEpoch起的时间间隔(Duration 类型),与fromUnixTimeStamp互为逆运算。
哈希:hashCode(): Int64返回实例哈希值,配合Hashable父类型使DateTime可作为哈希容器的键。
二、MonoTime:单调时间与高性能计时
2.1 类型声明与核心特性
public struct MonoTime <: Hashable & Comparable<MonoTime>MonoTime表示单调时间,是一个用来衡量经过时间的时间类型,类似一直运行的秒表,专门用于"计算时间差"。
- 表示范围:Duration.Zero 至 Duration.Max,数值表示为 [0, 2^63)(单位为秒),精度为纳秒;
- 单调保证:通过
now()创建的MonoTime总是晚于之前通过该方式创建的MonoTime(不受系统时间调整影响); - 典型场景:性能测试计时、时间优先的任务队列(需要单调递增时间戳做排序)。
MonoTime.now()底层调用clock_gettime并读取CLOCK_MONOTONIC时钟:
| 系统 | 系统调用函数 | 时钟类型 |
|---|---|---|
| Linux | clock_gettime | CLOCK_MONOTONIC |
| Windows | clock_gettime | CLOCK_MONOTONIC |
| macOS | clock_gettime | CLOCK_MONOTONIC |
这与DateTime.now()使用的CLOCK_REALTIME形成鲜明对比:单调时钟不受系统时间校准影响,因此MonoTime是测量代码执行耗时的正确选择。
2.2 MonoTime API
public static func now(): MonoTime public func compare(rhs: MonoTime): Ordering public func hashCode(): Int64now():获取与当前时间对应的MonoTime;compare(rhs):比较两个实例大小,返回 Ordering(GT/EQ/LT);hashCode():获取哈希值。
运算符:MonoTime提供与DateTime类似的完整运算符集:
| 运算 | 签名 | 返回值 | 异常 |
|---|---|---|---|
| + | MonoTime + Duration | MonoTime | 超出表示范围抛 ArithmeticException |
| - | MonoTime - Duration | MonoTime | 超出表示范围抛 ArithmeticException |
| - | MonoTime - MonoTime | Duration(经过的时间间隔) | — |
| 比较 | <<===!=>=> | Bool | — |
其中MonoTime - MonoTime是最常用的计时手段:用两次now()的结果相减即可获得精确到纳秒的耗时。
2.3 计时实战示例
完整示例见 monotime_test.md:
import std.time.* const count = 10000 main() { let start = MonoTime.now() for (_ in 0..count) { DateTime.now() } let end = MonoTime.now() let result = end - start println("total cost: ${result.toNanoseconds()}ns") }运行结果(以实际结果为准):
total cost: 951159ns该示例演示了标准计时模式:start = MonoTime.now()→ 执行被测代码 →end = MonoTime.now()→end - start得到 Duration 耗时,再调用toNanoseconds()等单位换算方法输出。由于MonoTime的单调特性,即使测量过程中系统时间被修改,计时结果依然准确。
三、时间字符串格式规范
DateTime.parse(str, format)与format(fmt)依赖统一的格式字母体系,规则详见 std.time 包介绍。核心约束如下:
- 必含日期信息:字符串必须包含描述具体年月日的信息,如公元年(y)+ 月(M)+ 日(d),或公元年(y)+ 一年中的第几天(D);
- 缺省默认值:不包含时分秒则均默认为 0;不包含时区信息则默认为当前时区
TimeZone.Local; - 同一字母仅允许一次:不允许对同一字母表示的格式两次取值(如两次 y);表示时区的 O 和 Z 两种格式不允许同时出现;
- 辅助验证:部分字母格式仅作辅助信息验证,如
"2023-04-24-Mon"使用"yyyy-MM-dd-www"解析时会验证 "Mon" 的正确性。
字母含义表:
| 字母 | 含义 |
|---|---|
| a | 上下午 |
| y | 公元年 |
| Y | 基于周的年 |
| M | 月份 |
| d | 日 |
| D | 以年算的天数 |
| w | 以周算的天 |
| W | 基于 ISO-8601 标准的周 |
| h | 12 小时制的小时 |
| H | 24 小时制的小时 |
| m | 分钟数 |
| s | 秒数 |
| S | 小于一秒的部分 |
| z | 时区名和时区 ID |
| Z | 距零时区偏移 |
| O | 时区偏移 |
| G | 纪年 |
字母数量规则要点:
- 年(y):1/3/4 个解析 4 位数年份;2 个解析 2 位数年份(xx >= 69 解析为 19xx,否则 20xx);5~9 个解析对应位数年份;
- 月(M):1 个解析 1~2 位数字;2 个解析 2 位数字;3 个解析简写(Jan、Dec);4 个解析完整书写(January、December);
- 小数秒(S):1 个解析 3 位(毫秒);2 个解析 6 位(微秒);3 个解析 9 位(纳秒);
- 时区偏移(O):1 个解析
+08(非整小时截断);2 个解析+08:00;3 个解析+08:00:00;4 个输出 case2 或 case3,偏移为 0 时输出 Z; - 时区名和 ID(z):1/2/3 个解析缩写(CST、GMT);4 个解析时区 ID(如 "Asia/Shanghai")。
另外,DateTimeFormat 类提供 4 个预置格式常量可直接复用:RFC1123(www, dd MMM yyyy HH:mm:ss z)、RFC3339(yyyy-MM-ddTHH:mm:ssOOOO)、RFC822(ww dd MMM yy HH:mm:ss z)、RFC850(wwww, dd-MMM-yy HH:mm:ss z)。
四、关联类型与异常
4.1 TimeZone 时区
DateTime的时区信息由 TimeZone 承载:
TimeZone.Local:本地时区,从环境变量 TZ 读取时区 ID 并加载;TZ 未设置时,Linux/Unix like 系统加载/etc/localtime链接,失败或 Windows 系统下返回UTC+偏移量形式时区;TimeZone.UTC:UTC 时区;TimeZone.load(id):从系统加载指定 ID 的时区(Linux/macOS/HarmonyOS 从系统时区目录加载,可通过CJ_TZPATH环境变量指定路径;Windows 需下载并编译 IANA 时区文件后设置CJ_TZPATH);init(id, offset):自定义时区,偏移量精度为秒,向东为正,取值范围 (-25h, 26h)。
4.2 Month 与 DayOfWeek 枚举
- Month:表示 1~12 月,
Month.of(Int64)构造,toInteger()/toString()转换,支持+/-月份运算; - DayOfWeek:表示周日~周六(0 表示周日,1~6 表示周一至周六),同样支持
of、toInteger、+/-运算。
4.3 异常类型
| 异常 | 触发场景 |
|---|---|
| TimeParseException | 解析时间字符串失败,或同一 format 多次取值 |
| InvalidDataException | 加载时区文件失败(找不到文件、解析失败) |
| IllegalArgumentException | 构造参数超出范围、format 不合法、时区 ID 非法 |
| ArithmeticException | 计算结果超出 DateTime/MonoTime 表示范围 |
五、实战选择建议
- 业务时间戳与日历计算(如订单时间、跨时区排期、日志记录):使用
DateTime,配合now()/nowUTC()、of/ofUTC、format/parse、inTimeZone/inUTC完成构造、展示与时区换算; - 代码耗时与性能基准:使用
MonoTime的now()+ 减法运算,避免系统时间调整造成误差; - 不确定输入的解析:优先
tryParse返回 Option 结果,避免异常流程; - 时间差计算:
DateTime - DateTime得到 Duration,再通过toDays/toHours/toMinutes/toSeconds/toNanoseconds等方法换算为所需单位; - 版本兼容:
monthValue、parse(String, DateTimeFormat)、toString(DateTimeFormat)已被标记 deprecated,新代码应改用month属性、parse(String, String)与format(String)。
参考文档
- 结构体 API 原文
- std.time 包介绍与时间字符串格式
- TimeZone 与 DateTimeFormat 类说明
- Month 与 DayOfWeek 枚举说明
- 时间异常类型
- DateTime 属性读取示例
- DateTime 格式化与解析示例
- DateTime 跨时区比较示例
- DateTime 时区转换示例
- MonoTime 计时示例
- Duration 时间间隔类型
- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
相关推荐
仓颉 std.time 时间包详解:DateTime、MonoTime、TimeZone 与时间字符串格式化解析全指南
仓颉 std.time 时间包详解:DateTime、MonoTime、TimeZone 与时间字符串格式化解析全指南 本文以仓颉标准库 stdlib 中的 s
编程语言语言运行时标准库垃圾回收并发编程仓颉 std.time 时间枚举完整指南:DayOfWeek 与 Month 的 API 解析与实战
仓颉 std.time 时间枚举完整指南:DayOfWeek 与 Month 的 API 解析与实战 本文以仓颉标准库 std.time 包中的两个核心枚举类型
文档知识库教程OpenHarmonycangjie_runtime std.time 实战:用 DateTime pattern 完成仓颉时间字符串的格式化与解析
cangjie_runtime std.time 实战:用 DateTime pattern 完成仓颉时间字符串的格式化与解析 本篇基于 cangjie_run
编程语言语言运行时标准库垃圾回收并发编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考