date_util.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. fc.addDays = addDays;
  2. fc.cloneDate = cloneDate;
  3. fc.parseDate = parseDate;
  4. fc.parseISO8601 = parseISO8601;
  5. fc.parseTime = parseTime;
  6. fc.formatDate = formatDate;
  7. fc.formatDates = formatDates;
  8. /* Date Math
  9. -----------------------------------------------------------------------------*/
  10. var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
  11. DAY_MS = 86400000,
  12. HOUR_MS = 3600000,
  13. MINUTE_MS = 60000;
  14. function addYears(d, n, keepTime) {
  15. d.setFullYear(d.getFullYear() + n);
  16. if (!keepTime) {
  17. clearTime(d);
  18. }
  19. return d;
  20. }
  21. function addMonths(d, n, keepTime) { // prevents day overflow/underflow
  22. if (+d) { // prevent infinite looping on invalid dates
  23. var m = d.getMonth() + n,
  24. check = cloneDate(d);
  25. check.setDate(1);
  26. check.setMonth(m);
  27. d.setMonth(m);
  28. if (!keepTime) {
  29. clearTime(d);
  30. }
  31. while (d.getMonth() != check.getMonth()) {
  32. d.setDate(d.getDate() + (d < check ? 1 : -1));
  33. }
  34. }
  35. return d;
  36. }
  37. function addDays(d, n, keepTime) { // deals with daylight savings
  38. if (+d) {
  39. var dd = d.getDate() + n,
  40. check = cloneDate(d);
  41. check.setHours(9); // set to middle of day
  42. check.setDate(dd);
  43. d.setDate(dd);
  44. if (!keepTime) {
  45. clearTime(d);
  46. }
  47. fixDate(d, check);
  48. }
  49. return d;
  50. }
  51. function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
  52. if (+d) { // prevent infinite looping on invalid dates
  53. while (d.getDate() != check.getDate()) {
  54. d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
  55. }
  56. }
  57. }
  58. function addMinutes(d, n) {
  59. d.setMinutes(d.getMinutes() + n);
  60. return d;
  61. }
  62. function clearTime(d) {
  63. d.setHours(0);
  64. d.setMinutes(0);
  65. d.setSeconds(0);
  66. d.setMilliseconds(0);
  67. return d;
  68. }
  69. function cloneDate(d, dontKeepTime) {
  70. if (dontKeepTime) {
  71. return clearTime(new Date(+d));
  72. }
  73. return new Date(+d);
  74. }
  75. function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
  76. var i=0, d;
  77. do {
  78. d = new Date(1970, i++, 1);
  79. } while (d.getHours()); // != 0
  80. return d;
  81. }
  82. function dayDiff(d1, d2) { // d1 - d2
  83. return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
  84. }
  85. function setYMD(date, y, m, d) {
  86. if (y !== undefined && y != date.getFullYear()) {
  87. date.setDate(1);
  88. date.setMonth(0);
  89. date.setFullYear(y);
  90. }
  91. if (m !== undefined && m != date.getMonth()) {
  92. date.setDate(1);
  93. date.setMonth(m);
  94. }
  95. if (d !== undefined) {
  96. date.setDate(d);
  97. }
  98. }
  99. /* Date Parsing
  100. -----------------------------------------------------------------------------*/
  101. function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
  102. if (typeof s == 'object') { // already a Date object
  103. return s;
  104. }
  105. if (typeof s == 'number') { // a UNIX timestamp
  106. return new Date(s * 1000);
  107. }
  108. if (typeof s == 'string') {
  109. if (s.match(/^\d+(\.\d+)?$/)) { // a UNIX timestamp
  110. return new Date(parseFloat(s) * 1000);
  111. }
  112. if (ignoreTimezone === undefined) {
  113. ignoreTimezone = true;
  114. }
  115. return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);
  116. }
  117. // TODO: never return invalid dates (like from new Date(<string>)), return null instead
  118. return null;
  119. }
  120. function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false
  121. // derived from http://delete.me.uk/2005/03/iso8601.html
  122. // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
  123. var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);
  124. if (!m) {
  125. return null;
  126. }
  127. var date = new Date(m[1], 0, 1);
  128. if (ignoreTimezone || !m[13]) {
  129. var check = new Date(m[1], 0, 1, 9, 0);
  130. if (m[3]) {
  131. date.setMonth(m[3] - 1);
  132. check.setMonth(m[3] - 1);
  133. }
  134. if (m[5]) {
  135. date.setDate(m[5]);
  136. check.setDate(m[5]);
  137. }
  138. fixDate(date, check);
  139. if (m[7]) {
  140. date.setHours(m[7]);
  141. }
  142. if (m[8]) {
  143. date.setMinutes(m[8]);
  144. }
  145. if (m[10]) {
  146. date.setSeconds(m[10]);
  147. }
  148. if (m[12]) {
  149. date.setMilliseconds(Number("0." + m[12]) * 1000);
  150. }
  151. fixDate(date, check);
  152. }else{
  153. date.setUTCFullYear(
  154. m[1],
  155. m[3] ? m[3] - 1 : 0,
  156. m[5] || 1
  157. );
  158. date.setUTCHours(
  159. m[7] || 0,
  160. m[8] || 0,
  161. m[10] || 0,
  162. m[12] ? Number("0." + m[12]) * 1000 : 0
  163. );
  164. if (m[14]) {
  165. var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);
  166. offset *= m[15] == '-' ? 1 : -1;
  167. date = new Date(+date + (offset * 60 * 1000));
  168. }
  169. }
  170. return date;
  171. }
  172. function parseTime(s) { // returns minutes since start of day
  173. if (typeof s == 'number') { // an hour
  174. return s * 60;
  175. }
  176. if (typeof s == 'object') { // a Date object
  177. return s.getHours() * 60 + s.getMinutes();
  178. }
  179. var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
  180. if (m) {
  181. var h = parseInt(m[1], 10);
  182. if (m[3]) {
  183. h %= 12;
  184. if (m[3].toLowerCase().charAt(0) == 'p') {
  185. h += 12;
  186. }
  187. }
  188. return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);
  189. }
  190. }
  191. /* Date Formatting
  192. -----------------------------------------------------------------------------*/
  193. // TODO: use same function formatDate(date, [date2], format, [options])
  194. function formatDate(date, format, options) {
  195. return formatDates(date, null, format, options);
  196. }
  197. function formatDates(date1, date2, format, options) {
  198. options = options || defaults;
  199. var date = date1,
  200. otherDate = date2,
  201. i, len = format.length, c,
  202. i2, formatter,
  203. res = '';
  204. for (i=0; i<len; i++) {
  205. c = format.charAt(i);
  206. if (c == "'") {
  207. for (i2=i+1; i2<len; i2++) {
  208. if (format.charAt(i2) == "'") {
  209. if (date) {
  210. if (i2 == i+1) {
  211. res += "'";
  212. }else{
  213. res += format.substring(i+1, i2);
  214. }
  215. i = i2;
  216. }
  217. break;
  218. }
  219. }
  220. }
  221. else if (c == '(') {
  222. for (i2=i+1; i2<len; i2++) {
  223. if (format.charAt(i2) == ')') {
  224. var subres = formatDate(date, format.substring(i+1, i2), options);
  225. if (parseInt(subres.replace(/\D/, ''), 10)) {
  226. res += subres;
  227. }
  228. i = i2;
  229. break;
  230. }
  231. }
  232. }
  233. else if (c == '[') {
  234. for (i2=i+1; i2<len; i2++) {
  235. if (format.charAt(i2) == ']') {
  236. var subformat = format.substring(i+1, i2);
  237. var subres = formatDate(date, subformat, options);
  238. if (subres != formatDate(otherDate, subformat, options)) {
  239. res += subres;
  240. }
  241. i = i2;
  242. break;
  243. }
  244. }
  245. }
  246. else if (c == '{') {
  247. date = date2;
  248. otherDate = date1;
  249. }
  250. else if (c == '}') {
  251. date = date1;
  252. otherDate = date2;
  253. }
  254. else {
  255. for (i2=len; i2>i; i2--) {
  256. if (formatter = dateFormatters[format.substring(i, i2)]) {
  257. if (date) {
  258. res += formatter(date, options);
  259. }
  260. i = i2 - 1;
  261. break;
  262. }
  263. }
  264. if (i2 == i) {
  265. if (date) {
  266. res += c;
  267. }
  268. }
  269. }
  270. }
  271. return res;
  272. };
  273. var dateFormatters = {
  274. s : function(d) { return d.getSeconds() },
  275. ss : function(d) { return zeroPad(d.getSeconds()) },
  276. m : function(d) { return d.getMinutes() },
  277. mm : function(d) { return zeroPad(d.getMinutes()) },
  278. h : function(d) { return d.getHours() % 12 || 12 },
  279. hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
  280. H : function(d) { return d.getHours() },
  281. HH : function(d) { return zeroPad(d.getHours()) },
  282. d : function(d) { return d.getDate() },
  283. dd : function(d) { return zeroPad(d.getDate()) },
  284. ddd : function(d,o) { return o.dayNamesShort[d.getDay()] },
  285. dddd: function(d,o) { return o.dayNames[d.getDay()] },
  286. M : function(d) { return d.getMonth() + 1 },
  287. MM : function(d) { return zeroPad(d.getMonth() + 1) },
  288. MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] },
  289. MMMM: function(d,o) { return o.monthNames[d.getMonth()] },
  290. yy : function(d) { return (d.getFullYear()+'').substring(2) },
  291. yyyy: function(d) { return d.getFullYear() },
  292. t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
  293. tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
  294. T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
  295. TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' },
  296. u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },
  297. S : function(d) {
  298. var date = d.getDate();
  299. if (date > 10 && date < 20) {
  300. return 'th';
  301. }
  302. return ['st', 'nd', 'rd'][date%10-1] || 'th';
  303. },
  304. w : function(d, o) { // local
  305. return o.weekNumberCalculation(d);
  306. },
  307. W : function(d) { // ISO
  308. return iso8601Week(d);
  309. }
  310. };
  311. fc.dateFormatters = dateFormatters;
  312. /* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js)
  313. *
  314. * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
  315. * `date` - the date to get the week for
  316. * `number` - the number of the week within the year that contains this date
  317. */
  318. function iso8601Week(date) {
  319. var time;
  320. var checkDate = new Date(date.getTime());
  321. // Find Thursday of this week starting on Monday
  322. checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
  323. time = checkDate.getTime();
  324. checkDate.setMonth(0); // Compare with Jan 1
  325. checkDate.setDate(1);
  326. return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
  327. }