2

I have the following javascript code for a countdown timer:

var end = new Date('10/26/2016 4:00 PM');

var _second = 1000;
var _minute = _second * 60;
var _hour = _minute * 60;
var _day = _hour * 24;
var timer;

function showRemaining() {
    var now = new Date();
    var distance = end - now;
    if (distance < 0) {

      clearInterval(timer);
      document.getElementById('countdown').innerHTML = 'EXPIRED!';

      return;
    }
    var days = Math.floor(distance / _day);
    var hours = Math.floor((distance % _day) / _hour);
    var minutes = Math.floor((distance % _hour) / _minute);
    var seconds = Math.floor((distance % _minute) / _second);

    document.getElementById('countdown').innerHTML = minutes + 'mins ' + seconds + 'secs';
}

timer = setInterval(showRemaining, 1000);

This works but the problem is I need the countdown timer to work on GMT/UTC time as all my times on the site / server are all stored in that way.

At the moment this countdown timer is using the users local time for the now setting. This script will be accessed worldwide so i cannot use local timezones and it must be in the GMT/UTC format.

i.e as of the time of posting this the current GMT time is 13:17 but if I access the script over in the UK the local time is 14:17 so the countdown is out by 1 hour.

I know javascript has the

toUTCString()

method but when I try and call this on

function showRemaining() {
    var now = new Date().toUTCString();
    ...

It results in this output:

NaNmins NaNsecs

jsfiddle is here => https://jsfiddle.net/pzbz35q1/1/

odd_duck
  • 3,941
  • 7
  • 43
  • 85
  • There is no "local" Date object, they're all UTC. The string "10/26/2016 4:00 PM" has no timezone offset so if parsed to a Date will represent a different moment in time for each host with a different time zone offset. – RobG Oct 26 '16 at 22:55

3 Answers3

4

I have used something similar to the following before:

var now = new Date();
var nowUTC = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());
var distance = end - nowUTC;

The .toUTCString() will place a string of the current UTC date/time in the variable, so any calculations based off it will fail (as it's trying to calculate a number from a string).

  • Thanks. That works. Just after posting I also spotted I could do this `var now = new Date(); var gmt = new Date(now.getTime() + now.getTimezoneOffset() * 60000);` which also works – odd_duck Oct 26 '16 at 13:58
  • The time value of a Date is UTC already, what you are doing is adjusting the UTC time value so that when the timezone offset is applied, it returns local values that are the same as the unadjusted UTC values. You should be using UTC methods in the first place. – RobG Oct 26 '16 at 23:17
2

Javascript Date objects are always UTC. It's the values passed to the constructor and those returned by the get* methods that may be treated as local.

Parsing of "10/26/2016 4:00 PM" by the Date constructor is entirely implementation dependent and the result may well be an invalid date. If parsed correctly, it should be treated as 26 October, 2016 16:00 in the host system's timezone. The host offset will be used to create a UTC time value for that date and time. Please note that the use of mm/dd/yyyy format is ambiguous for most of the world's population so the format of the string should be provided to the parser.

If you want "10/26/2016 4:00 PM" treated as UTC, then you should parse it as such:

/* Parse string in mm/dd/yyyy hh:mm ap format as UTC.
** '10/26/2016 4:23 PM'
** @param {string} s - string in required format
** @returns {Date} - if string is invalid then an invalid Date is returned
*/
function parseAsUTC(s) {
  var b = s.split(/\D/);
  var hr = b[3]%12 + (/pm$/i.test(s)? 12 : 0);
  var d = new Date(Date.UTC(b[2], --b[0], b[1], hr, b[4]))
  return d && d.getUTCMonth() == b[0] && d.getUTCHours() == hr? d : new Date(NaN);
}

var d = parseAsUTC('10/26/2016 4:23 PM');
console.log('UTC date: ' + d.toISOString() + '\n' +
            'Local equivalent: ' + d.toLocaleString());                 
RobG
  • 142,382
  • 31
  • 172
  • 209
-1

Please correct me if I am wrong, but I think we can just do something like this:

var end = new Date('Oct 26, 2016 04:00:00 GMT+00:00')

Or to get the number of milliseconds for a countdown timer:

var end = new Date('Oct 26, 2016 04:00:00 GMT+00:00').getTime()

The getTime() function returns the number of milliseconds since the Unix Epoch.

So, as far as I know that should give you exactly what you need. You'll just need to convert milliseconds to seconds, minutes, hours, days, like you are doing.

kojow7
  • 10,308
  • 17
  • 80
  • 135