资讯动态

Sway 智能合约时间库 std::time 完全指南:Duration 时长、UNIX/TAI64 时间戳与链上区块时间

发布时间:2026/9/12 4:41:37 来源:尧图企业网站定制
Sway 智能合约时间库 std::time 完全指南Duration 时长、UNIX/TAI64 时间戳与链上区块时间【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/swaystd::time是 Sway 标准库sway-lib-std中专门面向智能合约时间处理的模块为开发者提供以秒为单位的Duration时长类型和基于 UNIX 时间戳的Time类型并封装了 Fuel 虚拟机内部使用的 TAI64 时间与 UNIX 时间的自动换算。本文以官方文档 time.md 为核心骨架结合标准库源码 time.sw、配套示例 examples/time/src/main.sw 与语言内测试 time.sw系统讲解创建、转换、运算与错误处理读完即可在合约中实现锁仓、过期校验、限流等基于时间的高可靠性逻辑。1. std::time 库概览std::time库位于 Sway 标准库中通过 sway-lib-std/src/lib.sw 的pub mod time;声明对外暴露提供两个核心类型类型语义底层表示Duration一段以秒计的时间跨度u64秒数Time一个 UNIX 时间戳自 1970-01-01 00:00:00 UTC 起的秒数u64秒数从源码结构看time.swDuration内部只有一个字段seconds: u64Time同样只包装unix: u64time.sw。两者都实现了PartialEq、Eq、Ord、OrdEq、Hash以及Fromu64/Intou64因此可以直接参与相等判断、大小比较、哈希计算并与u64无缝互转。在合约中使用时通过use std::time::*;引入即可示例工程的 Forc.toml 展示了依赖声明方式[project] authors [Fuel Labs contactfuel.sh] entry main.sw license Apache-2.0 name time [dependencies] std { path ../../sway-lib-std }2. Duration以秒为单位的时间跨度2.1 创建 DurationDuration提供两条创建路径常量与构造函数。预定义常量定义于 time.sw常量秒数说明Duration::ZERO0零时长Duration::SECOND11 秒Duration::MINUTE601 分钟Duration::HOUR3_6001 小时Duration::DAY86_4001 天Duration::WEEK604_8001 周Duration::MINu64::MIN最小时长Duration::MAXu64::MAX最大时长构造函数seconds/minutes/hours/days/weekstime.sw接收任意u64并按固定倍数换算为秒例如Duration::hours(2)内部计算2 * 3_600。官方示例 完整演示了两条路径fn create_durations() { // Using constants let zero Duration::ZERO; let second Duration::SECOND; let minute Duration::MINUTE; let hour Duration::HOUR; let day Duration::DAY; let week Duration::WEEK; // Using constructor methods let thirty_seconds Duration::seconds(30); let two_hours Duration::hours(2); let three_days Duration::days(3); }2.2 转换 Duration库支持在seconds、minutes、hours、days、weeks五种时间尺度间转换对应as_seconds()/as_minutes()/as_hours()/as_days()/as_weeks()方法time.sw内部实现为对底层秒数做整数除法。注意as_minutes()等换算基于整数除法无法整除的余数会被截断例如 90 秒as_minutes()返回 1。源码文档注释中明确标注了这一行为time.sw。官方示例fn convert_durations() { let two_days Duration::days(2); assert(two_days.as_seconds() 172800); // 2 * 86400 assert(two_days.as_minutes() 2880); // 2 * 1440 assert(two_days.as_hours() 48); // 2 * 24 assert(two_days.as_days() 2); assert(two_days.as_weeks() 0); // Truncated value }注意最后一行2 天换算为周会被截断为 0——这是设计行为而非 bug在做精度要求高的换算时需特别留意。2.3 Duration 运算Duration实现了Add加法与Subtract减法运算time.sw并实现了PartialEq/Eq相等判断与Ord的、大小比较time.sw。语言内测试对每种常量的换算、相等与序关系均有断言覆盖见 time.sw。官方示例fn duration_operations() { let day1 Duration::DAY; let day2 Duration::days(1); // Equality assert(day1 day2); // Addition let two_days day1 day2; assert(two_days.as_days() 2); // Subtraction let half_day two_days - Duration::days(1).add(Duration::hours(12)); assert(half_day.as_hours() 12); // Comparison assert(Duration::MINUTE Duration::HOUR); }从源码可以推断乘法与除法运算的impl Multiply/impl Divide目前被注释掉time.sw因此当前版本中Duration不支持乘除只能通过构造方法与加减运算组合实现。3. TimeUNIX 时间戳Time表示一个 UNIX 时间戳自 1970-01-01 起经过的秒数用于表示链上某个时刻。3.1 创建 Time 的三种方式官方示例 给出了三种创建方式fn create_timestamps() { // Current block time let now Time::now(); // Specific block time let block_time Time::block(12345); // From UNIX timestamp let custom_time Time::new(1672531200); // Jan 1, 2023 00:00:00 UTC }三种方式的底层实现time.swTime::new(unix_timestamp: u64)直接包装一个自定义 UNIX 时间戳适用于构造已知时刻。Time::now()通过内联汇编读取当前区块的 TAI64 时间戳再减去TAI_64_CONVERTER得到 UNIX 时间pub fn now() - Self { let tia64 asm(timestamp, height) { bhei height; time timestamp height; timestamp: u64 }; Self { unix: tia64 - TAI_64_CONVERTER, } }Time::block(block_height: u32)读取指定区块高度的出块时间适用于回溯历史时刻如链上治理中的提案截止时间比较pub fn block(block_height: u32) - Self { let tia64 asm(timestamp, height: block_height) { time timestamp height; timestamp: u64 }; Self { unix: tia64 - TAI_64_CONVERTER, } }3.2 Time 运算Time与Duration联合使用支持add(duration)/subtract(duration)将时间前后平移time.sw。duration_since(earlier)计算与更早时刻的间隔返回ResultDuration, TimeError当earlier晚于自身时返回Err(TimeError::LaterThanTime)time.sw。elapsed()计算相对当前区块时间已流逝的时长返回ResultDuration, TimeError当自身晚于当前时间时返回Err(TimeError::LaterThanNow)time.sw。官方示例fn time_operations() { let now Time::now(); let yesterday now.subtract(Duration::DAY); let tomorrow now.add(Duration::DAY); // Duration calculations let elapsed now.duration_since(yesterday).unwrap(); assert(elapsed.as_days() 1); // Comparison assert(yesterday now); assert(tomorrow now); }Time同样实现了Ord的、比较time.sw。语言内测试time_time_add/time_time_subtract对平移运算做了大量断言time.sw并覆盖了溢出/下溢场景默认情况下Time::new(u64::max()).add(Duration::SECOND)会触发 revertrevert_time_time_overflow_add而在禁用溢出 panic 后则表现为回绕wrapping语义——这与 Sway 的算术安全检查机制一致。3.3 TimeError 错误处理TimeError枚举time.sw只有两个变体pub enum TimeError { /// Returned when the Time passed is later than the current Time. LaterThanTime: (), /// Returned when the current Time is later than the current block time. LaterThanNow: (), }LaterThanTimeduration_since(earlier)中传入的earlier比自身更晚。LaterThanNowelapsed()中自身时间戳比当前区块时间更晚例如传入了未来时刻。因此duration_since()与elapsed()都应视为可能失败的操作通过.unwrap()或模式匹配处理错误这也是官方最佳实践中的硬性要求。4. TAI64 与 UNIX 时间转换4.1 为什么链上要用 TAI64Fuel 虚拟机内部使用 TAI64 时间。TAI64 是一种连续时间标度不包含闰秒而 UNIX 时间基于 UTC历史上会因闰秒插入而产生不连续。区块链要求确定性执行——同一笔交易在任何节点重放都必须得到相同结果因此采用单调、无歧义的 TAI64 作为底层时间基准。标准库通过 block.sw 提供底层访问timestamp()返回当前区块的 TAI64 时间戳、timestamp_of_block(height)返回指定区块的 TAI64 时间戳、height()返回当前区块高度block.sw。4.2 换算常量与公式库中定义的换算常量time.swconst TAI_64_CONVERTER: u64 10 (1 62);(1 62)即0x4000000000000000TAI64 规范用它作为标记位标识一个数值为 TAI64 时间戳。10补偿 1970 年时 TAI 与 UTC 之间累积的初始偏移约 10 秒。换算公式UNIX → TAI64: tai64 unix TAI_64_CONVERTER TAI64 → UNIX: unix tai64 - TAI_64_CONVERTER对应实现为as_tai64()time.sw与from_tai64()time.swpub fn from_tai64(tai64: u64) - Self { Self { unix: tai64 - TAI_64_CONVERTER, } } pub fn as_tai64(self) - u64 { self.unix TAI_64_CONVERTER }4.3 转换示例官方示例fn tai64_conversion() { let now Time::now(); // Convert to TAI64 let tai64 now.as_tai64(); // Convert back to UNIX time let converted Time::from_tai64(tai64); assert(now converted); }语言内测试验证了双向换算的往返一致性并确认Time::now().as_tai64() timestamp()、Time::from_tai64(timestamp()) Time::now()time.sw——这说明Time类型与链上 TAI64 时间戳之间是严格可逆的。4.4 TAI64 与 UNIX 关键差异对照FeatureTAI64UNIXEpoch1970-01-01 00:00:00 TAI1970-01-01 00:00:00 UTCLeap Seconds无闰秒包含闰秒Stability连续时间标度存在不连续调整Value Range(1 62) 偏移10 秒自纪元起的秒数4.5 为什么选择 TAI64确定性执行Deterministic execution不存在闰秒歧义同一输入必然产生同一结果单调递增Monotonic time时间始终稳定前进不会回拨链上友好Blockchain-friendly与 Fuel 的区块时间戳机制天然对齐。5. 最佳实践官方文档给出 5 条建议结合源码可进一步解读其依据用Duration表示时间跨度而非裸秒数——自文档化且附带单位换算能力避免魔法数字。始终处理duration_since()与elapsed()返回的TimeError——两者返回ResultDuration, TimeError传入未来时间会得到Err忽略会导致非预期行为甚至 panic。与区块链原语交互时转换为 TAI64——Fuel 虚拟机内部、std::block::timestamp()等接口均为 TAI64使用as_tai64()/from_tai64()保持边界一致。历史时间比较优先用Time::block(height)——它返回指定区块的确定性时间相比当前时间更适合治理投票、拍卖截止等场景。优先使用SECOND、HOUR等时长常量——可读性更强且经语言内测试逐项验证time.sw。6. 局限性精度为秒级Duration只支持秒级精度无法表达毫秒/微秒。比较范围受限于u64时间比较基于u64约 5840 亿年对合约场景足够但并非无限。无日历/日期功能Time仅提供时间戳没有年月日格式化、时区等日历能力。换算会截断小数单位as_*系列方法为整数除法不整除时直接截断如 2 天as_weeks()为 0。7. 实践中的典型应用场景基于以上 API可以在合约中组合出常见的时间逻辑例如锁仓到期判断use std::time::{Time, Duration}; // 假设存储了锁仓解锁时间 fn is_unlocked(lock_time: Time) - bool { Time::now() lock_time }或基于duration_since计算两次操作之间的间隔并做限流注意对Result的错误分支做处理let last_action Time::block(previous_height); let cooldown Duration::MINUTE; match now.duration_since(last_action) { Result::Ok(elapsed) assert(elapsed cooldown), Result::Err(TimeError::LaterThanTime) revert(0), }8. 相关资源索引官方文档docs/book/src/blockchain-development/time.md标准库实现sway-lib-std/src/time.sw模块声明见 sway-lib-std/src/lib.sw配套示例examples/time/src/main.sw 及工程配置 examples/time/Forc.toml链上底层时间接口sway-lib-std/src/block.sw语言内测试覆盖常量、换算、相等/序、加减、溢出、TAI64 往返等test/src/in_language_tests/test_programs/time/src/time.sw综上std::time以两个薄封装类型Duration、Time加上 TAI64 换算机制为 Sway 合约提供了简洁、确定、可验证的时间处理能力配合 sway-lib-std/src/time.sw 源码与 time.sw 测试开发者可以放心地在生产合约中构建基于时间戳的各类业务逻辑。【免费下载链接】sway Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价