Revision: 50768
Updated Code
at September 17, 2011 04:18 by wizard04
Updated Code
/* ISO 8601 Date conversions v2.0 * * This work is licensed under a Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/ * * Author: Andy Harrison, http://dragonzreef.com/ * Date: 16 September 2011 */ //formats the Date into a string according to the Internet profile of ISO 8601 described in RFC 3339 //see http://tools.ietf.org/html/rfc3339 //time zone is always UTC if(!Date.prototype.toISOString) Date.prototype.toISOString = function(){ return this.format("%Y-%M-%DT%I:%N:%S.%ZZ", true); } //creates a Date object from a basic ISO 8601 formatted string //expanded years are not supported //see http://tools.ietf.org/html/rfc3339#section-5.6 // http://en.wikipedia.org/wiki/Iso8601 Date.fromISO = function(isoStr) { var rxpCalendarDate = "(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?"; var rxpWeekDate = "(\\d{4})(-?)[Ww](\\d{2})(?:\\2(\\d))?"; var rxpOrdinalDate = "(\\d{4})-?(\\d{3})"; var rxpTime = "(\\d{2})(?:(:?)(\\d{2})(?:\\2(\\d{2}))?)?(?:[.,](\\d+))?"; var rxpOffset = "(?:([Zz])|([+-])(\\d{2})(?::?(\\d{2}))?)"; var rxpFullDate = "^(?:(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?|(\\d{4})(-?)[Ww](\\d{2})(?:\\6(\\d))?|(\\d{4})-?(\\d{3}))(?=[Tt]|$)" var rxpFullTime = rxpTime+rxpOffset+"?$"; if(!( RegExp(rxpFullDate+"$").test(isoStr) || RegExp("^"+rxpFullTime).test(isoStr) || (RegExp(rxpFullDate+"[Tt].*").test(isoStr) && RegExp("^[^Tt]+[Tt]"+rxpFullTime).test(isoStr)) )) return null; //not a supported ISO 8601 string var now = new Date(); var parts = {year:now.getFullYear(), month:now.getMonth(), day:now.getDate(), hour:0, minute:0, second:0, fraction:0}; //default is midnight this morning, local time var rxp; var isoDate = RegExp(rxpFullDate).exec(isoStr); if(isoDate) //string includes a date { try{ isoDate = isoDate[0]; if((rxp = RegExp("^"+rxpCalendarDate+"$")).exec(isoDate)) //calendar date { isoDate.replace(rxp, function(match, y, dash, m, d){ if(m!="" && (m<1 || m>12)) throw new RangeError("Month is out of range"); if(d!="" && (d<1 || d>31)) throw new RangeError("Day is out of range"); parts.year = y; parts.month = m=="" ? 0 : m-1; parts.day = d=="" ? 1 : d; if(parts.day > Date.daysInMonth(parts.year, parts.month)) throw new RangeError("Day is out of range"); }); } else if((rxp = RegExp("^"+rxpWeekDate+"$")).exec(isoDate)) //week date { isoDate.replace(rxp, function(match, y, dash, w, d){ if(w<1 || w>53) throw new RangeError("Week number is out of range"); if(d!="" && (d<1 || d>7)) throw new RangeError("Weekday number is out of range"); var jan4th = new Date(y, 0, 4); var dayOfJan4th = (jan4th.getDay()+6)%7; //0-6 == Mon-Sun var firstMonday = new Date(jan4th.valueOf() - dayOfJan4th*86400000); if(w == 53) { var mondayAfter52Weeks = (new Date(firstMonday.valueOf() + 52*7*86400000)).getDate(); //if the 53rd week is actually the first week of next year (i.e., it includes Jan 4th), throw range error if(!(mondayAfter52Weeks > 4 && mondayAfter52Weeks < 29)) throw new RangeError("Week number is out of range"); } var weekday = d=="" ? 0 : d-1; //0-6 == Mon-Sun var date = new Date(firstMonday.valueOf() + weekday*86400000 + (w-1)*7*86400000); parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); }); } else //ordinal date { isoDate.replace(RegExp("^"+rxpOrdinalDate+"$"), function(match, y, d){ if(d > (Date.isLeapYear(y)?366:365)) throw new RangeError("Day number is out of range"); parts.year = y; var date = new Date((new Date(y, 0, 1)).valueOf() + (d-1)*86400000); parts.month = date.getMonth(); parts.day = date.getDate(); }); } }catch(err){ return null; //date string is invalid } } var isoTime = RegExp("(?:^|[Tt])"+rxpFullTime).exec(isoStr); if(isoTime) //string includes a time { try{ isoTime = isoTime[0]; if(isoTime[0].toUpperCase() == "T") isoTime = isoTime.slice(1); if(RegExp("^"+rxpTime+"$").exec(isoTime)) //if there is no time zone designator { //use local time var date = new Date(parts.year, parts.month, parts.day); //add hours, minutes, and seconds to date isoTime.replace(RegExp("^"+rxpTime+"$"), function(match, h, colon, m, s, f){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); date = new Date(val); }); } else //there is a time zone designator { //use UTC time as base var date = new Date(Date.UTC(parts.year, parts.month, parts.day)); //add hours, minutes, seconds, and offset to date isoTime.replace(RegExp("^"+rxpTime+rxpOffset+"$"), function(match, h, colon, m, s, f, z, sign, oh, om){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); if(oh!="" && oh>23) throw new RangeError("Offset hour is out of range"); if(om!="" && om>59) throw new RangeError("Offset minute is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); if(!z) //if there is an offset from UTC time { //adjust time according to offset (i.e., convert to UTC time) sign = sign=="-" ? 1 : -1; val += sign*oh*3600000; if(om != "") val += sign*om*60000; } date = new Date(val); }); } parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); parts.hour = date.getHours(); parts.minute = date.getMinutes(); parts.second = date.getSeconds(); parts.fraction = date.getMilliseconds(); }catch(err){ return null; //time string is invalid } } return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.fraction); }
Revision: 50767
Updated Code
at September 17, 2011 04:16 by wizard04
Updated Code
/* ISO 8601 Date conversions v2.0 * * This work is licensed under a Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/ * * Author: Andy Harrison, http://dragonzreef.com/ * Date: 16 September 2011 */ //formats the Date into a string according to the Internet profile of ISO 8601 described in RFC 3339 //see http://tools.ietf.org/html/rfc3339 //time zone is always UTC if(!Date.prototype.toISOString) Date.prototype.toISOString = function(){ return this.format("%Y-%M-%DT%I:%N:%S.%ZZ", true); } //creates a Date object from a basic ISO 8601 formatted string //expanded years, durations, and intervals are not supported //see http://tools.ietf.org/html/rfc3339#section-5.6 // http://en.wikipedia.org/wiki/Iso8601 Date.fromISO = function(isoStr) { var rxpCalendarDate = "(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?"; var rxpWeekDate = "(\\d{4})(-?)[Ww](\\d{2})(?:\\2(\\d))?"; var rxpOrdinalDate = "(\\d{4})-?(\\d{3})"; var rxpTime = "(\\d{2})(?:(:?)(\\d{2})(?:\\2(\\d{2}))?)?(?:[.,](\\d+))?"; var rxpOffset = "(?:([Zz])|([+-])(\\d{2})(?::?(\\d{2}))?)"; var rxpFullDate = "^(?:(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?|(\\d{4})(-?)[Ww](\\d{2})(?:\\6(\\d))?|(\\d{4})-?(\\d{3}))(?=[Tt]|$)" var rxpFullTime = rxpTime+rxpOffset+"?$"; if(!( RegExp(rxpFullDate+"$").test(isoStr) || RegExp("^"+rxpFullTime).test(isoStr) || (RegExp(rxpFullDate+"[Tt].*").test(isoStr) && RegExp("^[^Tt]+[Tt]"+rxpFullTime).test(isoStr)) )) return null; //not a supported ISO 8601 string var now = new Date(); var parts = {year:now.getFullYear(), month:now.getMonth(), day:now.getDate(), hour:0, minute:0, second:0, fraction:0}; //default is midnight this morning, local time var rxp; var isoDate = RegExp(rxpFullDate).exec(isoStr); if(isoDate) //string includes a date { try{ isoDate = isoDate[0]; if((rxp = RegExp("^"+rxpCalendarDate+"$")).exec(isoDate)) //calendar date { isoDate.replace(rxp, function(match, y, dash, m, d){ if(m!="" && (m<1 || m>12)) throw new RangeError("Month is out of range"); if(d!="" && (d<1 || d>31)) throw new RangeError("Day is out of range"); parts.year = y; parts.month = m=="" ? 0 : m-1; parts.day = d=="" ? 1 : d; if(parts.day > Date.daysInMonth(parts.year, parts.month)) throw new RangeError("Day is out of range"); }); } else if((rxp = RegExp("^"+rxpWeekDate+"$")).exec(isoDate)) //week date { isoDate.replace(rxp, function(match, y, dash, w, d){ if(w<1 || w>53) throw new RangeError("Week number is out of range"); if(d!="" && (d<1 || d>7)) throw new RangeError("Weekday number is out of range"); var jan4th = new Date(y, 0, 4); var dayOfJan4th = (jan4th.getDay()+6)%7; //0-6 == Mon-Sun var firstMonday = new Date(jan4th.valueOf() - dayOfJan4th*86400000); if(w == 53) { var mondayAfter52Weeks = (new Date(firstMonday.valueOf() + 52*7*86400000)).getDate(); //if the 53rd week is actually the first week of next year (i.e., it includes Jan 4th), throw range error if(!(mondayAfter52Weeks > 4 && mondayAfter52Weeks < 29)) throw new RangeError("Week number is out of range"); } var weekday = d=="" ? 0 : d-1; //0-6 == Mon-Sun var date = new Date(firstMonday.valueOf() + weekday*86400000 + (w-1)*7*86400000); parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); }); } else //ordinal date { isoDate.replace(RegExp("^"+rxpOrdinalDate+"$"), function(match, y, d){ if(d > (Date.isLeapYear(y)?366:365)) throw new RangeError("Day number is out of range"); parts.year = y; var date = new Date((new Date(y, 0, 1)).valueOf() + (d-1)*86400000); parts.month = date.getMonth(); parts.day = date.getDate(); }); } }catch(err){ return null; //date string is invalid } } var isoTime = RegExp("(?:^|[Tt])"+rxpFullTime).exec(isoStr); if(isoTime) //string includes a time { try{ isoTime = isoTime[0]; if(isoTime[0].toUpperCase() == "T") isoTime = isoTime.slice(1); if(RegExp("^"+rxpTime+"$").exec(isoTime)) //if there is no time zone designator { //use local time var date = new Date(parts.year, parts.month, parts.day); //add hours, minutes, and seconds to date isoTime.replace(RegExp("^"+rxpTime+"$"), function(match, h, colon, m, s, f){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); date = new Date(val); }); } else //there is a time zone designator { //use UTC time as base var date = new Date(Date.UTC(parts.year, parts.month, parts.day)); //add hours, minutes, seconds, and offset to date isoTime.replace(RegExp("^"+rxpTime+rxpOffset+"$"), function(match, h, colon, m, s, f, z, sign, oh, om){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); if(oh!="" && oh>23) throw new RangeError("Offset hour is out of range"); if(om!="" && om>59) throw new RangeError("Offset minute is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); if(!z) //if there is an offset from UTC time { //adjust time according to offset (i.e., convert to UTC time) sign = sign=="-" ? 1 : -1; val += sign*oh*3600000; if(om != "") val += sign*om*60000; } date = new Date(val); }); } parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); parts.hour = date.getHours(); parts.minute = date.getMinutes(); parts.second = date.getSeconds(); parts.fraction = date.getMilliseconds(); }catch(err){ return null; //time string is invalid } } return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.fraction); }
Revision: 50766
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at September 2, 2011 00:28 by wizard04
Initial Code
//formats the Date into a string according to the Internet profile of ISO 8601 described in RFC 3339 //see http://tools.ietf.org/html/rfc3339 Date.prototype.toISO = function(useZulu, useFraction) { if(!useZulu) return this.format("%Y-%M-%DT%I:%N:%S"+(useFraction?".%Z":"")+"%e%F:%G"); //if the time is in UTC, uses "Z" for the zone designator instead of "+00:00" (both are correct) //however, this format does not allow times to be sorted alphabetically return this.getTimezoneOffset()==0 ? this.format("%Y-%M-%DT%I:%N:%S"+(useFraction?".%Z":"")+"Z") : this.format("%Y-%M-%DT%I:%N:%S"+(useFraction?".%Z":"")+"%e%F:%G"); } //creates a Date object from a basic ISO 8601 formatted string //expanded years, durations, and intervals are not supported //see http://tools.ietf.org/html/rfc3339#section-5.6 // http://en.wikipedia.org/wiki/Iso8601 Date.fromISO = function(isoStr) { var rxpCalendarDate = "(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?"; var rxpWeekDate = "(\\d{4})(-?)[Ww](\\d{2})(?:\\2(\\d))?"; var rxpOrdinalDate = "(\\d{4})-?(\\d{3})"; var rxpTime = "(\\d{2})(?:(:?)(\\d{2})(?:\\2(\\d{2}))?)?(?:[.,](\\d+))?"; var rxpOffset = "(?:([Zz])|([+-])(\\d{2})(?::?(\\d{2}))?)"; var rxpFullDate = "^(?:(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?|(\\d{4})(-?)[Ww](\\d{2})(?:\\6(\\d))?|(\\d{4})-?(\\d{3}))(?=[Tt]|$)" var rxpFullTime = rxpTime+rxpOffset+"?$"; if(!( RegExp(rxpFullDate+"$").test(isoStr) || RegExp("^"+rxpFullTime).test(isoStr) || (RegExp(rxpFullDate+"[Tt].*").test(isoStr) && RegExp("^[^Tt]+[Tt]"+rxpFullTime).test(isoStr)) )) return null; //not a supported ISO 8601 string var now = new Date(); var parts = {year:now.getFullYear(), month:now.getMonth(), day:now.getDate(), hour:0, minute:0, second:0, fraction:0}; //default is midnight this morning, local time var rxp; var isoDate = RegExp(rxpFullDate).exec(isoStr); if(isoDate) //string includes a date { try{ isoDate = isoDate[0]; if((rxp = RegExp("^"+rxpCalendarDate+"$")).exec(isoDate)) //calendar date { isoDate.replace(rxp, function(match, y, dash, m, d){ if(m!="" && (m<1 || m>12)) throw new RangeError("Month is out of range"); if(d!="" && (d<1 || d>31)) throw new RangeError("Day is out of range"); parts.year = y; parts.month = m=="" ? 0 : m-1; parts.day = d=="" ? 1 : d; if(parts.day > Date.daysInMonth(parts.year, parts.month)) throw new RangeError("Day is out of range"); }); } else if((rxp = RegExp("^"+rxpWeekDate+"$")).exec(isoDate)) //week date { isoDate.replace(rxp, function(match, y, dash, w, d){ if(w<1 || w>53) throw new RangeError("Week number is out of range"); if(d!="" && (d<1 || d>7)) throw new RangeError("Weekday number is out of range"); var jan4th = new Date(y, 0, 4); var dayOfJan4th = (jan4th.getDay()+6)%7; //0-6 == Mon-Sun var firstMonday = new Date(jan4th.valueOf() - dayOfJan4th*86400000); if(w == 53) { var mondayAfter52Weeks = (new Date(firstMonday.valueOf() + 52*7*86400000)).getDate(); //if the 53rd week is actually the first week of next year (i.e., it includes Jan 4th), throw range error if(!(mondayAfter52Weeks > 4 && mondayAfter52Weeks < 29)) throw new RangeError("Week number is out of range"); } var weekday = d=="" ? 0 : d-1; //0-6 == Mon-Sun var date = new Date(firstMonday.valueOf() + weekday*86400000 + (w-1)*7*86400000); parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); }); } else //ordinal date { isoDate.replace(RegExp("^"+rxpOrdinalDate+"$"), function(match, y, d){ if(d > (Date.isLeapYear(y)?366:365)) throw new RangeError("Day number is out of range"); parts.year = y; var date = new Date((new Date(y, 0, 1)).valueOf() + (d-1)*86400000); parts.month = date.getMonth(); parts.day = date.getDate(); }); } }catch(err){ return null; //date string is invalid } } var isoTime = RegExp("(?:^|[Tt])"+rxpFullTime).exec(isoStr); if(isoTime) //string includes a time { try{ isoTime = isoTime[0]; if(isoTime[0].toUpperCase() == "T") isoTime = isoTime.slice(1); if(RegExp("^"+rxpTime+"$").exec(isoTime)) //if there is no time zone designator { //use local time var date = new Date(parts.year, parts.month, parts.day); //add hours, minutes, and seconds to date isoTime.replace(RegExp("^"+rxpTime+"$"), function(match, h, colon, m, s, f){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); date = new Date(val); }); } else //there is a time zone designator { //use UTC time as base var date = new Date(Date.UTC(parts.year, parts.month, parts.day)); //add hours, minutes, seconds, and offset to date isoTime.replace(RegExp("^"+rxpTime+rxpOffset+"$"), function(match, h, colon, m, s, f, z, sign, oh, om){ if(h>24) throw new RangeError("Hour is out of range"); if(m!="" && m>59) throw new RangeError("Minute is out of range"); if(s!="" && s>60) throw new RangeError("Second is out of range"); if(oh!="" && oh>23) throw new RangeError("Offset hour is out of range"); if(om!="" && om>59) throw new RangeError("Offset minute is out of range"); var val = date.valueOf(); val += h*3600000; if(m) val += m*60000; if(s) val += s*1000; if(f) val += 1000*("."+f.substr(0,3)); if(!z) //if there is an offset from UTC time { //adjust time according to offset (i.e., convert to UTC time) sign = sign=="-" ? 1 : -1; val += sign*oh*3600000; if(om != "") val += sign*om*60000; } date = new Date(val); }); } parts.year = date.getFullYear(); parts.month = date.getMonth(); parts.day = date.getDate(); parts.hour = date.getHours(); parts.minute = date.getMinutes(); parts.second = date.getSeconds(); parts.fraction = date.getMilliseconds(); }catch(err){ return null; //time string is invalid } } return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.fraction); }
Initial URL
Initial Description
This requires my [date formatting script](http://snipplr.com/view/54806/javascript-date-formatting/). (date).toISO() converts the Date object to an ISO 8601 string Date.fromISO() converts an ISO 8601 string to a Date object
Initial Title
ISO 8601 date conversion
Initial Tags
javascript, date
Initial Language
JavaScript