英文:
Javascript count down to UTC 4am every day & every Sunday
问题
我正在为一个每天和每周都有重置的MMORPG(游戏)构建资源。一个重置是每周日UTC时间上午4点,另一个是每天UTC时间上午4点。我希望在页面顶部显示倒计时计时器来显示这些重置。
下面的JavaScript代码是每天倒计时到午夜。我该如何修改这段代码,以便我可以构建两个倒计时。一个是倒计时到UTC时间上午4点(每天),另一个是倒计时到每周日UTC时间上午4点?
var div = document.getElementById("bb");
setInterval(function() { 
    var toDate = new Date();
    var tomorrow = new Date();
    tomorrow.setHours(24, 0, 0, 0);
    var diffMS = tomorrow.getTime() / 1000 - toDate.getTime() / 1000;
    var diffHr = Math.floor(diffMS / 3600);
    diffMS = diffMS - diffHr * 3600;
    var diffMi = Math.floor(diffMS / 60);
    diffMS = diffMS - diffMi * 60;
    var diffS = Math.floor(diffMS);
    var result = ((diffHr < 10) ? "0" + diffHr : diffHr);
    result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
    result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
    div.innerHTML = result;
},1000);
<div id="bb">
</div>
英文:
I am building a resource for an MMORPG (game) that has daily and weekly resets. One reset is every Sunday @ 4am UTC and another is every day @ 4am UTC. I am looking to display countdown timers at the top of a page for these resets.
This Javascript code below counts down to midnight each day. How can I modify this code so I can build 2 countdowns. 1 that counts down to 4am UTC (daily) and another that counts down to 4am UTC every Sunday?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var div = document.getElementById("bb");
setInterval(function() { 
    var toDate = new Date();
    var tomorrow = new Date();
    tomorrow.setHours(24, 0, 0, 0);
    var diffMS = tomorrow.getTime() / 1000 - toDate.getTime() / 1000;
    var diffHr = Math.floor(diffMS / 3600);
    diffMS = diffMS - diffHr * 3600;
    var diffMi = Math.floor(diffMS / 60);
    diffMS = diffMS - diffMi * 60;
    var diffS = Math.floor(diffMS);
    var result = ((diffHr < 10) ? "0" + diffHr : diffHr);
    result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
    result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
    div.innerHTML = result;
},1000);
<!-- language: lang-html -->
<div id="bb">
</div>
<!-- end snippet -->
答案1
得分: 1
我已经使用你之前提供的代码进行了以下修改:
var div = document.getElementById("bb");
var div2 = document.getElementById("bc");
setInterval(function() { 
    var toDate = new Date();
    var timezoneOffset =  toDate.getTimezoneOffset() / 60; // 与 GMT 的小时差
    
    var tomorrow = new Date();
    tomorrow.setHours(4, 0, 0); // 将时间设置为明天的凌晨4点
    var diffMS = tomorrow.getTime() / 1000 - toDate.getTime() / 1000;
    var diffHr = Math.floor(diffMS / 3600);
    diffMS = diffMS - diffHr * 3600;
    var diffMi = Math.floor(diffMS / 60);
    diffMS = diffMS - diffMi * 60;
    var diffS = Math.floor(diffMS);
    diffHr -= timezoneOffset;
    var result = ((diffHr < 10) ? "0" + diffHr : diffHr);
    result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
    result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
    div.innerHTML = result;
    
    var nextSunday = getNextSunday(new Date());
    nextSunday.setHours(4, 0, 0);
    diffMS = nextSunday.getTime() / 1000 - toDate.getTime() / 1000;
    diffHr = Math.floor(diffMS / 3600);
    diffMS = diffMS - diffHr * 3600;
    diffMi = Math.floor(diffMS / 60);
    diffMS = diffMS - diffMi * 60;
    diffS = Math.floor(diffMS);
    diffHr -= timezoneOffset;
    result = ((diffHr < 10) ? "0" + diffHr : diffHr);
    result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
    result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
    div2.innerHTML = result;
}, 1000);
function getNextSunday(d) {
  var t = new Date(d);
  t.setDate(d.getDate() + (7 - d.getDay()) % 7);
  return t;
}
首先,我对 tomorrow 进行了小的修改,将时间增加了4小时,这样它就设置为凌晨4点,而不是午夜。
然后,我只是添加了另一个 div,用于显示从现在到周日凌晨4点的时间,并在底部添加了一个获取下一个周日日期的函数。
我添加了一个用于 UTC 转换的偏移量,该偏移量在最后应用。除此之外,代码与你之前编写的几乎完全相同!
英文:
I've written this code below using what you had already:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var div = document.getElementById("bb");
var div2 = document.getElementById("bc");
setInterval(function() { 
var toDate = new Date();
var timezoneOffset =  toDate.getTimezoneOffset() / 60; // difference in hours from GMT
var tomorrow = new Date();
tomorrow.setHours(28, 0, 0);
var diffMS = tomorrow.getTime() / 1000 - toDate.getTime() / 1000;
var diffHr = Math.floor(diffMS / 3600);
diffMS = diffMS - diffHr * 3600;
var diffMi = Math.floor(diffMS / 60);
diffMS = diffMS - diffMi * 60;
var diffS = Math.floor(diffMS);
diffHr -= timezoneOffset;
var result = ((diffHr < 10) ? "0" + diffHr : diffHr);
result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
div.innerHTML = result;
var nextSunday = getNextSunday(new Date());
nextSunday.setHours(4, 0, 0);
diffMS = nextSunday.getTime() / 1000 - toDate.getTime() / 1000;
diffHr = Math.floor(diffMS / 3600);
diffMS = diffMS - diffHr * 3600;
diffMi = Math.floor(diffMS / 60);
diffMS = diffMS - diffMi * 60;
diffS = Math.floor(diffMS);
diffHr -= timezoneOffset;
result = ((diffHr < 10) ? "0" + diffHr : diffHr);
result += ":" + ((diffMi < 10) ? "0" + diffMi : diffMi);
result += ":" + ((diffS < 10) ? "0" + diffS : diffS);
div2.innerHTML = result;
}, 1000);
function getNextSunday(d) {
var t = new Date(d);
t.setDate(d.getDate() + (7 - d.getDay()) % 7);
return t;
}
<!-- language: lang-html -->
<div id="bb">
</div>
<div id="bc">
</div>
<!-- end snippet -->
Firstly, I made a small change to add 4 hours to tomorrow so that it's set for 4 am, instead of midnight.
Afterwards, I just added another div where I can put the time between now and Sunday at 4 am and a function to get the date for the next Sunday at the bottom.
I added an offset for the UTC conversion which is applied at the end. After that, the code is almost identical to what you had already written!
答案2
得分: 0
请尝试以下代码:
var dailyResetDiv = document.getElementById("dailyReset");
var weeklyResetDiv = document.getElementById("weeklyReset");
function updateCountdown(targetDate, outputElement) {
    var now = new Date();
    var diffMS = targetDate.getTime() - now.getTime();
    var diffHr = Math.floor(diffMS / 3600000);
    diffMS = diffMS - diffHr * 3600000;
    var diffMi = Math.floor(diffMS / 60000);
    diffMS = diffMS - diffMi * 60000;
    var diffS = Math.floor(diffMS / 1000);
    var result =
        (diffHr < 10 ? "0" + diffHr : diffHr) +
        ":" +
        (diffMi < 10 ? "0" + diffMi : diffMi) +
        ":" +
        (diffS < 10 ? "0" + diffS : diffS);
    outputElement.innerHTML = result;
}
setInterval(function () {
    // 每天在UTC时间的凌晨4点重置
    var dailyReset = new Date();
    dailyReset.setUTCHours(4, 0, 0, 0);
    updateCountdown(dailyReset, dailyResetDiv);
    // 每周在UTC时间的星期日凌晨4点重置
    var weeklyReset = new Date();
    weeklyReset.setUTCHours(4, 0, 0, 0);
    var dayOfWeek = weeklyReset.getUTCDay();
    if (dayOfWeek !== 0) {
        // 如果不是星期日,将日期调整到下一个星期日
        weeklyReset.setUTCDate(weeklyReset.getUTCDate() + (7 - dayOfWeek));
    }
    updateCountdown(weeklyReset, weeklyResetDiv);
}, 1000);
<div id="dailyReset"></div>
<div id="weeklyReset"></div>
英文:
Try this code:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var dailyResetDiv = document.getElementById("dailyReset");
var weeklyResetDiv = document.getElementById("weeklyReset");
function updateCountdown(targetDate, outputElement) {
var now = new Date();
var diffMS = targetDate.getTime() - now.getTime();
var diffHr = Math.floor(diffMS / 3600000);
diffMS = diffMS - diffHr * 3600000;
var diffMi = Math.floor(diffMS / 60000);
diffMS = diffMS - diffMi * 60000;
var diffS = Math.floor(diffMS / 1000);
var result =
(diffHr < 10 ? "0" + diffHr : diffHr) +
":" +
(diffMi < 10 ? "0" + diffMi : diffMi) +
":" +
(diffS < 10 ? "0" + diffS : diffS);
outputElement.innerHTML = result;
}
setInterval(function () {
// Daily reset at 4am UTC
var dailyReset = new Date();
dailyReset.setUTCHours(4, 0, 0, 0);
updateCountdown(dailyReset, dailyResetDiv);
// Weekly reset on Sunday at 4am UTC
var weeklyReset = new Date();
weeklyReset.setUTCHours(4, 0, 0, 0);
var dayOfWeek = weeklyReset.getUTCDay();
if (dayOfWeek !== 0) {
// If not Sunday, adjust the date to the next Sunday
weeklyReset.setUTCDate(weeklyReset.getUTCDate() + (7 - dayOfWeek));
}
updateCountdown(weeklyReset, weeklyResetDiv);
}, 1000);
<!-- language: lang-html -->
<div id="dailyReset"></div>
<div id="weeklyReset"></div>
<!-- end snippet -->
答案3
得分: 0
你可以尝试使用面向对象编程(OOP)的方法,创建一个计时器类(timer class)。你只需要计算目标日期一次,计时器将在一定时间间隔内调用渲染函数。
以下是代码示例:
const localTimeEl = document.querySelector('#local-time');
const utcTimeEl = document.querySelector('#utc-time');
const timerEl1 = document.querySelector('#timer-1');
const timerEl2 = document.querySelector('#timer-2');
const timerEl3 = document.querySelector('#timer-3');
const main = () => {
  // 本地时间
  looper(() => { localTimeEl.textContent = getLocaleTimeString(); }, 1000);
  // UTC 时间
  looper(() => { utcTimeEl.textContent = getLocaleTimeString('UTC'); }, 1000);
  
  // 每天
  const timer1 = new CountdownTimer({
    time: '04:00',
    timeZone: 'UTC',
    renderFn: (duration) => {
      timerEl1.textContent = formatDuration(duration);
    }
  }).start();
  // 下个星期日
  const timer2 = new CountdownTimer({
    time: '04:00',
    timeZone: 'UTC',
    dayOfWeek: 0,
    renderFn: (duration) => {
      timerEl2.textContent = formatDuration(duration);
    }
  }).start();
  
  // 今天
  const timer3 = new CountdownTimer({
    time: '12:00',
    timeZone: 'PDT',
    isToday: true,
    renderFn: (duration) => {
      timerEl3.textContent = formatDuration(duration);
    }
  }).start();
};
const looper = (callback, ms) => {
  setInterval(callback, ms);
  callback();
};
const getLocaleTimeString = (timeZone) =>
  new Date().toLocaleString('en-US', { timeZone });
const parseDuration = (duration) => {
  duration = +duration;
  const days = Math.floor(duration / 8.64e7);
  duration %= 8.64e7;
  const hours = Math.floor(duration / 3.6e6);
  duration %= 3.6e6;;
  const minutes = Math.floor(duration / 6e4);
  duration %= 6e4;
  const seconds = Math.floor(duration / 1e3);
  return { days, hours, minutes, seconds };
}
const applyUnit = (value, singular, plural) =>
  value > 0
    ? value + (value === 1 ? ` ${singular}` : ` ${plural}`)
    : null;
const formatDurationFull = (duration) => {
  const { days, hours, minutes, seconds } = parseDuration(duration);
  return [
    applyUnit(days, 'day', 'days'),
    applyUnit(hours, 'hour', 'hours'),
    applyUnit(minutes, 'minute', 'minutes'),
    applyUnit(seconds, 'second', 'seconds'),
  ].filter(v => v).join(', ');
};
const formatDurationSimple = (duration) => {
  const { days, hours, minutes, seconds } = parseDuration(duration);
  return [ days, hours, minutes, seconds ]
    .map(v => v.toString().padStart(2, '0')).join(':');
};
const formatDuration = (duration) =>
  duration > 0
  ? `${formatDurationSimple(duration)} (${formatDurationFull(duration)})`
  : 'Expired';
const getDateNextWeek = (date, dayOfWeek = 0) => {
  const currentDate = new Date(date);
  currentDate.setDate(currentDate.getDate() + (7 - currentDate.getDay() + dayOfWeek) % 7);
  return currentDate;
};
const getTomorrow = (date) => {
  const currentDate = new Date(date);
  currentDate.setDate(currentDate.getDate() + 1);
  return currentDate;
};
class CountdownTimer {
  constructor(options) {
    const opts = { ...options };
    this.time = opts.time;
    this.timeZone = opts.timeZone;
    this.dayOfWeek = opts.dayOfWeek;
    this.renderFn = opts.renderFn;
    this.isToday = opts.isToday ?? false;
    this.targetDate = this.computeTargetDate();
  }
  start() {
    this.stop();
    this.update();
    this.intervalId = setInterval(this.update.bind(this), 1000);
    return this;
  }
  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
    this.intervalId = undefined;
    return this;
  }
  update() {
    this.renderFn(this.targetDate - new Date());
  }
  // 2019-01-01T00:00:00.000+00:00
  computeTargetDate() {
    const now = new Date();
    const timeTokens = this.time.split(':').map(value => +value);
    const futureHour = timeTokens[0] ?? 0;
    const futureMinute = timeTokens[1] ?? 0;
    const futureSecond = timeTokens[2] ?? 0;
    const timeZone = this.parseTimeZone(this.timeZone);
    let targetDate;
    if (this.isToday) {
      targetDate = now;
    } else {
      if (this.dayOfWeek === undefined) {
        targetDate = getTomorrow(now);
      } else {
        targetDate = getDateNextWeek(now, this.dayOfWeek);
      }
    }
    const y = targetDate.getUTCFullYear();
    const m = (targetDate.getUTCMonth() + 1).toString().padStart(2, '0');
    const d = targetDate.getUTCDate().toString().padStart(2, '0');
    const H = futureHour.toString().padStart(2, '0');
    const M = futureMinute.toString().padStart(2, '0');
    const s = futureSecond.toString().padStart(2, '0');
    const ts = `${y}-${m}-${d}T${H}:${M}:${s}${timeZone}`;
    console.log(`Countdown target date: ${ts}`);
    return Date.parse(ts);
  }
  parseTimeZone(timeZone) {
    const offsetMinutes = this.timeZoneToMinutes(timeZone);
    if (offsetMinutes == null) return '';
    const sign = offsetMinutes < 0 ? '-' : '+';
    const h = Math.abs(offsetMinutes / 60).toString().padStart(2, '0');
    const m = Math.abs(offsetMinutes % 60).toString().padStart(2, '0');
    return `${sign}${h}${m}`;
  }
  timeZoneToMinutes(timeZone) {
    switch (timeZone) {
      case 'UTC':
      case 'GMT':
        return 0;
      case 'EDT': return -240;
      case 'EST': return -300;
      case 'CDT': return -300;
      case 'CST': return -360;
      case 'MDT': return -360;
      case 'MST': return -420;
      case 'PDT': return -420;
      case 'PST': return -480;
      default:
        return null;
    }
  }
}
main();
这段代码创建了一个计时器类(CountdownTimer),并使用了面向对象编程的思想。它包含了计时器的各种功能,如开始计时(start)、停止计时(stop)、更新计时(update)等。你可以根据需要调整代码中的参数和函数,以满足你的需求。
英文:
You could try an OOP approach by creating a timer class. You would only need to compute the target date once. The timer will call the render function on an interval.
<!-- begin snippet: js hide: false console: false babel: false -->
<!-- language: lang-js -->
const localTimeEl = document.querySelector('#local-time');
const utcTimeEl = document.querySelector('#utc-time');
const timerEl1 = document.querySelector('#timer-1');
const timerEl2 = document.querySelector('#timer-2');
const timerEl3 = document.querySelector('#timer-3');
const main = () => {
// Local Time
looper(() => { localTimeEl.textContent = getLocaleTimeString(); }, 1000);
// UTC Time
looper(() => { utcTimeEl.textContent = getLocaleTimeString('UTC'); }, 1000);
// Every day
const timer1 = new CountdownTimer({
time: '04:00',
timeZone: 'UTC',
renderFn: (duration) => {
timerEl1.textContent = formatDuration(duration);
}
}).start();
// Next Sunday
const timer2 = new CountdownTimer({
time: '04:00',
timeZone: 'UTC',
dayOfWeek: 0,
renderFn: (duration) => {
timerEl2.textContent = formatDuration(duration);
}
}).start();
// Today
const timer3 = new CountdownTimer({
time: '12:00',
timeZone: 'PDT',
isToday: true,
renderFn: (duration) => {
timerEl3.textContent = formatDuration(duration);
}
}).start();
};
const looper = (callback, ms) => {
setInterval(callback, ms);
callback();
};
const getLocaleTimeString = (timeZone) =>
new Date().toLocaleString('en-US', { timeZone });
const parseDuration = (duration) => {
duration = +duration;
const days = Math.floor(duration / 8.64e7);
duration %= 8.64e7;
const hours = Math.floor(duration / 3.6e6);
duration %= 3.6e6;;
const minutes = Math.floor(duration / 6e4);
duration %= 6e4;
const seconds = Math.floor(duration / 1e3);
return { days, hours, minutes, seconds };
}
const applyUnit = (value, singular, plural) =>
value > 0
? value + (value === 1 ? ` ${singular}` : ` ${plural}`)
: null;
const formatDurationFull = (duration) => {
const { days, hours, minutes, seconds } = parseDuration(duration);
return [
applyUnit(days, 'day', 'days'),
applyUnit(hours, 'hour', 'hours'),
applyUnit(minutes, 'minute', 'minutes'),
applyUnit(seconds, 'second', 'seconds'),
].filter(v => v).join(', ');
};
const formatDurationSimple = (duration) => {
const { days, hours, minutes, seconds } = parseDuration(duration);
return [ days, hours, minutes, seconds ]
.map(v => v.toString().padStart(2, '0')).join(':');
};
const formatDuration = (duration) =>
duration > 0
? `${formatDurationSimple(duration)} (${formatDurationFull(duration)})`
: 'Expired';
const getDateNextWeek = (date, dayOfWeek = 0) => {
const currentDate = new Date(date);
currentDate.setDate(currentDate.getDate() + (7 - currentDate.getDay() + dayOfWeek) % 7);
return currentDate;
};
const getTomorrow = (date) => {
const currentDate = new Date(date);
currentDate.setDate(currentDate.getDate() + 1);
return currentDate;
};
class CountdownTimer {
constructor(options) {
const opts = { ...options };
this.time = opts.time;
this.timeZone = opts.timeZone;
this.dayOfWeek = opts.dayOfWeek;
this.renderFn = opts.renderFn;
this.isToday = opts.isToday ?? false;
this.targetDate = this.computeTargetDate();
}
start() {
this.stop();
this.update();
this.intervalId = setInterval(this.update.bind(this), 1000);
return this;
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
this.intervalId = undefined;
return this;
}
update() {
this.renderFn(this.targetDate - new Date());
}
// 2019-01-01T00:00:00.000+00:00
computeTargetDate() {
const now = new Date();
const timeTokens = this.time.split(':').map(value => +value);
const futureHour = timeTokens[0] ?? 0;
const futureMinute = timeTokens[1] ?? 0;
const futureSecond = timeTokens[2] ?? 0;
const timeZone = this.parseTimeZone(this.timeZone);
let targetDate;
if (this.isToday) {
targetDate = now;
} else {
if (this.dayOfWeek === undefined) {
targetDate = getTomorrow(now);
} else {
targetDate = getDateNextWeek(now, this.dayOfWeek);
}
}
const y = targetDate.getUTCFullYear();
const m = (targetDate.getUTCMonth() + 1).toString().padStart(2, '0');
const d = targetDate.getUTCDate().toString().padStart(2, '0');
const H = futureHour.toString().padStart(2, '0');
const M = futureMinute.toString().padStart(2, '0');
const s = futureSecond.toString().padStart(2, '0');
const ts = `${y}-${m}-${d}T${H}:${M}:${s}${timeZone}`;
console.log(`Countdown target date: ${ts}`);
return Date.parse(ts);
}
parseTimeZone(timeZone) {
const offsetMinutes = this.timeZoneToMinutes(timeZone);
if (offsetMinutes == null) return '';
const sign = offsetMinutes < 0 ? '-' : '+';
const h = Math.abs(offsetMinutes / 60).toString().padStart(2, '0');
const m = Math.abs(offsetMinutes % 60).toString().padStart(2, '0');
return `${sign}${h}${m}`;
}
timeZoneToMinutes(timeZone) {
switch (timeZone) {
case 'UTC':
case 'GMT':
return 0;
case 'EDT': return -240;
case 'EST': return -300;
case 'CDT': return -300;
case 'CST': return -360;
case 'MDT': return -360;
case 'MST': return -420;
case 'PDT': return -420;
case 'PST': return -480;
default:
return null;
}
}
}
main();
<!-- language: lang-css -->
h2 { margin: 0; padding: 0; margin-top: 0.25rem; font-size: 1.25rem; }
.grid { display: grid; grid-template-rows: repeat(2, auto); grid-auto-flow: column; }
<!-- language: lang-html -->
<div class="grid">
<h2>Local Time</h2>
<div id="local-time"></div>
<h2>UTC Time</h2>
<div id="utc-time"></div>
</div>
<h2>Tomorrow @ 4am UTC</h2>
<div id="timer-1"></div>
<h2>Sunday @ 4am UTC</h2>
<div id="timer-2"></div>
<h2>Today @ 12pm PDT (-07:00)</h2>
<div id="timer-3"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论