0

I have written some Javascript to convert a database datetime in UTC format into local datetime. It works fine in Firefox and IE, but does not work in Chrome (for some reason it adds 3 hours to the times). Here is my code, any advice would be very appreciated :)

EDIT : The datetime is passed into my first function in the format '2014-06-21 20:00:00'

    function convertUTCTimeToLocal(utc24HrDateTime) {

    //first convert from 24hr to 12hr clock
    var twentyFourHrTime = convertDateToTime(utc24HrDateTime);
    var twelveHrTime = convert24hrTo12Hr(twentyFourHrTime);
    var twelveHrDateTime = convert12HrToDateTime(utc24HrDateTime, twelveHrTime);
    var utc12HrDateTime = twelveHrDateTime + ' UTC';
    var date = new Date(utc12HrDateTime);
    var dayMonthTimeOnly = convertToDayMonthTimeOnly(date);
    return dayMonthTimeOnly;
}

function convert24hrTo12Hr(time) {
    // Check correct time format and split into components
    time = time.toString().match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];

    if (time.length > 1) { // If time format correct
        time = time.slice(1);  // Remove full string match value
        time[5] = +time[0] < 12 ? ' AM' : ' PM'; // Set AM/PM
        time[0] = +time[0] % 12 || 12; // Adjust hours
    }
    return time.join(''); // return adjusted time or original string
}

function convertDateToTime(fixtureDate) {
    var d = new Date(fixtureDate);       // now
    var y = d.getFullYear();  // the full year (4 digits)
    var m = d.getMonth() + 1; // 0-based month

    var dt = d.getDate();     // 0-based day of the month
    dt = dt < 10 ? '0' + dt : dt; // add a preceding 0 to numbers less than 10      

    var h = d.getHours();     // 0-based hours
    h = h < 10 ? '0' + h : h; // add a preceding 0 to numbers less than 10

    var mn = d.getMinutes();      // minutes
    mn = mn < 10 ? '0' + mn : mn; // add a preceding 0 to numbers less than 10

    return h + ':' + mn;
}

function convert12HrToDateTime(fixtureDate, twelveHrTime) {
    var d = new Date(fixtureDate);       // now
    var y = d.getFullYear();  // the full year (4 digits)
    var m = d.getMonth() + 1; // 0-based month

    var dt = d.getDate();     // 0-based day of the month
    dt = dt < 10 ? '0' + dt : dt; // add a preceding 0 to numbers less than 10      

    return m + '/' + dt + '/' + y + ' ' + twelveHrTime;
}

function convertToDayMonthTimeOnly(fixtureDate) {
    var d = new Date(fixtureDate);       // now
    var y = d.getFullYear();  // the full year (4 digits)
    var m = d.getMonth() + 1; // 0-based month

    var dt = d.getDate();     // 0-based day of the month
    dt = dt < 10 ? '0' + dt : dt; // add a preceding 0 to numbers less than 10      

    var h = d.getHours();     // 0-based hours
    h = h < 10 ? '0' + h : h; // add a preceding 0 to numbers less than 10

    var mn = d.getMinutes();      // minutes
    mn = mn < 10 ? '0' + mn : mn; // add a preceding 0 to numbers less than 10

    return dt + '/' + m + ' ' + h + ':' + mn;
}
user517406
  • 13,623
  • 29
  • 80
  • 120
  • What version of Chrome? What time zone are you in? – TAS May 04 '14 at 18:52
  • version 34.0.1847.131, time zone GMT+2 – user517406 May 04 '14 at 19:35
  • Could you post a simple test case? I am not able to reproduce what you describe. – TAS May 05 '14 at 14:13
  • Example, in the database the datetime is like this : '2014-06-12 20:00:00.000'. This value gets passed to method convertUTCTimeToLocal, and in Chrome is rendered as the first date on this page : http://brasil2014.azurewebsites.net/Team/Brazil. In Firefox it is rendered as '12/6 23:00', whereas in Chrome it renders as '13/6 02:00' – user517406 May 05 '14 at 15:14

1 Answers1

1

Looking at the data returned from the ajax call in the page http://brasil2014.azurewebsites.net/Team/Brazil I was able to reproduce the observation using the following test (written using QUnit):

test("convertUTCTimeToLocal", function(assert) {
    var expected = "12/6 22:00",
        actual = convertUTCTimeToLocal("2014-06-12T20:00:00");
    assert.equal(actual, expected);
});

(My time zone is GMT+1, but with daylight savings, hence I am expecting the time to be offset +2 hours).

I was able to further drill down the problem using the following test case:

test("convertDateToTime", function(assert) {
    var expected = "20:00",
        actual = convertDateToTime("2014-06-12T20:00:00");

    assert.equal(actual, expected);
});

Changing the first lines of the function convertDateToTime to:

function convertDateToTime(fixtureDate) {
    var d = new Date(fixtureDate);       // now
    console.log(d);
    ...
}

showed me that the value of d already was converted from UTC to local time.

Some investigation showed that the underlying cause is the fact that JavaScript engines are free to interpret the date in any timezone it wants. See the following answer for more details.

Using this knowledge I rewritten and simplified the the code as follows:

function convertUTCTimeToLocal(fixtureDate) {

    function zeroPad(num) {
        return num<10 ? '0'+num : num; 
    }

    var d = new Date(fixtureDate + "Z"),
        m = d.getMonth() + 1,
        dt = zeroPad(d.getDate()),
        h = zeroPad(d.getHours()),
        mn = zeroPad(d.getMinutes());
    return dt + '/' + m + ' ' + h + ':' + mn;
}

The following test case shows that it works correctly on both Chrome and Firefox:

test("convertUTCTimeToLocal", function(assert) {
    var expected = "12/6 22:00",
        actual = convertUTCTimeToLocal2("2014-06-12T20:00:00");
    assert.equal(actual, expected);
})
Community
  • 1
  • 1
TAS
  • 2,039
  • 12
  • 17
  • So my 5 functions can basically be boiled down into appending 'Z' to the datetime and then just calling getDate, getHours and getMinutes? Wow... – user517406 May 06 '14 at 18:01