如何基于给定的活动时间规则计算距离下一次活动触发的剩余时长
JavaScript 活动下一次触发剩余时间计算实现
核心逻辑
- 先建立星期名称到JS原生日期对象星期索引的映射:JS中
Date.getDay()返回值为0~6,0对应周日、1对应周一、6对应周六 - 拆分两种时间规则的解析逻辑:
- 标注
EVERY的每日规则:优先取今日对应时间,若今日时间已过则自动顺延到次日 - 标注具体星期的周规则:优先取本周对应星期的时间,若本周时间已过则自动顺延到下周
- 标注
- 单个活动存在多个触发规则时取时间最近的计算剩余时长
- 自动格式化剩余时长为天/时/分/秒的可读格式
注意事项
原events对象中AirDrop的规则Thusday为拼写错误,需改为Thursday才能正常解析。
完整实现代码
// 活动规则定义(修正了AirDrop的星期拼写错误) let events = { "KOTH Airship": ["EVERY 19:00"], "KOTH Castle": ["EVERY 20:00"], "Totem": ["EVERY 17:00", "EVERY 23:00"], "Jump": ["Monday 18:00"], "Laby PvP": ["Tuesday 18:00"], "MegaKOTH Nether": ["Wednesday 18:00"], "AirDrop": ["Thursday 18:00"], "Rain of Items": ["Friday 18:00"], "MegaKOTH Pyramid": ["Saturday 18:00"], "MegaKOTH End": ["Sunday 18:00"], }; // 星期映射表 const WEEK_MAP = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6 }; /** * 解析时间规则生成下一次触发的Date对象 * @param {string} rule 时间规则 * @returns {Date} 下一次触发时间 */ function parseRuleToNextDate(rule) { const now = new Date(); // 处理每日规则 if (rule.startsWith('EVERY ')) { const [hour, minute] = rule.replace('EVERY ', '').split(':').map(Number); const triggerTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute, 0); // 今日时间已过,顺延到明天 if (triggerTime < now) { triggerTime.setDate(triggerTime.getDate() + 1); } return triggerTime; } // 处理周规则 const [weekName, timeStr] = rule.split(' '); const [hour, minute] = timeStr.split(':').map(Number); const targetWeekDay = WEEK_MAP[weekName]; const currentWeekDay = now.getDay(); // 计算距离目标星期的天数差 let diffDays = targetWeekDay - currentWeekDay; const triggerTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute, 0); // 本周时间已过,加7天到下周 if (diffDays < 0 || (diffDays === 0 && triggerTime < now)) { diffDays += 7; } triggerTime.setDate(triggerTime.getDate() + diffDays); return triggerTime; } /** * 格式化剩余时间为可读格式 * @param {number} ms 剩余毫秒数 * @returns {string} 格式化后的剩余时间 */ function formatRemainTime(ms) { const days = Math.floor(ms / (1000 * 60 * 60 * 24)); const hours = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((ms % (1000 * 60)) / 1000); return `${days}天${hours}小时${minutes}分${seconds}秒`; } /** * 获取所有活动下一次触发的剩余时间 * @returns {Object} 各活动剩余时间映射 */ function getAllEventNextRemainTime() { const now = new Date(); const result = {}; for (const [eventName, rules] of Object.entries(events)) { // 生成所有规则的下一次触发时间,取最近的 const nextTimes = rules.map(rule => parseRuleToNextDate(rule)); const nearestTime = new Date(Math.min(...nextTimes)); const remainMs = nearestTime - now; result[eventName] = { nextTriggerTime: nearestTime.toLocaleString(), remainTime: formatRemainTime(remainMs) }; } return result; } // 调用示例 console.log(getAllEventNextRemainTime());
输出示例
执行调用后会返回如下结构的结果:
{ "KOTH Airship": { "nextTriggerTime": "2024/5/20 19:00:00", "remainTime": "0天3小时25分12秒" }, // 其余活动数据省略 }
内容的提问来源于stack exchange,提问作者daysling
相关产品推荐
相关产品推荐

