PageRenderTime 68ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/ajax/scripts/date-time.js

http://showslow.googlecode.com/
JavaScript | 452 lines | 290 code | 45 blank | 117 comment | 33 complexity | 6763f09e5767174cbf58d95071004a03 MD5 | raw file
  1. /**
  2. * @fileOverview A collection of date/time utility functions
  3. * @name SimileAjax.DateTime
  4. */
  5. SimileAjax.DateTime = new Object();
  6. SimileAjax.DateTime.MILLISECOND = 0;
  7. SimileAjax.DateTime.SECOND = 1;
  8. SimileAjax.DateTime.MINUTE = 2;
  9. SimileAjax.DateTime.HOUR = 3;
  10. SimileAjax.DateTime.DAY = 4;
  11. SimileAjax.DateTime.WEEK = 5;
  12. SimileAjax.DateTime.MONTH = 6;
  13. SimileAjax.DateTime.YEAR = 7;
  14. SimileAjax.DateTime.DECADE = 8;
  15. SimileAjax.DateTime.CENTURY = 9;
  16. SimileAjax.DateTime.MILLENNIUM = 10;
  17. SimileAjax.DateTime.EPOCH = -1;
  18. SimileAjax.DateTime.ERA = -2;
  19. /**
  20. * An array of unit lengths, expressed in milliseconds, of various lengths of
  21. * time. The array indices are predefined and stored as properties of the
  22. * SimileAjax.DateTime object, e.g. SimileAjax.DateTime.YEAR.
  23. * @type Array
  24. */
  25. SimileAjax.DateTime.gregorianUnitLengths = [];
  26. (function() {
  27. var d = SimileAjax.DateTime;
  28. var a = d.gregorianUnitLengths;
  29. a[d.MILLISECOND] = 1;
  30. a[d.SECOND] = 1000;
  31. a[d.MINUTE] = a[d.SECOND] * 60;
  32. a[d.HOUR] = a[d.MINUTE] * 60;
  33. a[d.DAY] = a[d.HOUR] * 24;
  34. a[d.WEEK] = a[d.DAY] * 7;
  35. a[d.MONTH] = a[d.DAY] * 31;
  36. a[d.YEAR] = a[d.DAY] * 365;
  37. a[d.DECADE] = a[d.YEAR] * 10;
  38. a[d.CENTURY] = a[d.YEAR] * 100;
  39. a[d.MILLENNIUM] = a[d.YEAR] * 1000;
  40. })();
  41. SimileAjax.DateTime._dateRegexp = new RegExp(
  42. "^(-?)([0-9]{4})(" + [
  43. "(-?([0-9]{2})(-?([0-9]{2}))?)", // -month-dayOfMonth
  44. "(-?([0-9]{3}))", // -dayOfYear
  45. "(-?W([0-9]{2})(-?([1-7]))?)" // -Wweek-dayOfWeek
  46. ].join("|") + ")?$"
  47. );
  48. SimileAjax.DateTime._timezoneRegexp = new RegExp(
  49. "Z|(([-+])([0-9]{2})(:?([0-9]{2}))?)$"
  50. );
  51. SimileAjax.DateTime._timeRegexp = new RegExp(
  52. "^([0-9]{2})(:?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?)?$"
  53. );
  54. /**
  55. * Takes a date object and a string containing an ISO 8601 date and sets the
  56. * the date using information parsed from the string. Note that this method
  57. * does not parse any time information.
  58. *
  59. * @param {Date} dateObject the date object to modify
  60. * @param {String} string an ISO 8601 string to parse
  61. * @return {Date} the modified date object
  62. */
  63. SimileAjax.DateTime.setIso8601Date = function(dateObject, string) {
  64. /*
  65. * This function has been adapted from dojo.date, v.0.3.0
  66. * http://dojotoolkit.org/.
  67. */
  68. var d = string.match(SimileAjax.DateTime._dateRegexp);
  69. if(!d) {
  70. throw new Error("Invalid date string: " + string);
  71. }
  72. var sign = (d[1] == "-") ? -1 : 1; // BC or AD
  73. var year = sign * d[2];
  74. var month = d[5];
  75. var date = d[7];
  76. var dayofyear = d[9];
  77. var week = d[11];
  78. var dayofweek = (d[13]) ? d[13] : 1;
  79. dateObject.setUTCFullYear(year);
  80. if (dayofyear) {
  81. dateObject.setUTCMonth(0);
  82. dateObject.setUTCDate(Number(dayofyear));
  83. } else if (week) {
  84. dateObject.setUTCMonth(0);
  85. dateObject.setUTCDate(1);
  86. var gd = dateObject.getUTCDay();
  87. var day = (gd) ? gd : 7;
  88. var offset = Number(dayofweek) + (7 * Number(week));
  89. if (day <= 4) {
  90. dateObject.setUTCDate(offset + 1 - day);
  91. } else {
  92. dateObject.setUTCDate(offset + 8 - day);
  93. }
  94. } else {
  95. if (month) {
  96. dateObject.setUTCDate(1);
  97. dateObject.setUTCMonth(month - 1);
  98. }
  99. if (date) {
  100. dateObject.setUTCDate(date);
  101. }
  102. }
  103. return dateObject;
  104. };
  105. /**
  106. * Takes a date object and a string containing an ISO 8601 time and sets the
  107. * the time using information parsed from the string. Note that this method
  108. * does not parse any date information.
  109. *
  110. * @param {Date} dateObject the date object to modify
  111. * @param {String} string an ISO 8601 string to parse
  112. * @return {Date} the modified date object
  113. */
  114. SimileAjax.DateTime.setIso8601Time = function (dateObject, string) {
  115. /*
  116. * This function has been adapted from dojo.date, v.0.3.0
  117. * http://dojotoolkit.org/.
  118. */
  119. var d = string.match(SimileAjax.DateTime._timeRegexp);
  120. if(!d) {
  121. SimileAjax.Debug.warn("Invalid time string: " + string);
  122. return false;
  123. }
  124. var hours = d[1];
  125. var mins = Number((d[3]) ? d[3] : 0);
  126. var secs = (d[5]) ? d[5] : 0;
  127. var ms = d[7] ? (Number("0." + d[7]) * 1000) : 0;
  128. dateObject.setUTCHours(hours);
  129. dateObject.setUTCMinutes(mins);
  130. dateObject.setUTCSeconds(secs);
  131. dateObject.setUTCMilliseconds(ms);
  132. return dateObject;
  133. };
  134. /**
  135. * The timezone offset in minutes in the user's browser.
  136. * @type Number
  137. */
  138. SimileAjax.DateTime.timezoneOffset = new Date().getTimezoneOffset();
  139. /**
  140. * Takes a date object and a string containing an ISO 8601 date and time and
  141. * sets the date object using information parsed from the string.
  142. *
  143. * @param {Date} dateObject the date object to modify
  144. * @param {String} string an ISO 8601 string to parse
  145. * @return {Date} the modified date object
  146. */
  147. SimileAjax.DateTime.setIso8601 = function (dateObject, string){
  148. /*
  149. * This function has been adapted from dojo.date, v.0.3.0
  150. * http://dojotoolkit.org/.
  151. */
  152. var offset = null;
  153. var comps = (string.indexOf("T") == -1) ? string.split(" ") : string.split("T");
  154. SimileAjax.DateTime.setIso8601Date(dateObject, comps[0]);
  155. if (comps.length == 2) {
  156. // first strip timezone info from the end
  157. var d = comps[1].match(SimileAjax.DateTime._timezoneRegexp);
  158. if (d) {
  159. if (d[0] == 'Z') {
  160. offset = 0;
  161. } else {
  162. offset = (Number(d[3]) * 60) + Number(d[5]);
  163. offset *= ((d[2] == '-') ? 1 : -1);
  164. }
  165. comps[1] = comps[1].substr(0, comps[1].length - d[0].length);
  166. }
  167. SimileAjax.DateTime.setIso8601Time(dateObject, comps[1]);
  168. }
  169. if (offset == null) {
  170. offset = dateObject.getTimezoneOffset(); // local time zone if no tz info
  171. }
  172. dateObject.setTime(dateObject.getTime() + offset * 60000);
  173. return dateObject;
  174. };
  175. /**
  176. * Takes a string containing an ISO 8601 date and returns a newly instantiated
  177. * date object with the parsed date and time information from the string.
  178. *
  179. * @param {String} string an ISO 8601 string to parse
  180. * @return {Date} a new date object created from the string
  181. */
  182. SimileAjax.DateTime.parseIso8601DateTime = function (string) {
  183. try {
  184. return SimileAjax.DateTime.setIso8601(new Date(0), string);
  185. } catch (e) {
  186. return null;
  187. }
  188. };
  189. /**
  190. * Takes a string containing a Gregorian date and time and returns a newly
  191. * instantiated date object with the parsed date and time information from the
  192. * string. If the param is actually an instance of Date instead of a string,
  193. * simply returns the given date instead.
  194. *
  195. * @param {Object} o an object, to either return or parse as a string
  196. * @return {Date} the date object
  197. */
  198. SimileAjax.DateTime.parseGregorianDateTime = function(o) {
  199. if (o == null) {
  200. return null;
  201. } else if (o instanceof Date) {
  202. return o;
  203. }
  204. var s = o.toString();
  205. if (s.length > 0 && s.length < 8) {
  206. var space = s.indexOf(" ");
  207. if (space > 0) {
  208. var year = parseInt(s.substr(0, space));
  209. var suffix = s.substr(space + 1);
  210. if (suffix.toLowerCase() == "bc") {
  211. year = 1 - year;
  212. }
  213. } else {
  214. var year = parseInt(s);
  215. }
  216. var d = new Date(0);
  217. d.setUTCFullYear(year);
  218. return d;
  219. }
  220. try {
  221. return new Date(Date.parse(s));
  222. } catch (e) {
  223. return null;
  224. }
  225. };
  226. /**
  227. * Rounds date objects down to the nearest interval or multiple of an interval.
  228. * This method modifies the given date object, converting it to the given
  229. * timezone if specified.
  230. *
  231. * @param {Date} date the date object to round
  232. * @param {Number} intervalUnit a constant, integer index specifying an
  233. * interval, e.g. SimileAjax.DateTime.HOUR
  234. * @param {Number} timeZone a timezone shift, given in hours
  235. * @param {Number} multiple a multiple of the interval to round by
  236. * @param {Number} firstDayOfWeek an integer specifying the first day of the
  237. * week, 0 corresponds to Sunday, 1 to Monday, etc.
  238. */
  239. SimileAjax.DateTime.roundDownToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
  240. var timeShift = timeZone *
  241. SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
  242. var date2 = new Date(date.getTime() + timeShift);
  243. var clearInDay = function(d) {
  244. d.setUTCMilliseconds(0);
  245. d.setUTCSeconds(0);
  246. d.setUTCMinutes(0);
  247. d.setUTCHours(0);
  248. };
  249. var clearInYear = function(d) {
  250. clearInDay(d);
  251. d.setUTCDate(1);
  252. d.setUTCMonth(0);
  253. };
  254. switch(intervalUnit) {
  255. case SimileAjax.DateTime.MILLISECOND:
  256. var x = date2.getUTCMilliseconds();
  257. date2.setUTCMilliseconds(x - (x % multiple));
  258. break;
  259. case SimileAjax.DateTime.SECOND:
  260. date2.setUTCMilliseconds(0);
  261. var x = date2.getUTCSeconds();
  262. date2.setUTCSeconds(x - (x % multiple));
  263. break;
  264. case SimileAjax.DateTime.MINUTE:
  265. date2.setUTCMilliseconds(0);
  266. date2.setUTCSeconds(0);
  267. var x = date2.getUTCMinutes();
  268. date2.setTime(date2.getTime() -
  269. (x % multiple) * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
  270. break;
  271. case SimileAjax.DateTime.HOUR:
  272. date2.setUTCMilliseconds(0);
  273. date2.setUTCSeconds(0);
  274. date2.setUTCMinutes(0);
  275. var x = date2.getUTCHours();
  276. date2.setUTCHours(x - (x % multiple));
  277. break;
  278. case SimileAjax.DateTime.DAY:
  279. clearInDay(date2);
  280. break;
  281. case SimileAjax.DateTime.WEEK:
  282. clearInDay(date2);
  283. var d = (date2.getUTCDay() + 7 - firstDayOfWeek) % 7;
  284. date2.setTime(date2.getTime() -
  285. d * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.DAY]);
  286. break;
  287. case SimileAjax.DateTime.MONTH:
  288. clearInDay(date2);
  289. date2.setUTCDate(1);
  290. var x = date2.getUTCMonth();
  291. date2.setUTCMonth(x - (x % multiple));
  292. break;
  293. case SimileAjax.DateTime.YEAR:
  294. clearInYear(date2);
  295. var x = date2.getUTCFullYear();
  296. date2.setUTCFullYear(x - (x % multiple));
  297. break;
  298. case SimileAjax.DateTime.DECADE:
  299. clearInYear(date2);
  300. date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 10) * 10);
  301. break;
  302. case SimileAjax.DateTime.CENTURY:
  303. clearInYear(date2);
  304. date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 100) * 100);
  305. break;
  306. case SimileAjax.DateTime.MILLENNIUM:
  307. clearInYear(date2);
  308. date2.setUTCFullYear(Math.floor(date2.getUTCFullYear() / 1000) * 1000);
  309. break;
  310. }
  311. date.setTime(date2.getTime() - timeShift);
  312. };
  313. /**
  314. * Rounds date objects up to the nearest interval or multiple of an interval.
  315. * This method modifies the given date object, converting it to the given
  316. * timezone if specified.
  317. *
  318. * @param {Date} date the date object to round
  319. * @param {Number} intervalUnit a constant, integer index specifying an
  320. * interval, e.g. SimileAjax.DateTime.HOUR
  321. * @param {Number} timeZone a timezone shift, given in hours
  322. * @param {Number} multiple a multiple of the interval to round by
  323. * @param {Number} firstDayOfWeek an integer specifying the first day of the
  324. * week, 0 corresponds to Sunday, 1 to Monday, etc.
  325. * @see SimileAjax.DateTime.roundDownToInterval
  326. */
  327. SimileAjax.DateTime.roundUpToInterval = function(date, intervalUnit, timeZone, multiple, firstDayOfWeek) {
  328. var originalTime = date.getTime();
  329. SimileAjax.DateTime.roundDownToInterval(date, intervalUnit, timeZone, multiple, firstDayOfWeek);
  330. if (date.getTime() < originalTime) {
  331. date.setTime(date.getTime() +
  332. SimileAjax.DateTime.gregorianUnitLengths[intervalUnit] * multiple);
  333. }
  334. };
  335. /**
  336. * Increments a date object by a specified interval, taking into
  337. * consideration the timezone.
  338. *
  339. * @param {Date} date the date object to increment
  340. * @param {Number} intervalUnit a constant, integer index specifying an
  341. * interval, e.g. SimileAjax.DateTime.HOUR
  342. * @param {Number} timeZone the timezone offset in hours
  343. */
  344. SimileAjax.DateTime.incrementByInterval = function(date, intervalUnit, timeZone) {
  345. timeZone = (typeof timeZone == 'undefined') ? 0 : timeZone;
  346. var timeShift = timeZone *
  347. SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR];
  348. var date2 = new Date(date.getTime() + timeShift);
  349. switch(intervalUnit) {
  350. case SimileAjax.DateTime.MILLISECOND:
  351. date2.setTime(date2.getTime() + 1)
  352. break;
  353. case SimileAjax.DateTime.SECOND:
  354. date2.setTime(date2.getTime() + 1000);
  355. break;
  356. case SimileAjax.DateTime.MINUTE:
  357. date2.setTime(date2.getTime() +
  358. SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.MINUTE]);
  359. break;
  360. case SimileAjax.DateTime.HOUR:
  361. date2.setTime(date2.getTime() +
  362. SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
  363. break;
  364. case SimileAjax.DateTime.DAY:
  365. date2.setUTCDate(date2.getUTCDate() + 1);
  366. break;
  367. case SimileAjax.DateTime.WEEK:
  368. date2.setUTCDate(date2.getUTCDate() + 7);
  369. break;
  370. case SimileAjax.DateTime.MONTH:
  371. date2.setUTCMonth(date2.getUTCMonth() + 1);
  372. break;
  373. case SimileAjax.DateTime.YEAR:
  374. date2.setUTCFullYear(date2.getUTCFullYear() + 1);
  375. break;
  376. case SimileAjax.DateTime.DECADE:
  377. date2.setUTCFullYear(date2.getUTCFullYear() + 10);
  378. break;
  379. case SimileAjax.DateTime.CENTURY:
  380. date2.setUTCFullYear(date2.getUTCFullYear() + 100);
  381. break;
  382. case SimileAjax.DateTime.MILLENNIUM:
  383. date2.setUTCFullYear(date2.getUTCFullYear() + 1000);
  384. break;
  385. }
  386. date.setTime(date2.getTime() - timeShift);
  387. };
  388. /**
  389. * Returns a new date object with the given time offset removed.
  390. *
  391. * @param {Date} date the starting date
  392. * @param {Number} timeZone a timezone specified in an hour offset to remove
  393. * @return {Date} a new date object with the offset removed
  394. */
  395. SimileAjax.DateTime.removeTimeZoneOffset = function(date, timeZone) {
  396. return new Date(date.getTime() +
  397. timeZone * SimileAjax.DateTime.gregorianUnitLengths[SimileAjax.DateTime.HOUR]);
  398. };
  399. /**
  400. * Returns the timezone of the user's browser.
  401. *
  402. * @return {Number} the timezone in the user's locale in hours
  403. */
  404. SimileAjax.DateTime.getTimezone = function() {
  405. var d = new Date().getTimezoneOffset();
  406. return d / -60;
  407. };