Javascript: Convert a Date object to an ISO 8601 formatted string

 
One of my technical New Year’s Resolutions is to clean up my collection of code snippets. Over the years I’ve built up a sizeable collection but many of them are either not very useful anymore or could be improved. After deleting those that are no longer useful I am cleaning up the code of those that are left, making sure they validate in the latest version of JSLint, before posting them to this blog and sharing them on Gist and Snipplr, with a jsFiddle thrown in where useful.

The first snippet posted is a simple shim to convert a Javascript date object to an ISO 8601 formatted string. The format of these strings is comprehensively detailed  on the W3C website but, simply put, it looks like this:


Screenshot_1_13_13_9_18_PM-2

As well as being a simple, easy-to-understand string format it’s well-supported in many languages which makes it useful for data interchange. Most modern languages have a function to take a date and return an ISO 8601 string. In Javascript, this function is ‘ISODateString’ but, unfortunately, it isn’t implemented in all commonly used browsers – significantly, Internet Explorer 8 and earlier don’t include it.

The simple solution is a small function that will use the ‘ISODateString’ when it is available and fallback to a d-i-y solution when it isn’t. In that way we get a working solution now and the performance and reliability improvements of a native browser solution when it is available without the need to change our code.


if (typeof Date.prototype.toISOString !== 'function') {

    (function () {

        'use strict';

        // Function which takes a 1 or 2-digit number and returns
        // it as a two-character string, padded with
        // an extra leading zero, if necessary.
        function pad(number) {
            var r = String(number);
            if (r.length === 1) {
                r = '0' + r;
            }
            return r;
        }

        Date.prototype.toISOString = function () {
            return this.getUTCFullYear()
                + '-' + pad(this.getUTCMonth() + 1)
                + '-' + pad(this.getUTCDate())
                + 'T' + pad(this.getUTCHours())
                + ':' + pad(this.getUTCMinutes())
                + ':' + pad(this.getUTCSeconds())
                + '.' + String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
                + 'Z';
         };

    }());
}

The structure of the snippet is straightforward. In line 1 I check if the native function exists. If it does then nothing more needs to be done. If it doesn’t then I create a new function with the same name as the native one which takes a date object and concatenates together its constituent parts to make the ISO string. As ISO 8601 requires that Month, Day, Hours, etc. are two digits there is another function – ‘Pad’ – which takes a number and ensures it is two digits long by padding with a leading zero, if necessary. By wrapping the whole thing in an anonymous function I ensure that ‘Pad’ is not globally available and so won’t clash with any existing function of the same name.
A few minor tweaks to the layout and the addition of ‘use strict’ ensures that it validates cleanly in the latest version of JSLint (Edition 2012-12-31).

The source for this function can be downloaded from Gist or Snipplr.
You can also try it out in jsFiddle.


More:

3 useful Oracle queries

Yesterday I posted 3 useful MySQL queries that I use almost every day. As I also work with Oracle I have to use the equivalents for that database i.e. I regularly have to create database update scripts – scripts that create tables or add new columns to existing tables or populate new tables with base data. One requirement is that these scripts be re-runnable. For example, if a new table doesn’t exist it should be created, if it does exist then the update script should continue without throwing an error. For these situations I find the following simple queries very useful. Wrap them in functions written in your language of choice and you have an easy way to check the current status of your Oracle database before taking action.

1. Check if a table exists in the current database schema

select table_name
from user_tables
where table_name = '__TABLE_NAME__'
2. Check if a column exists in a table
select column_name as found
from user_tab_cols
where table_name = '__TABLE_NAME__'
and column_name = '__COLUMN_NAME__'
3. Check if a table contains any data
select 1
from __TABLE_NAME__
where rownum = 1
After running each of these queries, simply check if any rows were returned. A non-zero row count indicates the existence of the table, the column or the data as appropriate. These three queries, and a couple of variations on them, can also be found on my Gist page.
An alternative method for checking if a table or column exists before creating it is to just go ahead with your create / alter table and catch any error that comes along. This is not a sensible or correct approach in most situations. The existence of a table or column is a knowable property that is easily checked – throwing an error then scrambling around to determine what caused it by comparing error codes is crude, avoidable and not at all what exception handling is intended for.

 

Previously:

 

3 useful MySQL queries

I regularly have to create database update scripts i.e. scripts that create tables or add new columns to existing tables or populate new tables with base data. One requirement is that these scripts be re-runnable. For example, if a new table doesn’t exist it should be created, if it does exist then the update script should continue without throwing an error. For these situations I find the following simple queries very useful.

Wrap them in functions written in your language of choice and you have an easy way to check the current status of your MySQL database before taking action.

1. Check if a table exists in the current database schema

select table_name as found
from information_schema.tables
where table_schema = SCHEMA()
and table_name = '__table_name__'

2. Check if a column exists in a table

select column_name as found
from information_schema.columns
where table_schema = SCHEMA()
and table_name = '__table_name__'
and column_name = '__column_name__'

3. Check if a table contains any data

select 1
from __table_name__
limit 1

After running each of these queries, simply check if any rows were returned. A non-zero row count indicates the existence of the table, the column or the data as appropriate.

These three queries, and a couple of variations on them, can also be found on my Gist page.

 

Geolocating IP Addresses for free using geoPlugin.net and ColdFusion

Geolocation is defined by Wikipedia as “the identification of the real-world geographic location of an object, such as a radar, mobile phone or an Internet-connected computer terminal.” One of the most useful (and common) applications of geolocation is to take an IP address and convert it to a real world location such as a city or country. Why would this be useful? Suppose we have a visitor to our web site with IP address 208.73.210.29 – by geolocating that IP we discover that our site visitor is in Los Angeles, California, U.S.A. From this we know we can show the visitor prices in U.S. dollars, events in the Los Angeles area or a local weather forecast. Simply put, geolocation gives us a low-risk way to add a layer of personalisation and convenience to our web sites.

As well as being very useful, gelocation is incredibly simple  – there are a number of free, public API’s that will take an IP address and convert it into more usable data. One of the best of these is geoPlugin.net, a site that has been offering a free and reliable geolocation service for more than five years. By providing a number of web services to suit different programming languages (PHP, Java, JSON, XML, even ASP) it’s likely they have your requirements covered.

 

The code

The following is an example function, written in ColdFusion, showing just how easy it can be to integrate location data into your site.


<cffunction name="ipLocation"
            access="remote"
            returntype="struct"
            displayname="ipLocation"
            output="no">

  <cfargument name="ip" type="string" required="no" default="">

  <cfset var local = StructNew()>

  <cftry>

    <cfset local.ip = Trim(arguments.ip)>
    <cfset local.url = "http://www.geoplugin.net/json.gp?ip=#local.ip#">

    <cfhttp result="local.ipRequest"
            url="#local.url#"
            method="get"
            timeout="5"
            throwOnError="yes"/>

    <cfset local.ipRequest =
           ReplaceList(local.ipRequest.filecontent,
                       "geoPlugin(,),geoplugin_",",,")>
    <cfif isJSON(local.ipRequest) EQ "No">
      <cfthrow message="geoPlugin response to #local.url# was not JSON format - #local.ipRequest#">
    <!--<span class="hiddenSpellError" pre=""-->cfif>

    <cfset local.return = StructNew()>

    <cfset local.return["status"] = "OK">
    <cfset local.return["geoplugin"] =
           DeserializeJSON(local.ipRequest,true)>

    <cfloop list="status,dmaCode,regionCode,areaCode" index="local.id">
      <cfif IsNumeric(local.return.geoplugin[local.id])>
        <cfset local.return.geoplugin[local.id] =
               Javacast("int",local.return.geoplugin[local.id])>
      <!--<span class="hiddenSpellError" pre=""-->cfif>
    <!--<span class="hiddenSpellError" pre=""-->cfloop>

    <!--- For consistency, we convert "null"s to empty strings --->
    <cfloop collection="#local.return.geoplugin#" item="local.id">
      <cfif local.return.geoplugin[local.id] EQ "null">
        <cfset local.return.geoplugin[local.id] = "">
      </cfif>
    <!--<span class="hiddenSpellError" pre=""-->cfloop>

    <cfreturn local.return>
    <cfcatch>
      <cfset local.return = StructNew()>
      <cfset local.return["status"] = "BAD">
      <cfset local.return["cfcatch"] = cfcatch>
      <cfreturn local.return>
    </cfcatch>

  </cftry>

</cffunction>

This function expects an IP address to be passed in which will be available to us as arguments.ip. Lines 14-20 are the bit that matters – we build the geoPlugin.net URL that we are going to call (in this case we want JSON formatted output returned to us as that is easier to manipulate than the alternatives), then we make a HTTP get request to geoPlugin.net.


<cfhttp result="local.ipRequest"
        url="#local.url#"
        method="get"
        timeout="5"
        throwOnError="yes"/>

The response from geoPlugin is then stored in the variable local.ipRequest. In most cases the response time is usually less than 100ms but I have occasionally seen a very slow response so I am allowing a timeout period of 5 seconds. What will happen if no IP address is passed to geoPlugin? The IP of the server making the request will be used. Although this won’t cause a problem, it won’t be much use either as you won’t be retrieving the geolocation details of your visitor but of your own ColdFusion server.

Assuming we call geoPlugin with the IP address 208.73.210.29, this is the response we would receive:

geoPlugin({
"geoplugin_request":"208.73.210.29",
"geoplugin_status":200,
"geoplugin_city":"Los Angeles",
"geoplugin_region":"CA",
"geoplugin_areaCode":213,
"geoplugin_dmaCode":803,
"geoplugin_countryCode":"US",
"geoplugin_countryName":"United States",
"geoplugin_continentCode":"NA",
"geoplugin_latitude":34.053298950195,
"geoplugin_longitude":-118.25489807129,
"geoplugin_regionCode":"CA",
"geoplugin_regionName":"California",
"geoplugin_currencyCode":"USD",
"geoplugin_currencySymbol":"$",
"geoplugin_currencyConverter":1
})

Unfortunately, although this looks like it is JSON, it isn’t quite. A quick check using JSONLint tells us that the geoPlugin() that wraps the response is not valid JSON. Simply stripping this off gives us something we can use, so that is exactly what we do in line 22

<cfset local.ipRequest =
       ReplaceList(local.ipRequest.filecontent,
                   "geoPlugin(,),geoplugin_",",,")>

before converting the JSON into a ColdFusion structure in line 32

<cfset local.return["geoplugin"] =
           DeserializeJSON(local.ipRequest,true)>

This should really be us finished – we have our response from geoPlugin and we’ve converted it into a format that ColdFusion can use. If we CFDUMP the structure DeserializeJSON has returned we can see what we have:

This looks exactly right. All of the fields are populated and are in the correct format. If all we want to do is return this structure as is to another ColdFusion template then we’re done. But what if we want to allow this function to be called as a web service or from Javascript using Ajax and to return JSON formatted output? This is easy enough – all we’d need to do is call the function using this URL:

http://myhost.com/geoplugin.cfc?method=iplocation&returnformat=json&ip=208.73.210.29

 

200 or 200.0?

Without the code at lines 35-40, this is what would be returned:

{
  "geoplugin":
  {
   "currencySymbol":"$",
   "continentCode":"NA",
   "request":"208.73.210.29",
   "status":200.0,
   "regionName":"California",
   "dmaCode":803.0,
   "latitude":34.053298950195,
   "countryCode":"US",
   "countryName":"United States",
   "regionCode":"CA",
   "currencyConverter":1.0,
   "city":"Los Angeles",
   "longitude":-118.25489807129,
   "region":"CA",
   "currencyCode":"USD",
   "areaCode":213.0
  },
  "status":"OK"
}

Look at the values returned for status,dmaCode,regionCode and areaCode. Instead of 213 the areaCode is being returned as 213.0. Worse still, depending on what version of ColdFusion you are using and what hotfixes you have applied it may actually be returned as the string “213.0”. I want to force these values to be returned as integers and this I do using Javacast:

<cfloop list="status,dmaCode,regionCode,areaCode" index="local.id">
  IsNumeric(local.return.geoplugin[local.id])>
    <cfset local.return.geoplugin[local.id] =
           Javacast("int",local.return.geoplugin[local.id])>
  </cfif>
</cfloop>

 

Dealing with null values

The final change I make to the geoPlugin data before returning it is to deal with null values. If we call geoLocation with IP set to 173.254.216.66 we get this response:

geoPlugin({
  "geoplugin_request":"173.254.216.66",
  "geoplugin_status":206,
  "geoplugin_city":"",
  "geoplugin_region":"",
  "geoplugin_areaCode":0,
  "geoplugin_dmaCode":0,
  "geoplugin_countryCode":"A1",
  "geoplugin_countryName":"Anonymous Proxy",
  "geoplugin_continentCode":"--",
  "geoplugin_latitude":0,
  "geoplugin_longitude":0,
  "geoplugin_regionCode":"",
  "geoplugin_regionName":null,
  "geoplugin_currencyCode":null,
  "geoplugin_currencySymbol":null,
  "geoplugin_currencyConverter":null
})

Because this is an anonymous proxy, many of the values are set to null. When this is deserialized to a CF structure and then serialized back into JSON the result is these values being returned as strings with the value “null” which is not the same thing at all.
By converting all null values  to empty strings (“”), lines 43-47 take care of that problem:

<cfloop collection="#local.return.geoplugin#" item="local.id">
  <cfif local.return.geoplugin[local.id] EQ "null">
    <cfset local.return.geoplugin[local.id] = "">
  </cfif>
</cfloop>

As you can see, retrieving location data for an IP is incredibly easy using the geoPlugin API and with a few extra lines of clean up code in ColdFusion we can ensure consistent and trouble free processing of the returned data.

 

Some sample IP addresses

These IP addresses may be useful for testing and illustrate the variety of output from geoPlugin:

  • 208.73.210.29 – Los Angeles, California, U.S.A., all available values returned.
  • 173.254.216.66 – An anonymous proxy – little location data returned.
  • 86.96.160.7 – Dubai, United Arab Emirates, all available values returned.
  • 127.0.0.1 – “Local host” – no values returned (response includes nulls).

 

The W3C geolocation specification

The W3C are currently working on a geolocation specification and we are already starting to see this functionality built into browsers such as Google Chrome. Unfortunately, it is likely it will be some time before this is universally available (if ever) and, even when fully implemented, it will be fairly limited in what it can do. It would seem that there will be a role for services such as geoPlugin for some time to come.

The source code for this ColdFusion function is available for download from Gist or Snipplr.

 

More:


							

Javascript: Accurate timing is (almost) here

If you’ve ever tried to optimize or locate a bottleneck in your Javascript code you’ve most likely ended up using Date().getTime(). As this function returns the number of milliseconds since the 1st of January, 1970 we can easily determine the total run time of the code we wish to test by taking two readings, one immediately prior to the code to be tested and and one immediately after. A simple subtraction will then give us the total run time in milliseconds:


var start, end;

start = (new Date()).getTime();

// Run a test

end = (new Date()).getTime();

alert(end - start);

While this is easy to use and consistently implemented across browsers it has a three flaws that make it less than ideal for benchmarking – the value returned is an integer so it’s useless for timing anything that takes less than a millisecond, it’s derived from the system clock which may be unstable or subject to adjustment and, depending on the operating system and browser, can be significantly wrong.

With the recent release of Google Chrome 20 to beta we now have the opportunity to use a new, more reliable and more precise timer – High Resolution Time a.k.a.  performance.now. More specifically, we can use the Chrome, vendor-prefixed, version – performance.webkitNow.

As performance.webkitNow returns the number of milliseconds since the navigationStart of the page and is not tied to the system clock we get more reliable timings. Better still, it returns the elapsed time as a double with microseconds in the fractional part, allowing us to have more accurate, sub-millisecond, timings.

If we rewrite the previous example to use High Resolution Time instead of Date().getTime() our code would be:


var start, end;

start = window.performance.webkitNow();

// Run a test

end = window.performance.webkitNow();

alert(end - start);

Running this example would give us results such as 0.005999987479299307 whereas our original, Date-based, example consistently returned zero.

Of course, it’s never so simple. This will work fine in Chrome 20 Beta but will error in all other browsers (and earlier versions of Chrome). To allow for other, as yet to be released, vendor-prefixed versions and to be usable today we must create a small shim function:

 var now = (function() {

// Returns the number of milliseconds elapsed since either the browser navigationStart event or
// the UNIX epoch, depending on availability.
// Where the browser supports 'performance' we use that as it is more accurate (microsoeconds
// will be returned in the fractional part) and more reliable as it does not rely on the system time.
// Where 'performance' is not available, we will fall back to Date().getTime().

var performance = window.performance || {};

performance.now = (function() {
return performance.now    ||
performance.webkitNow     ||
performance.msNow         ||
performance.oNow          ||
performance.mozNow        ||
function() { return new Date().getTime(); };
})();

return performance.now();

});   

This will use the “official” performance.now, if it is available. If not it will try each of the vendor prefixes, then ultimately fall back to Date().getTime(), allowing for all eventualities now or in the near future. Using this function is no more difficult that our previous examples:


var start, end;

start = now();

// Run a test

end = now();

alert(end - start);

 

You can try out this function on jsFiddle or grab it from Gist or Snipplr.

 

More: