(function(global, undefined) { var kafe = global.kafe, $ = kafe.dependencies.jQuery; kafe.bonify({name:'date', version:'1.2.0', obj:(function(){ var // dictionary _dict = { fr: { m: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'], m3: [0,0,0,0,0,'Jun','Jul'], w: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], d: ['1er'], r: ['en ce moment','il y a moins d\'une minute','il y a environ une minute','il y a %n minutes','il y a environ une heure','il y a %n heures','hier','avant-hier','il y a %n jours','la semaine passée','il y a %n semaines','le mois passé','il y a %n mois'] }, en: { m: ['January','February','March','April','May','June','July','August','September','October','November','December'], w: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], d: ['1st','2nd','3rd','4th','5th','6th','7th','8th','9th','10th','11th','12th','13th','14th','15th','16th','17th','18th','19th','20th','21st','22nd','23rd','24th','25th','26th','27th','28th','29th','30th','31st'], r: ['now','less than a minute ago','about a minute ago','%n minutes ago','about an hour ago','%n hours ago','yesterday','day before yesterday','%n days ago','last week','%n weeks ago','last month','%n months ago'] }, multi: { m2: ['Ja','Fe','Mr','Al','Ma','Jn','Jl','Au','Se','Oc','No','De'] } }, // get a valid lang _lang = function(lang) { return kafe.fn.lang(_dict,lang); }, // get the 3-char month abbreviation _m3 = function(month, lang) { var d = _dict[_lang(lang)]; return (d.m3 && d.m3[month]) ? d.m3[month] : d.m[month].toString().substring(0,3); }, // get the 3-char weekday abbreviation _w3 = function(weekday, lang) { var d = _dict[_lang(lang)]; return (d.w3 && d.w3[weekday]) ? d.w3[weekday] : d.w[weekday].toString().substring(0,3); }, // trim every element of the array _trim = function(list, nb) { var d = []; for (var i in list) { d.push(list[i].toString().substr(0,nb)); } return d; } ; /** * ### Version 1.2.0 * Additionnal methods for date manipulation * * @module kafe * @class kafe.date */ var date = { /** * Number of milliseconds in a second (1000 ms per second) * * @property SECOND * @type Number **/ SECOND:1000, /** * Number of milliseconds in a minute (60 seconds per minute) * * @property MINUTE * @type Number **/ MINUTE:60000, /** * Number of milliseconds in an hour (60 minutes per hour) * * @property HOUR * @type Number **/ HOUR:3600000, /** * Number of milliseconds in a day (24 hours per day) * * @property DAY * @type Number **/ DAY:86400000, /** * Number of milliseconds in a week (7 days per week) * * @property WEEK * @type Number **/ WEEK:604800000, /** * Number of milliseconds in a month (4.348121428571429 weeks per month) * * @property MONTH * @type Number **/ MONTH:2629743840, /** * Number of milliseconds in a year (365.2422 days per year) * * @property YEAR * @type Number **/ YEAR:31556926080 }; /** * Get the day number out of the full year (365 days). * * @method getDayYear * @param {Date} d The date * @return {Number} The day of the year * @example * kafe.date.getDayYear(new Date('2013-07-17')); * // returns 198 */ date.getDayYear = function(d) { var max = this.getMaxMonth(d.getFullYear()), m = d.getMonth(), total = 0 ; for (var i=0; i<m; ++i) { total += max[i]; } return total+d.getDate(); }; /** * Returns whether the date is within a leap year or not. * * @method isLeapYear * @param {Number} year The year. * @return {Boolean} If it is a leap year or not. * @example * kafe.date.isLeapYear(2013); * // returns false * @example * kafe.date.isLeapYear(2004); * // returns true */ date.isLeapYear = function(year) { return ((year%4 === 0 && year%400 !== 0) || year == 2000); }; /** * Get the number of days for all the months of a given year. * * @method getMaxMonth * @param {Number} year The year. * @return {Array(Number)} An ordered array of day counts for each months of the given year. * @example * kafe.date.getMaxMonth(2013); * // returns [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] * @example * kafe.date.getMaxMonth(2013)[3]; * // returns 30 */ date.getMaxMonth = function(year) { return [31, (this.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; }; /** * Get the full name of the months of the year. * * @method getMonthNames * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of month names. * @example * kafe.date.getMonthNames('en'); * // returns ["January", "February", "March", "April", "May", "June", ... ] * @example * kafe.date.getMonthNames('en')[3]; * // returns "April" */ date.getMonthNames = function(lang) { return _dict[_lang(lang)].m; }; /** * Get the 1-char abbreviations of the months of the year. * * @method getMonth1Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 1-char month abbreviations. * @example * kafe.date.getMonth1Names('en'); * // returns ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"] * @example * kafe.date.getMonth1Names('en')[3]; * // returns "A" */ date.getMonth1Names = function(lang) { return _trim(_dict[_lang(lang)].m,1); }; /** * Get the 2-char abbreviations of the months of the year. * * @method getMonth2Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 2-char month abbreviations. * @example * kafe.date.getMonth2Names('en'); * // returns ["Ja", "Fe", "Mr", "Al", "Ma", "Jn", "Jl", "Au", "Se", "Oc", "No", "De"] * @example * kafe.date.getMonth2Names('en')[3]; * // returns "Al" */ date.getMonth2Names = function(lang) { lang = _lang(lang); return (_dict[lang].m2) ? _dict[lang].m2 : _dict.multi.m2; }; /** * Get the 3-char abbreviations of the months of the year. * * @method getMonth3Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 3-char month abbreviations. * @example * kafe.date.getMonth3Names('en'); * // returns ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] * @example * kafe.date.getMonth3Names('en')[3]; * // returns "Apr" */ date.getMonth3Names = function(lang) { var d = []; for (var i=0; i<12; ++i) { d.push(_m3(i, lang)); } return d; }; /** * Returns whether the date is within a weekend. * * @method isWeekend * @param {Date} d The date * @return {Boolean} If it is within a weekend or not. * @example * kafe.date.isWeekend(new Date('2013-07-17')); * // returns false * @example * kafe.date.isWeekend(new Date('2013-07-20')); * // returns true */ date.isWeekend = function(date) { var weekday = date.getDay(); return (weekday === 0 || weekday === 6); }; /** * Get the full name of the days of the week. * * @method getWeekdayNames * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of weekday names. * @example * kafe.date.getWeekdayNames('en'); * // returns ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] * @example * kafe.date.getWeekdayNames('en')[3]; * // returns "Wednesday" */ date.getWeekdayNames = function(lang) { return _dict[_lang(lang)].w; }; /** * Get the 1-char abbreviations of the days of the week. * * @method getWeekday1Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 1-char weekday abbreviations. * @example * kafe.date.getWeekday1Names('en'); * // returns ["S", "M", "T", "W", "T", "F", "S"] * @example * kafe.date.getWeekday1Names('en')[3]; * // returns "W" */ date.getWeekday1Names = function(lang) { return _trim(_dict[_lang(lang)].w,1); }; /** * Get the 2-char abbreviations of the days of the week. * * @method getWeekday2Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 2-char weekday abbreviations. * @example * kafe.date.getWeekday2Names('en'); * // returns ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"] * @example * kafe.date.getWeekday2Names('en')[3]; * // returns "We" */ date.getWeekday2Names = function(lang) { return _trim(_dict[_lang(lang)].w,2); }; /** * Get the 3-char abbreviations of the days of the week. * * @method getWeekday3Names * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of 3-char weekday abbreviations. * @example * kafe.date.getWeekday3Names('en'); * // returns ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] * @example * kafe.date.getWeekday3Names('en')[3]; * // returns "Wed" */ date.getWeekday3Names = function(lang) { var d = []; for (var i=0; i<7; ++i) { d.push(_w3(i, lang)); } return d; }; /** * Get a clean representation for all possible days of a month. * * @method getDayNames * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {Array(String)} An ordered array of clean representations for all possible days of a month. * @example * kafe.date.getDayNames('en'); * // returns ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", ... ] * @example * kafe.date.getDayNames('en')[3]; * // returns "4th" */ date.getDayNames = function(lang) { var d = _dict[_lang(lang)].d, l = d.length ; for (var i=l; i<31; ++i) { d[i] = (i+1).toString(); } return d; }; /** * Flexible formatting a given date object. * * @method format * @param {String} format A custom format composed of %- tokens. Characters that are not part of a token will be rendered literally. * @param {Token} format.%Y,%y Year variants: [2011, 11] * @param {Token} format.%M,%m,%A,%a,%B,%b,%C,%c Month variants: [01, 1, January, january, Jan, jan, JA, Ja] * @param {Token} format.%D,%d,%e Day variants: [02, 2, 2nd] * @param {Token} format.%W,%w,%X,%x,%Z,%z Weekday variants: [Sunday, sunday, Sun, sun, Su, su] * @param {Token} format.%H,%h,%K,%k,%p Hour variants [15, 15, 03, 3, pm] * @param {Token} format.%I,%i Minute variants [04, 4] * @param {Token} format.%S,%s Second variants [05, 5] * @param {Date} [date=NOW] A date to be formatted. * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {String} The formatted date. * @example * kafe.date.format('%W, %A %e, %Y', new Date('2013-07-17'), 'en'); * // returns "Tuesday, July 16th, 2013" * @example * kafe.date.format('%W, %d %a, %Y', new Date('2013-07-17'), 'fr'); * // returns "Mardi, 16 juillet, 2013" */ date.format = function(format, date, lang) { date = (date) ? date : new Date(); lang = _lang(lang); var pad = function() { return ('0'+arguments[0].toString()).slice(-2); }, d = _dict[lang], year = date.getFullYear(), month = date.getMonth()+1, day = date.getDate(), weekday = date.getDay(), hours = date.getHours(), minutes = date.getMinutes(), seconds = date.getSeconds(), hours12 = ((hours % 12) === 0) ? 12 : (hours % 12), hoursAmPm = Math.floor(hours/12), // 2011-01-02 15:04:05 data = { // ------------------- Y: year, // year 2011 y: year.toString().substring(2), // year 11 M: pad(month), // month 01 m: month, // month 1 A: d.m[month-1], // month January a: d.m[month-1].toLowerCase(), // month january B: this.getMonth3Names(lang)[month-1], // month Jan b: this.getMonth3Names(lang)[month-1].toLowerCase(), // month jan C: this.getMonth2Names(lang)[month-1].toUpperCase(), // month JA c: this.getMonth2Names(lang)[month-1], // month Ja D: pad(day), // day 02 d: day, // day 2 e: this.getDayNames(lang)[day-1], // day 2nd W: d.w[weekday], // weekday Sunday w: d.w[weekday].toLowerCase(), // weekday sunday X: this.getWeekday3Names(lang)[weekday], // weekday Sun x: this.getWeekday3Names(lang)[weekday].toLowerCase(), // weekday sun Z: this.getWeekday2Names(lang)[weekday], // weekday Su z: this.getWeekday2Names(lang)[weekday].toLowerCase(), // weekday su H: pad(hours), // hour 15 h: hours, // hour 15 K: pad(hours12), // hour 03 k: hours12, // hour 3 p: (hoursAmPm) ? 'pm' : 'am', // hour pm I: pad(minutes), // minute 04 i: minutes, // minute 4 S: pad(seconds), // second 05 s: seconds // second 5 } ; for (var i in data) { format = format.replace(new RegExp('%'+i,'g'),data[i]); } return format; }; /** * Get a relative time expression from a specific datetime. * * @method formatRelative * @param {Date} time Specific datetime object. * @param {Date} [now=NOW] Comparative datetime object to calculate the time difference. * @param {String} [lang=CURRENT_ENV_LANG] A two character language code. * @return {String} The relative time expression * @example * kafe.date.formatRelative(new Date('2013-07-19 6:00:00'), new Date('2013-07-19 20:00:00'), 'en'); * // returns "14 hours ago" * @example * kafe.date.formatRelative(new Date('2013-05-19'), new Date('2013-07-19'), 'en'); * // returns "2 months ago" */ date.formatRelative = function(time, now, lang) { now = (now) ? now : new Date(); var d = _dict[_lang(lang)].r, delta = now.getTime() - time.getTime() ; if (delta <= 0) { return d[0]; } else if (delta < date.MINUTE) { return d[1]; } else if(delta < 2*date.MINUTE) { return d[2]; } else if(delta < date.HOUR) { return d[3].replace('%n', Math.floor(delta/date.MINUTE)); } else if(delta < 2*date.HOUR) { return d[4]; } else if(delta < date.DAY) { return d[5].replace('%n', Math.floor(delta/date.HOUR)); } else if(delta < 2*date.DAY) { return d[6]; } else if(delta < 3*date.DAY) { return d[7]; } else if(delta < date.WEEK) { return d[8].replace('%n', Math.floor(delta/date.DAY)); } else if(delta < 2*date.WEEK) { return d[9]; } else if(delta < date.MONTH) { return d[10].replace('%n', Math.floor(delta/date.WEEK)); } else if(delta < 2*date.MONTH) { return d[11]; } else { return d[12].replace('%n', Math.floor(delta/date.MONTH)); } }; /** * Parses a given datetime string into a standard datetime object. * * @method parse * @param {String} dtstring Custom datetime string * @return {Date} The date object * @example * kafe.date.parse('2012-08-08T12:18:00.000-04:00'); * // returns Wed Aug 08 2012 12:18:00 GMT-0400 (EDT) * @example * kafe.date.parse('June 3, 2013'); * // returns Mon Jun 03 2013 00:00:00 GMT-0400 (EDT) */ date.parse = function(dtstring) { if (/^([0-9]{2,4})-([0-9]{2})-([0-9]{2})$/gi.test(dtstring)) { dtstring += ' 00:00:00'; } else if (/^([0-9]{2,4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})$/gi.test(dtstring)) { dtstring += ':00'; } var ts = Date.parse(dtstring); if (isNaN(ts)) { var y2y4 = function(year) { if (year > 69 && year < 100) { return Number(year) + 1900; } else if (year < 69) { return Number(year) + 2000; } else { return year; } }, m = date.getMonth3Names('en'), year, month, day, hour, minute, second, delta, e, d ; // ISO 8601 / 2011-03-08 09:25:15 (useless for chrome) if ((e = new RegExp('^([0-9]{2,4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$','gi').exec(dtstring))) { year = y2y4(e[1]); month = e[2]; day = e[3]; hour = e[4]; minute = e[5]; second = e[6]; // RFC 822 (rss) / Sat, 30 Oct 10 13:51:32 +0000 } else if ((e = new RegExp('^([a-z]{3}), ([0-9]{2}) ([a-z]{3}) ([0-9]{2,4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([+-][0-9]{4})$','gi').exec(dtstring))) { year = y2y4(e[4]); month = $.inArray(e[3], m)+1; day = e[2]; hour = e[5]; minute = e[6]; second = e[7]; delta = e[8]/100; // (twitter) / Mon Nov 01 01:49:22 +0000 2010 } else if ((e = new RegExp('^([a-z]{3}) ([a-z]{3}) ([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) ([+-][0-9]{4}) ([0-9]{2,4})$','gi').exec(dtstring))) { year = y2y4(e[8]); month = $.inArray(e[2], m)+1; day = e[3]; hour = e[4]; minute = e[5]; second = e[6]; delta = e[7]/100; // ISO 8601 / 2012-08-08T12:18:00.000-04:00 (useless for chrome/safari) } else if ((e = new RegExp('^([0-9]{2,4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})\\.([0-9]{3})([+-])([0-9]{2}):([0-9]{2})$','gi').exec(dtstring))) { year = y2y4(e[1]); month = e[2]; day = e[3]; hour = e[4]; minute = e[5]; second = e[6]; delta = (Number(e[9]) + (Number(e[10])/60)) * ((e[8] == '-') ? -1 : 1); } d = new Date(year, month-1, day, hour, minute, second, 0); return (delta !== undefined) ? new Date(d - ( (d.getTimezoneOffset() + (Number(delta)*60) ) * 60 * 1000)) : d; } else { return new Date(ts); } }; /** * Refreshes a dropdown containing the days of a given year/month combination. * * @method refreshSelectDays * @param {DOMElement} obj The <select> element * @param {Number} month The month * @param {Number} year The year * @example * $('.select-month').on('change', function(e) { * kafe.date.refreshSelectDays('.select-day', $(this).val(), $('.select-year').val()); * }) */ date.refreshSelectDays = function(obj, month, year) { // if a title in the dropdown var dp = (Number(obj.options[0].value)) ? 0 : 1, dn = -dp, nb = this.getMaxMonth(year)[month-1] ; // if there are less day in the new month if (obj.length+dn > nb) { // if a impossible day for the new days is selected if (obj.selectedIndex+1 > nb+dn) { obj.selectedIndex = nb-1+dp; } obj.length = nb+dp; // if there are more days in the new month } else if ( obj.length+dn < nb ) { var curr = obj.length; obj.length = nb+dp; // rebuild the new days for (var i=curr; i<nb+dp; ++i) { obj.options[i].text = i+1+dn; obj.options[i].value = i+1+dn; } } }; /** * Creates an html table calendar for a given month/year combination. You can also provide specific dates with destination url to be included in the rendered source. * * @method makeMonthCalendar * @param {Number} year The year * @param {Number} month The month * @param {Object} [links] The links by date * @param {Array} links.YYYY-MM-DD The links * @return {String} The rendered HTML * @example * kafe.date.makeMonthCalendar(2013, 4, {'2013-04-03':'http://mybirthday.com/'}); * // returns "<table data-month="2013-04"><caption>Avril 2013</caption><thead><tr><th>Dim</th><th>Lun</th><th>Mar</th><th>Mer</th><th>Jeu</th><th>Ven</th><th>Sam</th></thead><tbody><tr><td> </td><td data-date="2013-04-01"><span>1</span></td><td data-date="2013-04-02"><span>2</span></td><td data-date="2013-04-03"><a href="http://mybirthday.com/">3</a></td><td data-date="2013-04-04"><span>4</span></td><td data-date="2013-04-05"><span>5</span></td><td data-date="2013-04-06"><span>6</span></td></tr><tr><td data-date="2013-04-07"><span>7</span></td><td data-date="2013-04-08"><span>8</span></td><td data-date="2013-04-09"><span>9</span></td><td data-date="2013-04-10"><span>10</span></td><td data-date="2013-04-11"><span>11</span></td><td data-date="2013-04-12"><span>12</span></td><td data-date="2013-04-13"><span>13</span></td></tr><tr><td data-date="2013-04-14"><span>14</span></td><td data-date="2013-04-15"><span>15</span></td><td data-date="2013-04-16"><span>16</span></td><td data-date="2013-04-17"><span>17</span></td><td data-date="2013-04-18"><span>18</span></td><td data-date="2013-04-19"><span>19</span></td><td data-date="2013-04-20"><span>20</span></td></tr><tr><td data-date="2013-04-21"><span>21</span></td><td data-date="2013-04-22"><span>22</span></td><td data-date="2013-04-23"><span>23</span></td><td data-date="2013-04-24"><span>24</span></td><td data-date="2013-04-25"><span>25</span></td><td data-date="2013-04-26"><span>26</span></td><td data-date="2013-04-27"><span>27</span></td></tr><tr><td data-date="2013-04-28"><span>28</span></td><td data-date="2013-04-29"><span>29</span></td><td data-date="2013-04-30"><span>30</span></td><td> </td><td> </td><td> </td><td> </td></tr></tbody></table>" */ date.makeMonthCalendar = function(year, month, links) { links = links || {}; --m; var i, weekdays = date.getWeekday3Names(), max = date.getMaxMonth(year)[month], firstDay = new Date(year,month,1).getDay(), week = 0, today = date.format('%Y-%M-%D', new Date()), html = '<table data-month="'+date.format('%Y-%M', new Date(year,month,1))+'"><caption>'+date.getMonthNames()[month]+' '+year+'</caption><thead><tr>' ; // weekdays for (i in weekdays) { html += '<th>'+weekdays[i]+'</th>'; } html += '</thead><tbody><tr>'; // start padding for (i=0; i<firstDay; ++i) { html += '<td> </td>'; ++week; } // days for (i=1; i<=max; ++i) { if (week == 7) { html += '</tr><tr>'; week = 0; } var thisDate = date.format('%Y-%M-%D', new Date(year,month,i)); html += '<td data-date="'+thisDate+'"'+((thisDate == today) ? ' class="Today"' : '')+'>' + ((links[thisDate]) ? '<a href="'+links[thisDate]+'">'+i+'</a>' : '<span>'+i+'</span>') + '</td>'; ++week; } // end padding for (i=week; i<7; ++i) { html += '<td> </td>'; } return html+'</tr></tbody></table>'; }; return date; })()}); })(typeof window !== 'undefined' ? window : this);