ISO 8601 date conversion


/ Published in: JavaScript
Save to your folder(s)

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


Copy this code and paste it in your HTML
  1. /* ISO 8601 Date conversions v2.0
  2.  *
  3.  * This work is licensed under a Creative Commons Attribution 3.0 Unported License
  4.  * http://creativecommons.org/licenses/by/3.0/
  5.  *
  6.  * Author: Andy Harrison, http://dragonzreef.com/
  7.  * Date: 16 September 2011
  8.  */
  9.  
  10. //formats the Date into a string according to the Internet profile of ISO 8601 described in RFC 3339
  11. //see http://tools.ietf.org/html/rfc3339
  12. //time zone is always UTC
  13. if(!Date.prototype.toISOString) Date.prototype.toISOString = function(){ return this.format("%Y-%M-%DT%I:%N:%S.%ZZ", true); }
  14.  
  15. //creates a Date object from a basic ISO 8601 formatted string
  16. //expanded years are not supported
  17. //see http://tools.ietf.org/html/rfc3339#section-5.6
  18. // http://en.wikipedia.org/wiki/Iso8601
  19. Date.fromISO = function(isoStr)
  20. {
  21. var rxpCalendarDate = "(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?";
  22. var rxpWeekDate = "(\\d{4})(-?)[Ww](\\d{2})(?:\\2(\\d))?";
  23. var rxpOrdinalDate = "(\\d{4})-?(\\d{3})";
  24. var rxpTime = "(\\d{2})(?:(:?)(\\d{2})(?:\\2(\\d{2}))?)?(?:[.,](\\d+))?";
  25. var rxpOffset = "(?:([Zz])|([+-])(\\d{2})(?::?(\\d{2}))?)";
  26. var rxpFullDate = "^(?:(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?|(\\d{4})(-?)[Ww](\\d{2})(?:\\6(\\d))?|(\\d{4})-?(\\d{3}))(?=[Tt]|$)"
  27. var rxpFullTime = rxpTime+rxpOffset+"?$";
  28.  
  29. if(!( RegExp(rxpFullDate+"$").test(isoStr) ||
  30. RegExp("^"+rxpFullTime).test(isoStr) ||
  31. (RegExp(rxpFullDate+"[Tt].*").test(isoStr) && RegExp("^[^Tt]+[Tt]"+rxpFullTime).test(isoStr)) )) return null; //not a supported ISO 8601 string
  32.  
  33. var now = new Date();
  34. 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
  35. var rxp;
  36.  
  37. var isoDate = RegExp(rxpFullDate).exec(isoStr);
  38. if(isoDate) //string includes a date
  39. {
  40. try{
  41. isoDate = isoDate[0];
  42. if((rxp = RegExp("^"+rxpCalendarDate+"$")).exec(isoDate)) //calendar date
  43. {
  44. isoDate.replace(rxp, function(match, y, dash, m, d){
  45. if(m!="" && (m<1 || m>12)) throw new RangeError("Month is out of range");
  46. if(d!="" && (d<1 || d>31)) throw new RangeError("Day is out of range");
  47.  
  48. parts.year = y;
  49. parts.month = m=="" ? 0 : m-1;
  50. parts.day = d=="" ? 1 : d;
  51.  
  52. if(parts.day > Date.daysInMonth(parts.year, parts.month)) throw new RangeError("Day is out of range");
  53. });
  54. }
  55. else if((rxp = RegExp("^"+rxpWeekDate+"$")).exec(isoDate)) //week date
  56. {
  57. isoDate.replace(rxp, function(match, y, dash, w, d){
  58. if(w<1 || w>53) throw new RangeError("Week number is out of range");
  59. if(d!="" && (d<1 || d>7)) throw new RangeError("Weekday number is out of range");
  60.  
  61. var jan4th = new Date(y, 0, 4);
  62. var dayOfJan4th = (jan4th.getDay()+6)%7; //0-6 == Mon-Sun
  63. var firstMonday = new Date(jan4th.valueOf() - dayOfJan4th*86400000);
  64. if(w == 53)
  65. {
  66. var mondayAfter52Weeks = (new Date(firstMonday.valueOf() + 52*7*86400000)).getDate();
  67. //if the 53rd week is actually the first week of next year (i.e., it includes Jan 4th), throw range error
  68. if(!(mondayAfter52Weeks > 4 && mondayAfter52Weeks < 29)) throw new RangeError("Week number is out of range");
  69. }
  70. var weekday = d=="" ? 0 : d-1; //0-6 == Mon-Sun
  71. var date = new Date(firstMonday.valueOf() + weekday*86400000 + (w-1)*7*86400000);
  72. parts.year = date.getFullYear();
  73. parts.month = date.getMonth();
  74. parts.day = date.getDate();
  75. });
  76. }
  77. else //ordinal date
  78. {
  79. isoDate.replace(RegExp("^"+rxpOrdinalDate+"$"), function(match, y, d){
  80. if(d > (Date.isLeapYear(y)?366:365)) throw new RangeError("Day number is out of range");
  81.  
  82. parts.year = y;
  83. var date = new Date((new Date(y, 0, 1)).valueOf() + (d-1)*86400000);
  84. parts.month = date.getMonth();
  85. parts.day = date.getDate();
  86. });
  87. }
  88. }catch(err){
  89. return null; //date string is invalid
  90. }
  91. }
  92.  
  93. var isoTime = RegExp("(?:^|[Tt])"+rxpFullTime).exec(isoStr);
  94. if(isoTime) //string includes a time
  95. {
  96. try{
  97. isoTime = isoTime[0];
  98. if(isoTime[0].toUpperCase() == "T") isoTime = isoTime.slice(1);
  99.  
  100. if(RegExp("^"+rxpTime+"$").exec(isoTime)) //if there is no time zone designator
  101. {
  102. //use local time
  103. var date = new Date(parts.year, parts.month, parts.day);
  104. //add hours, minutes, and seconds to date
  105. isoTime.replace(RegExp("^"+rxpTime+"$"), function(match, h, colon, m, s, f){
  106. if(h>24) throw new RangeError("Hour is out of range");
  107. if(m!="" && m>59) throw new RangeError("Minute is out of range");
  108. if(s!="" && s>60) throw new RangeError("Second is out of range");
  109.  
  110. var val = date.valueOf();
  111. val += h*3600000;
  112. if(m) val += m*60000;
  113. if(s) val += s*1000;
  114. if(f) val += 1000*("."+f.substr(0,3));
  115. date = new Date(val);
  116. });
  117. }
  118. else //there is a time zone designator
  119. {
  120. //use UTC time as base
  121. var date = new Date(Date.UTC(parts.year, parts.month, parts.day));
  122. //add hours, minutes, seconds, and offset to date
  123. isoTime.replace(RegExp("^"+rxpTime+rxpOffset+"$"), function(match, h, colon, m, s, f, z, sign, oh, om){
  124. if(h>24) throw new RangeError("Hour is out of range");
  125. if(m!="" && m>59) throw new RangeError("Minute is out of range");
  126. if(s!="" && s>60) throw new RangeError("Second is out of range");
  127. if(oh!="" && oh>23) throw new RangeError("Offset hour is out of range");
  128. if(om!="" && om>59) throw new RangeError("Offset minute is out of range");
  129.  
  130. var val = date.valueOf();
  131. val += h*3600000;
  132. if(m) val += m*60000;
  133. if(s) val += s*1000;
  134. if(f) val += 1000*("."+f.substr(0,3));
  135.  
  136. if(!z) //if there is an offset from UTC time
  137. {
  138. //adjust time according to offset (i.e., convert to UTC time)
  139. sign = sign=="-" ? 1 : -1;
  140. val += sign*oh*3600000;
  141. if(om != "") val += sign*om*60000;
  142. }
  143. date = new Date(val);
  144. });
  145. }
  146.  
  147. parts.year = date.getFullYear();
  148. parts.month = date.getMonth();
  149. parts.day = date.getDate();
  150. parts.hour = date.getHours();
  151. parts.minute = date.getMinutes();
  152. parts.second = date.getSeconds();
  153. parts.fraction = date.getMilliseconds();
  154. }catch(err){
  155. return null; //time string is invalid
  156. }
  157. }
  158.  
  159. return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.fraction);
  160. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.