// // strftime // github.com/samsonjs/strftime // @_sjs // // Copyright 2010 - 2013 Sami Samhuri // // MIT License // http://sjs.mit-license.org // ;(function() { //// Where to export the API var namespace; // CommonJS / Node module if (typeof module !== 'undefined') { namespace = module.exports = strftime; } // Browsers and other environments else { // Get the global object. Works in ES3, ES5, and ES5 strict mode. namespace = (function(){ return this || (1,eval)('this') }()); } function words(s) { return (s || '').split(' '); } var DefaultLocale = { days: words('Sunday Monday Tuesday Wednesday Thursday Friday Saturday') , shortDays: words('Sun Mon Tue Wed Thu Fri Sat') , months: words('January February March April May June July August September October November December') , shortMonths: words('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec') , AM: 'AM' , PM: 'PM' , am: 'am' , pm: 'pm' }; namespace.strftime = strftime; function strftime(fmt, d, locale) { return _strftime(fmt, d, locale); } // locale is optional namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ; function strftimeTZ(fmt, d, locale, timezone) { if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { timezone = locale; locale = undefined; } return _strftime(fmt, d, locale, { timezone: timezone }); } namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC; function strftimeUTC(fmt, d, locale) { return _strftime(fmt, d, locale, { utc: true }); } namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime; function localizedStrftime(locale) { return function(fmt, d, options) { return strftime(fmt, d, locale, options); }; } // d, locale, and options are optional, but you can't leave // holes in the argument list. If you pass options you have to pass // in all the preceding args as well. // // options: // - locale [object] an object with the same structure as DefaultLocale // - timezone [number] timezone offset in minutes from GMT function _strftime(fmt, d, locale, options) { options = options || {}; // d and locale are optional so check if d is really the locale if (d && !quacksLikeDate(d)) { locale = d; d = undefined; } d = d || new Date(); locale = locale || DefaultLocale; locale.formats = locale.formats || {}; // Hang on to this Unix timestamp because we might mess with it directly below. var timestamp = d.getTime(); var tz = options.timezone; var tzType = typeof tz; if (options.utc || tzType == 'number' || tzType == 'string') { d = dateToUTC(d); } if (tz) { // ISO 8601 format timezone string, [-+]HHMM // // Convert to the number of minutes and it'll be applied to the date below. if (tzType == 'string') { var sign = tz[0] == '-' ? -1 : 1; var hours = parseInt(tz.slice(1, 3), 10); var mins = parseInt(tz.slice(3, 5), 10); tz = sign * ((60 * hours) + mins); } if (tzType) { d = new Date(d.getTime() + (tz * 60000)); } } // Most of the specifiers supported by C's strftime, and some from Ruby. // Some other syntax extensions from Ruby are supported: %-, %_, and %0 // to pad with nothing, space, or zero (respectively). return fmt.replace(/%([-_0:]?.)/g, function(_, c) { var mod, padding, ext; if (c.length == 2) { mod = c[0]; // omit padding if (mod == '-') { padding = ''; } // pad with space else if (mod == '_') { padding = ' '; } // pad with zero else if (mod == '0') { padding = '0'; } else if (mod == ":") { ext = true; } else { // unrecognized, return the format return _; } c = c[1]; } switch (c) { // Examples for new Date(0) in GMT // 'Thursday' case 'A': return locale.days[d.getDay()]; // 'Thu' case 'a': return locale.shortDays[d.getDay()]; // 'January' case 'B': return locale.months[d.getMonth()]; // 'Jan' case 'b': return locale.shortMonths[d.getMonth()]; // '19' case 'C': return pad(Math.floor(d.getFullYear() / 100), padding); // '01/01/70' case 'D': return _strftime(locale.formats.D || '%m/%d/%y', d, locale); // '01' case 'd': return pad(d.getDate(), padding); // '01' case 'e': return pad(d.getDate(), padding == null ? ' ' : padding); // '1970-01-01' case 'F': return _strftime(locale.formats.F || '%Y-%m-%d', d, locale); // '00' case 'H': return pad(d.getHours(), padding); // 'Jan' case 'h': return locale.shortMonths[d.getMonth()]; // '12' case 'I': return pad(hours12(d), padding); // '000' case 'j': var y = new Date(d.getFullYear(), 0, 1); var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); return pad(day, 3); // ' 0' case 'k': return pad(d.getHours(), padding == null ? ' ' : padding); // '000' case 'L': return pad(Math.floor(timestamp % 1000), 3); // '12' case 'l': return pad(hours12(d), padding == null ? ' ' : padding); // '00' case 'M': return pad(d.getMinutes(), padding); // '01' case 'm': return pad(d.getMonth() + 1, padding); // '\n' case 'n': return '\n'; // '1st' case 'o': return String(d.getDate()) + ordinal(d.getDate()); // 'am' case 'P': return d.getHours() < 12 ? locale.am : locale.pm; // 'AM' case 'p': return d.getHours() < 12 ? locale.AM : locale.PM; // '00:00' case 'R': return _strftime(locale.formats.R || '%H:%M', d, locale); // '12:00:00 AM' case 'r': return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale); // '00' case 'S': return pad(d.getSeconds(), padding); // '0' case 's': return Math.floor(timestamp / 1000); // '00:00:00' case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale); // '\t' case 't': return '\t'; // '00' case 'U': return pad(weekNumber(d, 'sunday'), padding); // '4' case 'u': var day = d.getDay(); return day == 0 ? 7 : day; // 1 - 7, Monday is first day of the week // ' 1-Jan-1970' case 'v': return _strftime(locale.formats.v || '%e-%b-%Y', d, locale); // '00' case 'W': return pad(weekNumber(d, 'monday'), padding); // '4' case 'w': return d.getDay(); // 0 - 6, Sunday is first day of the week // '1970' case 'Y': return d.getFullYear(); // '70' case 'y': var y = String(d.getFullYear()); return y.slice(y.length - 2); // 'GMT' case 'Z': if (options.utc) { return "GMT"; } else { var tzString = d.toString().match(/\(([\w\s]+)\)/); return tzString && tzString[1] || ''; } // '+0000' case 'z': if (options.utc) { return ext ? "+00:00" : "+0000"; } else { var off = typeof tz == 'number' ? tz : -d.getTimezoneOffset(); var sep = ext ? ":" : ""; // separator for extended offset return (off < 0 ? '-' : '+') + pad(Math.floor(Math.abs(off) / 60)) + sep + pad(Math.abs(off) % 60); } default: return c; } }); } function dateToUTC(d) { var year = d.getUTCFullYear(); var date = new Date( year, d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds() ); // In old dates, years is incorrectly interpreted as a 2-digit year with base 1900. // Correct this by setting the year explicitly after the fuzzy creation process. if (date.getFullYear() != year) { date.setFullYear(year); } return date; } var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; function quacksLikeDate(x) { var i = 0 , n = RequiredDateMethods.length ; for (i = 0; i < n; ++i) { if (typeof x[RequiredDateMethods[i]] != 'function') { return false; } } return true; } // Default padding is '0' and default length is 2, both are optional. function pad(n, padding, length) { // pad(n, ) if (typeof padding === 'number') { length = padding; padding = '0'; } // Defaults handle pad(n) and pad(n, ) if (padding == null) { padding = '0'; } length = length || 2; var s = String(n); // padding may be an empty string, don't loop forever if it is if (padding) { while (s.length < length) s = padding + s; } return s; } function hours12(d) { var hour = d.getHours(); if (hour == 0) hour = 12; else if (hour > 12) hour -= 12; return hour; } // Get the ordinal suffix for a number: st, nd, rd, or th function ordinal(n) { var i = n % 10 , ii = n % 100 ; if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { return 'th'; } switch (i) { case 1: return 'st'; case 2: return 'nd'; case 3: return 'rd'; } } // firstWeekday: 'sunday' or 'monday', default is 'sunday' // // Pilfered & ported from Ruby's strftime implementation. function weekNumber(d, firstWeekday) { firstWeekday = firstWeekday || 'sunday'; // This works by shifting the weekday back by one day if we // are treating Monday as the first day of the week. var wday = d.getDay(); if (firstWeekday == 'monday') { if (wday == 0) // Sunday wday = 6; else wday--; } var firstDayOfYear = new Date(d.getFullYear(), 0, 1) , yday = (d - firstDayOfYear) / 86400000 , weekNum = (yday + 7 - wday) / 7 ; return Math.floor(weekNum); } }());