Sleight of Date

3 01 2015

Flickr: by Paolo Margari

Someone posted an interesting JavaScript question recently at StackOverflow, concerning how one may  convert a date string into Unix time without the timezone effecting the result. In reflecting on that question, I also discovered a “trick” by which one can fool a local date object to a degree.


Consider the following snippet which converts Valentine’s Day midnight 2014 as a string to Unix time:


var date_str  = "2014-02-14";

// extract year, month and day   
var year      = date_str.split('-')[0];
var month     = date_str.split('-')[1] - 1;          
var day       = date_str.split('-')[2];

var ms        = Date.UTC( year, month, day );          
var unix_time = ms/1000;  // convert to seconds 
                            
    console.log("Unix time: " + unix_time); 

/** 
  * Output: Unix time: 1392336000
  *
  * Live demo: http://codepen.io/anon/pen/ZYBrxN
 **/

JavaScript’s Date Object, usually functions as a constructor for instantiating a new date object. In this case it does nothing of the sort; its presence permits the static UTC() method to execute. Alternately, you could use Date.parse() with date_str as a parameter to achieve the same outcome, a benefit of which is less code. However, Date.UTC() lends itself nicely to self-documenting the code; one knows that this static method clearly deals with UTC time.

One immediate question concerns its result, how do you really know that ms contains the correct value? There are two ways to check it, the easiest of which is as follows:


// Presuming preceding variable listing

var date      = new Date( date_str );
    console.log( date.toUTCString( ms ) );  

/** 
  * Output: Fri, 14 Feb 2014 00:00:00 GMT
  *
  * Live demo: http://codepen.io/anon/pen/gbLvrm
 **/

Passing date_str as a parameter to create a new date object in local time may seem odd until you realize that such objects among their many methods, come with a slew of UTC-oriented ones. When the UTCString method parses ms, it proves the credibility of its value.

The following snippet indicates a different way of getting Unix time, as follows:


var dt = new Date(2014, 1, 14); // 1 = Feb; mos: 0-11 in JS
var ms = dt.getTime();
var unix_time = ms / 1000;
    console.log( "UTC time: "; + unix_time );
    console.log( dt.toUTCString( ms ) );

// the string is the thing!
var dt2 = new Date( "2014-02-14" );
var ms2 = dt2.getTime();
var unix_time = ms2 / 1000;
    console.log( "UTC time: " + unix_time );
    console.log( dt2.toUTCString( ms2 ) );

/**
  * 
  * Output: UTC time: 1392364800
  *         Fri, 14 Feb 2014 08:00:00 GMT
  *
  *         UTC time: 1392336000
  *         Fri, 14 Feb 2014 00:00:00 GMT
  *
  * Live demo: http://jsfiddle.net/9862tq84/7/
  *
**/

The getTime method (like valueOf(), too) returns UTC time in milliseconds. When these are parsed, the result may be incorrect if you dutifully pass the Date constructor the numeric parameters it expects, in which case, instead of seeing a time of midnight, 8:00 a.m displays, owing to the PST timezone having an offset from UTC of minus eight hours.

One can trick the local date object if its argument is a numeric string conforming to the international standard of the month, day, and year format. Then, the local date object will be unaware as to what timezone that string pertains, so the timezone defaults to 0, i.e. UTC’s timezone. You still need to use the toUTCString method, to see a pure UTC result.  Otherwise, if you simply use the toString method, the local date object will append information about the local timezone.

There is another way to check the value that ms contains. The solution requires far more code but, in exchange, it offers more flexibility in formatting the result, as follows:


function padZero( n ){
    return ( n < 10 )? "0" + n : n;
}

// Presuming variable listing of first example, plus:
var dt_obj   = new Date( date_str );

/* months array */
var months = new Array( 1, 2, 3, 4, 5,6,
                        7, 8, 9, 10, 11, 12 );

var month = months[ dt_obj.getUTCMonth( ms ) ];  

// build array of date part objects
var arr = [                                   
 { yr: dt_obj.getUTCFullYear( ms ),
 toString: function() {return this.yr; }
 },
 { mo: month, 
 toString: function() { return padZero( this.mo );
 }},
 { day: dt_obj.getUTCDate( ms ) ,
 toString: function(){ return padZero( this.day );
 }},
 { hrs: dt_obj.getUTCHours( ms ) ,
 toString: function(){ return padZero( this.hrs );
 }},
 { mins: dt_obj.getUTCMinutes( ms ),
 toString: function(){ return padZero( this.mins );
 }},
 { secs: dt_obj.getUTCSeconds( ms ),
 toString: function(){ return padZero( this.secs );
 }}];
 
console.log( arr.join('-').split('-00').join(':00') );
/** 
  * Output:  2014-02-14:00:00:00
  *
  * Live demo: http://codepen.io/anon/pen/MYbQoL
**/

This second example creates an interesting array of date parts as objects.  Each one features a toString() method, which pads single digits with a zero and facilitates joining an object’s property value with others. After the UTC() method retrieves the precise time in milliseconds, the script passes that data to a local date object’s relevant methods. That object, a creation by “sleight of date”, i.e. using the aforementioned date string “trick”, provides a pure UTC result.

Recommended Reading

This work is licensed under a Creative Commons License

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: