/*! iso date This module was built for the exact needs of parsing ISO dates to the microformats standard. * Parses and builds ISO dates to the W3C note, HTML5 or RFC3339 profiles. * Also allows for profile detection using 'auto' * Outputs to the same level of specificity of date and time that was input Copyright (C) 2010 - 2015 Glenn Jones. All Rights Reserved. MIT License: https://raw.github.com/glennjones/microformat-shiv/master/license.txt */ var Modules = (function (modules) { /** * constructor * parses text to find just the date element of an ISO date/time string i.e. 2008-05-01 * * @param {String} dateString * @param {String} format * @return {String} */ modules.ISODate = function ( dateString, format ) { this.clear(); this.format = (format)? format : 'auto'; // auto or W3C or RFC3339 or HTML5 this.setFormatSep(); // optional should be full iso date/time string if(arguments[0]) { this.parse(dateString, format); } }; modules.ISODate.prototype = { /** * clear all states * */ clear: function(){ this.clearDate(); this.clearTime(); this.clearTimeZone(); this.setAutoProfileState(); }, /** * clear date states * */ clearDate: function(){ this.dY = -1; this.dM = -1; this.dD = -1; this.dDDD = -1; }, /** * clear time states * */ clearTime: function(){ this.tH = -1; this.tM = -1; this.tS = -1; this.tD = -1; }, /** * clear timezone states * */ clearTimeZone: function(){ this.tzH = -1; this.tzM = -1; this.tzPN = '+'; this.z = false; }, /** * resets the auto profile state * */ setAutoProfileState: function(){ this.autoProfile = { sep: 'T', dsep: '-', tsep: ':', tzsep: ':', tzZulu: 'Z' }; }, /** * parses text to find ISO date/time string i.e. 2008-05-01T15:45:19Z * * @param {String} dateString * @param {String} format * @return {String} */ parse: function( dateString, format ) { this.clear(); var parts = [], tzArray = [], position = 0, datePart = '', timePart = '', timeZonePart = ''; if(format){ this.format = format; } // discover date time separtor for auto profile // Set to 'T' by default if(dateString.indexOf('t') > -1) { this.autoProfile.sep = 't'; } if(dateString.indexOf('z') > -1) { this.autoProfile.tzZulu = 'z'; } if(dateString.indexOf('Z') > -1) { this.autoProfile.tzZulu = 'Z'; } if(dateString.toUpperCase().indexOf('T') === -1) { this.autoProfile.sep = ' '; } dateString = dateString.toUpperCase().replace(' ','T'); // break on 'T' divider or space if(dateString.indexOf('T') > -1) { parts = dateString.split('T'); datePart = parts[0]; timePart = parts[1]; // zulu UTC if(timePart.indexOf( 'Z' ) > -1) { this.z = true; } // timezone if(timePart.indexOf( '+' ) > -1 || timePart.indexOf( '-' ) > -1) { tzArray = timePart.split( 'Z' ); // incase of incorrect use of Z timePart = tzArray[0]; timeZonePart = tzArray[1]; // timezone if(timePart.indexOf( '+' ) > -1 || timePart.indexOf( '-' ) > -1) { position = 0; if(timePart.indexOf( '+' ) > -1) { position = timePart.indexOf( '+' ); } else { position = timePart.indexOf( '-' ); } timeZonePart = timePart.substring( position, timePart.length ); timePart = timePart.substring( 0, position ); } } } else { datePart = dateString; } if(datePart !== '') { this.parseDate( datePart ); if(timePart !== '') { this.parseTime( timePart ); if(timeZonePart !== '') { this.parseTimeZone( timeZonePart ); } } } return this.toString( format ); }, /** * parses text to find just the date element of an ISO date/time string i.e. 2008-05-01 * * @param {String} dateString * @param {String} format * @return {String} */ parseDate: function( dateString, format ) { this.clearDate(); var parts = []; // discover timezone separtor for auto profile // default is ':' if(dateString.indexOf('-') === -1) { this.autoProfile.tsep = ''; } // YYYY-DDD parts = dateString.match( /(\d\d\d\d)-(\d\d\d)/ ); if(parts) { if(parts[1]) { this.dY = parts[1]; } if(parts[2]) { this.dDDD = parts[2]; } } if(this.dDDD === -1) { // YYYY-MM-DD ie 2008-05-01 and YYYYMMDD ie 20080501 parts = dateString.match( /(\d\d\d\d)?-?(\d\d)?-?(\d\d)?/ ); if(parts[1]) { this.dY = parts[1]; } if(parts[2]) { this.dM = parts[2]; } if(parts[3]) { this.dD = parts[3]; } } return this.toString(format); }, /** * parses text to find just the time element of an ISO date/time string i.e. 13:30:45 * * @param {String} timeString * @param {String} format * @return {String} */ parseTime: function( timeString, format ) { this.clearTime(); var parts = []; // discover date separtor for auto profile // default is ':' if(timeString.indexOf(':') === -1) { this.autoProfile.tsep = ''; } // finds timezone HH:MM:SS and HHMMSS ie 13:30:45, 133045 and 13:30:45.0135 parts = timeString.match( /(\d\d)?:?(\d\d)?:?(\d\d)?.?([0-9]+)?/ ); if(parts[1]) { this.tH = parts[1]; } if(parts[2]) { this.tM = parts[2]; } if(parts[3]) { this.tS = parts[3]; } if(parts[4]) { this.tD = parts[4]; } return this.toTimeString(format); }, /** * parses text to find just the time element of an ISO date/time string i.e. +08:00 * * @param {String} timeString * @param {String} format * @return {String} */ parseTimeZone: function( timeString, format ) { this.clearTimeZone(); var parts = []; if(timeString.toLowerCase() === 'z'){ this.z = true; // set case for z this.autoProfile.tzZulu = (timeString === 'z')? 'z' : 'Z'; }else{ // discover timezone separtor for auto profile // default is ':' if(timeString.indexOf(':') === -1) { this.autoProfile.tzsep = ''; } // finds timezone +HH:MM and +HHMM ie +13:30 and +1330 parts = timeString.match( /([\-\+]{1})?(\d\d)?:?(\d\d)?/ ); if(parts[1]) { this.tzPN = parts[1]; } if(parts[2]) { this.tzH = parts[2]; } if(parts[3]) { this.tzM = parts[3]; } } this.tzZulu = 'z'; return this.toTimeString( format ); }, /** * returns ISO date/time string in W3C Note, RFC 3339, HTML5, or auto profile * * @param {String} format * @return {String} */ toString: function( format ) { var output = ''; if(format){ this.format = format; } this.setFormatSep(); if(this.dY > -1) { output = this.dY; if(this.dM > 0 && this.dM < 13) { output += this.dsep + this.dM; if(this.dD > 0 && this.dD < 32) { output += this.dsep + this.dD; if(this.tH > -1 && this.tH < 25) { output += this.sep + this.toTimeString( format ); } } } if(this.dDDD > -1) { output += this.dsep + this.dDDD; } } else if(this.tH > -1) { output += this.toTimeString( format ); } return output; }, /** * returns just the time string element of an ISO date/time * in W3C Note, RFC 3339, HTML5, or auto profile * * @param {String} format * @return {String} */ toTimeString: function( format ) { var out = ''; if(format){ this.format = format; } this.setFormatSep(); // time can only be created with a full date if(this.tH) { if(this.tH > -1 && this.tH < 25) { out += this.tH; if(this.tM > -1 && this.tM < 61){ out += this.tsep + this.tM; if(this.tS > -1 && this.tS < 61){ out += this.tsep + this.tS; if(this.tD > -1){ out += '.' + this.tD; } } } // time zone offset if(this.z) { out += this.tzZulu; } else { if(this.tzH && this.tzH > -1 && this.tzH < 25) { out += this.tzPN + this.tzH; if(this.tzM > -1 && this.tzM < 61){ out += this.tzsep + this.tzM; } } } } } return out; }, /** * set the current profile to W3C Note, RFC 3339, HTML5, or auto profile * */ setFormatSep: function() { switch( this.format.toLowerCase() ) { case 'rfc3339': this.sep = 'T'; this.dsep = ''; this.tsep = ''; this.tzsep = ''; this.tzZulu = 'Z'; break; case 'w3c': this.sep = 'T'; this.dsep = '-'; this.tsep = ':'; this.tzsep = ':'; this.tzZulu = 'Z'; break; case 'html5': this.sep = ' '; this.dsep = '-'; this.tsep = ':'; this.tzsep = ':'; this.tzZulu = 'Z'; break; default: // auto - defined by format of input string this.sep = this.autoProfile.sep; this.dsep = this.autoProfile.dsep; this.tsep = this.autoProfile.tsep; this.tzsep = this.autoProfile.tzsep; this.tzZulu = this.autoProfile.tzZulu; } }, /** * does current data contain a full date i.e. 2015-03-23 * * @return {Boolean} */ hasFullDate: function() { return(this.dY !== -1 && this.dM !== -1 && this.dD !== -1); }, /** * does current data contain a minimum date which is just a year number i.e. 2015 * * @return {Boolean} */ hasDate: function() { return(this.dY !== -1); }, /** * does current data contain a minimum time which is just a hour number i.e. 13 * * @return {Boolean} */ hasTime: function() { return(this.tH !== -1); }, /** * does current data contain a minimum timezone i.e. -1 || +1 || z * * @return {Boolean} */ hasTimeZone: function() { return(this.tzH !== -1); } }; modules.ISODate.prototype.constructor = modules.ISODate; return modules; } (Modules || {}));