# 日期时间展示规范(小程序前端) > **文档编号**:DS-DATETIME-001 > **版本**:v1.1.0 > **适用范围**:NeoZQYY 小程序所有前端页面 > **最后更新**:2026-03-18 --- ## 一、设计原则 - **就近优先**:越近的时间用越自然的语言表达,减少认知负担。 - **精度递减**:随时间距离增大,展示精度逐步降低(秒 → 分 → 时 → 天 → 日期)。 - **一致性**:全端统一规则,禁止页面间自行实现差异逻辑。 - **可读性优先**:格式选择以用户直觉理解为准,而非技术精确。 --- ## 二、展示规则总表 | 时间距当前的范围 | 展示格式 | 示例 | |---|---|---| | 0 秒 ~ 119 秒(不足 2 分钟) | `刚刚` | 刚刚 | | 2 分钟 ~ 59 分钟 | `N分钟前` | 2分钟前 / 59分钟前 | | 1 小时 ~ 23 小时 59 分 | `N小时前` | 1小时前 / 23小时前 | | 24 小时 ~ 71 小时 59 分(1天~3天内) | `N天前` | 1天前 / 3天前 | | 超过 72 小时(3天前以上) | `YYYY-MM-DD` | 2026-03-10 | > **注**:所有时间差计算以**服务端返回的 UTC 时间戳**为基准,前端根据设备本地时区渲染,不得使用客户端本地时间作为「当前时间」基准。 --- ## 三、逐级规则详解 ### 3.1 刚刚(0 ~ 119 秒) - **触发条件**:`now - timestamp < 120 秒` - **展示文案**:`刚刚` - **说明**:2 分钟内的时间差对用户无感知意义,统一收敛为「刚刚」,不展示具体秒数或分钟数。 ``` 示例:发布于 5 秒前 → 刚刚 发布于 90 秒前 → 刚刚 发布于 119 秒前 → 刚刚 ``` --- ### 3.2 N 分钟前(2 ~ 59 分钟) - **触发条件**:`120 秒 ≤ now - timestamp < 3600 秒` - **展示格式**:`Math.floor(diff / 60) + '分钟前'` - **最小值**:2分钟前 - **最大值**:59分钟前 ``` 示例: diff = 120s → 2分钟前 diff = 3540s → 59分钟前 ``` > **不得** 展示「1分钟前」(119 秒内均为「刚刚」);**不得** 展示「60分钟前」,3600 秒起跳进入「小时」维度。 --- ### 3.3 N 小时前(1 ~ 23 小时) - **触发条件**:`3600 秒 ≤ now - timestamp < 86400 秒` - **展示格式**:`Math.floor(diff / 3600) + '小时前'` - **最小值**:1小时前 - **最大值**:23小时前 ``` 示例: diff = 3600s → 1小时前 diff = 82800s → 23小时前 ``` > **不得** 展示「24小时前」,86400 秒起跳进入「天」维度。 --- ### 3.4 N 天前(1 ~ 3 天) - **触发条件**:`86400 秒 ≤ now - timestamp < 259200 秒`(即 1 天 ~ 不足 72 小时) - **展示格式**:`Math.floor(diff / 86400) + '天前'` - **最小值**:1天前 - **最大值**:3天前 ``` 示例: diff = 86400s → 1天前 diff = 259199s → 3天前 ``` > **临界说明**:72小时(259200秒)整数点,即 diff ≥ 259200 秒,切换为日期格式。 --- ### 3.5 日期展示(超过 3 天) - **触发条件**:`now - timestamp ≥ 259200 秒`(≥ 72 小时) - **展示格式**: - **同年**:`MM-DD`(省略年份,如 `03-10`) - **跨年**:`YYYY-MM-DD`(保留年份,如 `2025-08-21`) - **分隔符**:使用连字符 `-`,不使用斜杠 `/` 或中文「年月日」 - **不展示时分秒**:日期维度下不展示具体时刻。 ``` 示例(当前日期 2026-03-18): 时间戳 2026-03-10 → 03-10 时间戳 2025-08-21 → 2025-08-21(跨年展示完整年份) ``` --- ## 四、判断流程图 ``` 输入:服务端时间戳 timestamp │ ▼ diff = now - timestamp(单位:秒) │ ┌─────┴───────┐ │ diff < 120 │──► 刚刚 └─────┬───────┘ │ ┌─────┴──────────┐ │ diff < 3600 │──► N分钟前(N = floor(diff/60),2≤N≤59) └─────┬──────────┘ │ ┌─────┴──────────┐ │ diff < 86400 │──► N小时前(N = floor(diff/3600),1≤N≤23) └─────┬──────────┘ │ ┌─────┴──────────┐ │ diff < 259200 │──► N天前(N = floor(diff/86400),1≤N≤3) └─────┬──────────┘ │ ▼ 日期格式(同年MM-DD / 跨年YYYY-MM-DD) ``` --- ## 五、前端实现参考(JavaScript) ```javascript /** * 格式化时间展示 * @param {number} timestamp - 服务端返回的 Unix 时间戳(毫秒) * @returns {string} 格式化后的时间文案 */ function formatRelativeTime(timestamp) { const now = Date.now(); const diff = Math.floor((now - timestamp) / 1000); // 转换为秒 if (diff < 120) { return '刚刚'; } if (diff < 3600) { return `${Math.floor(diff / 60)}分钟前`; } if (diff < 86400) { return `${Math.floor(diff / 3600)}小时前`; } if (diff < 259200) { // 72小时 = 3天 return `${Math.floor(diff / 86400)}天前`; } // 超过3天,展示日期 const date = new Date(timestamp); const nowDate = new Date(now); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); if (year === nowDate.getFullYear()) { return `${month}-${day}`; // 同年省略年份 } return `${year}-${month}-${day}`; // 跨年显示完整年份 } ``` > **微信小程序说明**:可直接将此函数挂载到 `utils/time.js`,在 WXML 中通过 `wxs` 模块或 `Page.data` 绑定使用。 --- ## 六、边界与特殊情况处理 | 场景 | 处理方式 | |---|---| | `timestamp` 为空 / undefined | 展示 `--`,不报错 | | `timestamp` 为未来时间(服务端时钟偏差) | 统一展示 `刚刚`(diff < 0 时按 0 处理) | | 用户设备时区异常 | 以服务端返回的格式化日期字段(fallback)为准 | | 时间戳单位(秒 vs 毫秒) | 统一由服务端约定为**毫秒**,前端不做猜测 | --- ## 七、禁止事项 - ❌ 禁止展示「1分钟前」「60分钟前」「24小时前」「0分钟前」等临界歧义文案(2分钟内统一展示「刚刚」) - ❌ 禁止在「天」维度之后继续展示相对文案(如「7天前」「30天前」) - ❌ 禁止使用中文「年月日」格式(如「2026年3月10日」),统一使用 `-` 分隔符 - ❌ 禁止在超3天后展示时分秒 - ❌ 禁止各页面自行定义时间格式化函数,必须引用 `utils/time.js` 统一工具 --- ## 八、关联文档 - [VI 设计规范](./VI-DESIGN-SYSTEM.md) - [组件库规范](../components/) - `apps/miniprogram/miniprogram/utils/time.js`(工具函数实现位置)