admin管理员组

文章数量:1291114

I've got two Date() times and I'm trying to use the difference between them to set the width of a progress bar shrinking from 100% to 0% when there is no more difference between the times, but I'm getting really strange results.

This is how I'm trying to do it currently (it's being split across a couple of different functions in React so I'll just include the code that is relevant) :

First I set up the target datetime which sets the endDate to the top of the hour within the next 24hrs (e.g 10pm exactly)...

this.endDate = new Date();

if (this.props.data.end_hr === 0) {
    this.endDate.setHours(24, 0, 0, 0);
} else {
    this.endDate.setHours(this.props.data.end_hr);
}
this.endDate.setMinutes(0);
this.endDate.setSeconds(0);

this.countdown = setInterval(this.timeRemaining, 1000);

Then in the timeRemaining function, which fires every second, I'm getting the current datetime and calculating the difference between them. Lastly I'm trying to work out a percentage to send to the progress bar css width property...

let now = new Date().getTime();
let diff = this.endDate - now;

let percent =
  Math.round(((diff / this.endDate) * 100000000 * 2) / 100) + '%';

this.countdownProgress.style.width = percent;

The diff is 100% correct but the percentage is wrong.

I've tried every different way of calculating the percentage that I could think of but nothing works as expected, the method above was the closest I could get.

Could somebody show me where I'm going wrong please?

Edit: @Danziger's answer implemented in the way that I want to use it. This sets the start time at 10pm and the end time at midnight.

It turns out that it does work correctly so I must have something else in my code causing the issue. Thanks again to Danziger for showing me light!

const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');

const startDate = new Date();
startDate.setHours(22);
startDate.setMinutes(0);
startDate.setSeconds(0);

const endDate = new Date();
endDate.setHours(24,0,0,0);
endDate.setMinutes(0);
endDate.setSeconds(0);

const range = endDate - startDate;

function updateCountdown() {
  const diff = Math.max(0, endDate - new Date());
  
  progressBar.style.width = `${ 100 * diff / range }%`;
  progressText.innerText = `${ `000${ Math.ceil(diff / 1000) }`.slice(-4) } seconds`
  
  if (diff >= 0) {
    requestAnimationFrame(updateCountdown);
  }  
}

updateCountdown();
body {
  font-family: monospace;
}

.progressBar__base {
  position: relative;
  height: 32px;
  border: 3px solid black;
  margin: 0 0 8px;
}

.progressBar__progress {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: blue;
}
<div class="progressBar__base">
  <div class="progressBar__progress" id="progressBar"></div>
</div>

<div id="progressText"></div>

I've got two Date() times and I'm trying to use the difference between them to set the width of a progress bar shrinking from 100% to 0% when there is no more difference between the times, but I'm getting really strange results.

This is how I'm trying to do it currently (it's being split across a couple of different functions in React so I'll just include the code that is relevant) :

First I set up the target datetime which sets the endDate to the top of the hour within the next 24hrs (e.g 10pm exactly)...

this.endDate = new Date();

if (this.props.data.end_hr === 0) {
    this.endDate.setHours(24, 0, 0, 0);
} else {
    this.endDate.setHours(this.props.data.end_hr);
}
this.endDate.setMinutes(0);
this.endDate.setSeconds(0);

this.countdown = setInterval(this.timeRemaining, 1000);

Then in the timeRemaining function, which fires every second, I'm getting the current datetime and calculating the difference between them. Lastly I'm trying to work out a percentage to send to the progress bar css width property...

let now = new Date().getTime();
let diff = this.endDate - now;

let percent =
  Math.round(((diff / this.endDate) * 100000000 * 2) / 100) + '%';

this.countdownProgress.style.width = percent;

The diff is 100% correct but the percentage is wrong.

I've tried every different way of calculating the percentage that I could think of but nothing works as expected, the method above was the closest I could get.

Could somebody show me where I'm going wrong please?

Edit: @Danziger's answer implemented in the way that I want to use it. This sets the start time at 10pm and the end time at midnight.

It turns out that it does work correctly so I must have something else in my code causing the issue. Thanks again to Danziger for showing me light!

const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');

const startDate = new Date();
startDate.setHours(22);
startDate.setMinutes(0);
startDate.setSeconds(0);

const endDate = new Date();
endDate.setHours(24,0,0,0);
endDate.setMinutes(0);
endDate.setSeconds(0);

const range = endDate - startDate;

function updateCountdown() {
  const diff = Math.max(0, endDate - new Date());
  
  progressBar.style.width = `${ 100 * diff / range }%`;
  progressText.innerText = `${ `000${ Math.ceil(diff / 1000) }`.slice(-4) } seconds`
  
  if (diff >= 0) {
    requestAnimationFrame(updateCountdown);
  }  
}

updateCountdown();
body {
  font-family: monospace;
}

.progressBar__base {
  position: relative;
  height: 32px;
  border: 3px solid black;
  margin: 0 0 8px;
}

.progressBar__progress {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: blue;
}
<div class="progressBar__base">
  <div class="progressBar__progress" id="progressBar"></div>
</div>

<div id="progressText"></div>

Share Improve this question edited Jan 23, 2019 at 23:22 spice asked Jan 23, 2019 at 22:10 spicespice 1,5103 gold badges22 silver badges41 bronze badges 6
  • 1 You’re calculating diff / endDate, when you’re looking to calculate diff / (endDate - startDate) - that is diff as a percentage of the total time between startDate and endDate. Also, using your current definition for diff will give you a decreasing progress bar. If you want an increasing one, use diff = now - startDate instead. – MTCoster Commented Jan 23, 2019 at 22:22
  • Just tried that - Math.round(diff / (this.endDate - now)) and I'm getting 1 back? The endDate in question is currently set to midnight UK and it's currently 22:29 here at the moment. – spice Commented Jan 23, 2019 at 22:30
  • Ahh so I need to supply a start date? I'm not doing that. Only an endDate and the current time – spice Commented Jan 23, 2019 at 22:31
  • 2 If you don’t have a start date, you can’t know how much progress has been made. That’s like asking “Given that you’ve travelled 200 miles, how much of your journey to Toronto have you covered? – MTCoster Commented Jan 23, 2019 at 22:33
  • 1 We’ve all been there :p – MTCoster Commented Jan 23, 2019 at 22:36
 |  Show 1 more ment

2 Answers 2

Reset to default 7

I think your problem is that you don't have a defined startTime to use as a reference and instead you're using now.

If you had a startTime, you would do:

let now = new Date().getTime();
let totalTime = endTime - startTime;
let progress = now - startTime;
let percentage = (progress / totalTime) * 100;

I'm not actually sure what value you're getting with your own calculation.

You need to divide diff by some range, in this case, the time difference you had initially (which is its maximum value), not by endDate:

const progressBarDescending = document.getElementById('progressBarDescending');
const progressBarAscending = document.getElementById('progressBarAscending');
const progressTextDescending = document.getElementById('progressTextDescending');
const progressTextAscending = document.getElementById('progressTextAscending');

const startDate = new Date();
const endDate = new Date(startDate.getTime() + 10000); // + 10 seconds
const range = endDate - startDate;

function updateCountdown() {
  const diff = Math.max(0, endDate - new Date());
  
  progressBarDescending.style.width = `${ 100 * diff / range }%`;
  progressBarAscending.style.width = `${ 100 - 100 * diff / range }%`;
  
  progressTextDescending.innerText = `${ `000${ Math.ceil(diff / 1000) }`.slice(-4) } seconds left`;
  progressTextAscending.innerText = `${ `000${ Math.floor((range - diff) / 1000) }`.slice(-4) } seconds elapsed`;
  
  if (diff >= 0) {
    requestAnimationFrame(updateCountdown);
  }  
}

updateCountdown();
body {
  font-family: monospace;
}

.progressBar__base {
  position: relative;
  height: 32px;
  border: 3px solid black;
  margin: 16px 0 8px;
}

.progressBar__progress {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: blue;
}
<div class="progressBar__base">
  <div class="progressBar__progress" id="progressBarDescending"></div>
</div>

<div id="progressTextDescending"></div>

<div class="progressBar__base">
  <div class="progressBar__progress" id="progressBarAscending"></div>
</div>

<div id="progressTextAscending"></div>

So, let's say you start this countdown at startDate = 5 and endDate = 15, so your range = 10.

If you want to update the diff after 5 seconds, that would be diff = endDate - now = endDate - 10 = 5. Then, progress = 100 * diff / range = 100 * 5 / 10, not progress = 100 * diff / endDate = 100 * 5 / 15.

本文标签: Percentage of time left with two given timestamps JavascriptStack Overflow