近期在公司两次遇到倒计时的不同需求 纪录一下自己的解决思路。
(1)需求1:活动时间在每周二和每周六 计算本次活动距离下次的倒计时(周二⇋ 周六)
function countdist(target, currentTime) {
var date = new Date(currentTime);
var day = date.getDay();
//修复时区问题 (否则拿到当地一天所消耗的时间是不准的)
var datetime = date.getTime() - date.getTimezoneOffset() * 60 * 1000; //【无论东区还是西区】当前的时间戳,当地的时间戳 !!!
var oneDaySStime = 86400000; //一天的毫秒数
var targetDate1 = target; //结束时间是周几??????
var nowIsTargetDay = false; //当前是否是已经到达目标日期
// console.log(date, "今天是", myDay(day));
//当前时间距离【本】周2的天数,
var targetDate1DateDis1 = targetDate1 - day;
//这里只是算天数,没有把小时算在内,也没有考虑跨周的情况,所以不能直接显示
console.log("的剩余天数", targetDate1DateDis1);
//考虑跨周情况
//判断当前时间是否超过(或等于)目标时间,超过则计算下一周的
//如果今天是周三了,那周二活动就是下一周的了
if (targetDate1DateDis1 <= 0) {
targetDate1DateDis1 = targetDate1DateDis1 + 7;
}
//当前时间已经在目标日期内
if (targetDate1DateDis1 == 0) {
nowIsTargetDay = true;
}
let todayHSM = datetime % oneDaySStime; //【本地时间】今天已消耗的是分秒时间戳
console.log(
"今天已消耗的是分秒时间戳",
todayHSM,
"今天已消耗的小时",
todayHSM / (1000 * 60 * 60)
);
//剩余的天数*一天的时间戳-今天已消耗的时间 !!!
let disMtime = targetDate1DateDis1 * oneDaySStime - todayHSM;
console.warn(
"最终: 剩余天数",
targetDate1DateDis1,
"剩余的总秒数",
disMtime,
"距离目标还剩余的小时",
disMtime / (1000 * 60 * 60)
);
return {
nowIsTargetDay: nowIsTargetDay, //是否已经到了目标日期
nextDayDiss: targetDate1DateDis1, //距离下一个活动开启的天数,不会为0,如果已经在目标日期了,会变成下一周的目标
mmtime: disMtime, //距离下一次活动日期时间戳的差值(最终结果!!!)
netDaytmpTime: date.getTime() + disMtime, //下次活动日期的时间戳
};
}
(2)需求2:每三天为一次倒计时
第一种方法: (不涉及世界时间)
//第一次开始时间
var starTime = new Date("2022/11/29 00:00:00").getTime();
// 现在的时间
var nowTime = new Date().getTime();
// 循环了多少遍
var times = parseInt((nowTime - starTime) / (3 * 86400000)) + 1;
console.log(times, "times");
// N个三天的时间
let pointTime = 3 * 86400000 * times;
//如果本次结束
if (starTime + pointTime >= nowTime) {
// 拿到下次的时间
starTime = starTime + pointTime;
}
第二种方法:(涉及世界时间)
<script>
//计算几天是三天中的第几天
function computedOrderDay(starTime, todayTime) {
let threeDayTime = 86400000 * 3;
let disTime = todayTime - starTime;
let time = disTime % threeDayTime;//得到差值除以3天时间戳的余数(剩余的是不满三天的时间)
if (time - 86400000 * 2 > 0) {
return 3
}
else if (time - 86400000 > 0) {
return 2;
}
else {
return 1;
}
}
function formatTime(time) {
let t = new Date(time);
return ` ${t.getFullYear()}年 ${t.getMonth() + 1} 月${t.getDate()}日${t.getHours()}时${t.getMinutes()} 分${t.getSeconds()}秒`
}
//开始时间===================
var starDay = new Date("2022/11/26 20:00:00");
//本地时间时间戳
var starTime = starDay.getTime();
//本地世界时间时间戳
var starTimeLocal = starDay.getTime() - starDay.getTimezoneOffset() * 60 * 1000;
//今天时间======================
var todayday = new Date();
//世界时间戳
var todayTime = todayday.getTime();
//本地时间戳
var todayTimeLocal = todayday.getTime() - todayday.getTimezoneOffset() * 60 * 1000;
var nextTargetTime;//下一个结束日期的时间戳
//3天一个周期对应的时间戳总值
let oneLoopTime = 86400000 * 3;
/*
为什么要用本地时间戳???
因为今天过去了多少小时就是用本地时间算了,例如东八区7点,就是过去了7小时
但是默认的时间戳是世界世界,格林兰时间对应的0时区,东8区7点对应的世界时间戳是格陵兰时间的11点,
这样计算的今天剩余时间是1小时,实际上本地时间剩余的小时是24-8=16
*/
//开始时间当天的剩余时间
let startlesstime = 86400000 - starTimeLocal % 86400000;
//计算周期之外还剩多少时间
//当前周期还剩余的时间,需要用本地时间戳,这里的今天时间戳肯定也需要用到【本地的时间戳】了!!!!!
let looplesstime = oneLoopTime - todayTimeLocal % (oneLoopTime);
//今天时间戳【加】一个周期的剩余时间戳【减去】开始时间一天剩余的时间戳
//这里的【今天】时间戳肯定是要用世界时间戳,否则给new Date()使用的时候就出问题了,因为它接受的要求的是世界世界戳
nextTargetTime = todayTime + looplesstime - startlesstime;
console.warn(`下次周期开始时间 ${formatTime(nextTargetTime)},今天是一周期内的第${computedOrderDay(starTime, todayTime)}天`)
</script>
由两种方法引出的本地时间和世界时间的思考
(1)时间戳是世界时间,世界时间比本地时间少8个小时,处理方法:Time-Time.getTimezoneOffset() * 60 * 1000 可以拿到当地的本地时间。
(2)第二种方法用到【今天】剩余多少时间,这种带有【本地化】的需要考虑时区问题,像第一种方法就不用 因为计算的是两个时间点之间相差的时间戳 无论是世界时间还是本地时间都是一样的。