日期计算器:把日期选择框、时间选择框和计时器的日期方法做成一个实用小工具,顺带一个会自动保存的「倒数日」清单。
下载 DateCalculator.aia 返回搜索需求专题
这一篇回答的搜索:获取日期选择框选中日期的前一天、日期选择框如何使用、如何获取日期选择框选择的日期、时间选择框如何使用、获取当前时间、datepicker。
界面

图为由最终 .aia 生成的布局预览(数值为示例),不是真机截图。
能做什么
| 功能 | 例子 |
|---|---|
| 当前日期时间 | 顶部每秒刷新:2026年10月05日 星期一 21:30:15 |
| 选一个日期 | 前一天、后一天、星期几、今年第几天、距今天还有/已过几天;◀ ▶ 按钮逐日移动 |
| 日期加减 | 2026-10-05 的 100 天之后是 2027-01-13 星期三;支持天、周、个月、年 |
| 相差几天 | 2026-01-01 到 2026-12-31 相差 364 天(52 周零 0 天),含首尾 365 天 |
| 时间选择框 | 选 07:30 → 距离明天 07:30 还有 10 小时 0 分钟 |
| 倒数日 | 期末考试 · 还有 100 天;过零点自动刷新,点一条可删除 |
核心代码
日期选择框选完后,所选日期在 Instant 属性里,是一个「时刻」,配合计时器的日期方法使用。
取前一天、后一天、星期几
计时器的 AddDays 返回新的时刻,不会改原来的值;天数填负数就是往前。星期用自己的列表换算(Weekday 返回 1~7,1 是星期日),不用 WeekdayName——后者在英文系统上会显示 Monday。
global 星期表 = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
function 日期文字(时刻) {
return join(计时器1.FormatDate(时刻, "yyyy-MM-dd"), " ", 星期表[计时器1.Weekday(时刻)])
}
when 日期选择框_日期.AfterDateSet() {
var 选中 = 日期选择框_日期.Instant
标签_日期结果.Text = join("选中:", 日期文字(选中), "\n前一天:", 日期文字(计时器1.AddDays(选中, -1)), "\n后一天:", 日期文字(计时器1.AddDays(选中, 1)))
}
两个日期相差几天:先对齐到零点
Duration 得到两个时刻相差的毫秒数,DurationToDays 换成天数(向零取整)。日期选择框的时刻都在零点,可以直接相减;但「现在」带着时分秒,要先用 MakeDate 造出今天零点再算,否则晚上算出来会少一天。
function 今天() {
return 计时器1.MakeDate(计时器1.Year(计时器1.Now()), 计时器1.Month(计时器1.Now()), 计时器1.DayOfMonth(计时器1.Now()))
}
function 相差天数(开始, 结束) {
return 计时器1.DurationToDays(计时器1.Duration(开始, 结束))
}
when 日期选择框_结束.AfterDateSet() {
var 天 = 相差天数(日期选择框_开始.Instant, 日期选择框_结束.Instant)
标签_相差结果.Text = join("相差 ", abs(天), " 天,距今天 ", 相差天数(今天(), 日期选择框_结束.Instant), " 天")
}
时间选择框:距离下一次某时刻还有多久
时间选择框给出 Hour 和 Minute。用今天的年月日拼出这个时刻,如果已经过了就加一天:
when 时间选择框_时刻.AfterTimeSet() {
var 现在 = 计时器1.Now()
var 目标 = 计时器1.MakeInstantFromParts(计时器1.Year(现在), 计时器1.Month(现在), 计时器1.DayOfMonth(现在), 时间选择框_时刻.Hour, 时间选择框_时刻.Minute, 0)
if 计时器1.GetMillis(目标) <= 计时器1.GetMillis(现在) {
目标 = 计时器1.AddDays(目标, 1)
}
var 分钟 = ceiling(计时器1.Duration(现在, 目标) / 60000)
标签_时间结果.Text = join("还有 ", floor(分钟 / 60), " 小时 ", 分钟 % 60, " 分钟")
}
倒数日保存:时刻存成毫秒数
微数据库不能直接保存「时刻」,要用 GetMillis 转成毫秒数再存,读出来用 MakeInstantFromMillis 还原:
global 倒数日 = []
when 按钮_添加.Click() {
listadd(倒数日, [文本输入框_事件.Text, 计时器1.GetMillis(日期选择框_日期.Instant)])
微数据库1.StoreValue("countdown", 倒数日)
}
when Screen1.Initialize() {
倒数日 = 微数据库1.GetValue("countdown", [])
foreach 项 in 倒数日 {
var 日期 = 计时器1.MakeInstantFromMillis(项[2])
标签_倒数日标题.Text = join(项[1], ":", 计时器1.FormatDate(日期, "yyyy-MM-dd"))
}
}
常见问题
| 现象 | 原因与处理 |
|---|---|
| 相差天数少一天 | 拿「现在」(带时分秒)和零点的日期相减,不足一整天被舍掉了。两边都先对齐到零点(见上面「今天」函数)。 |
| 加 1 个月后日期不对 | 1 月 31 日加 1 个月是 2 月 28 日(闰年 29 日),这是日历规则:目标月份没有 31 日就落在月底。 |
| 星期显示成 Monday | WeekdayName 跟随手机语言,用自己的星期列表按 Weekday 换算。 |
| 日期选择框打开时不是想要的日期 | 用 SetDateToDisplay(年, 月, 日) 或 SetDateToDisplayFromInstant(时刻) 设置打开时停在哪天;它不会触发 AfterDateSet。 |
| 微数据库存了日期,读出来报错 | 时刻不能直接存,存 GetMillis 的毫秒数或 FormatDate 的文本,读出来再还原。 |
| 倒数日过了零点不变 | 成品在计时器里比较「今天」的文字,变了就刷新;App 在后台时计时器默认暂停,回到前台第一秒就会更新。 |
| 想做时间戳转换 | 毫秒时间戳就是 GetMillis 的结果,详见 时间戳转换。 |
用到的组件
验证范围
最终 .aia 已通过:正式编辑器载入与保存重开 0 错误、后台导入、Android APK 编译,并按真实日历语义执行了积木的 22 项业务检查(当前日期与星期、前一天/后一天、闰年 2 月 29 日、逐日移动、加减天/周/年、1 月 31 日加一个月、非法数量、相差天数与逆序、三种时间选择情形、倒数日添加/重启恢复/跨零点刷新/删除)。详见验证记录。
扫码添加客服咨询