├── README.md └── index.js /README.md: -------------------------------------------------------------------------------- 1 | Date Formatting Support (strftime) for CommonJS + Node.js 2 | =========================================== 3 | 4 | This CommonJS module provides PHP-style date formatting support (strftime), 5 | to allow you to print javascript dates according to a format specifier. 6 | 7 | Based heavily on Philip S Tellis' version for client side javascript. 8 | 9 | Tested on node.js. 10 | 11 | Install: 12 | -------- 13 | cd ~/.node_libraries 14 | git clone git://github.com/loopj/commonjs-date-formatting.git date_format 15 | 16 | Basic usage: 17 | ----------- 18 | // Load the module 19 | var strftime = require("date_format").strftime; 20 | 21 | // Print the current date in mm/dd/yyyy format 22 | console.log(strftime(new Date(), "%m/%d/%Y")); 23 | 24 | Supported Format Specifiers: 25 | ------------------------- 26 | - %a - abbreviated weekday name according to the current locale 27 | - %A - full weekday name according to the current locale 28 | - %b - abbreviated month name according to the current locale 29 | - %B - full month name according to the current locale 30 | - %c - preferred date and time representation for the current locale 31 | - %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) 32 | - %d - day of the month as a decimal number (range 01 to 31) 33 | - %D - same as %m/%d/%y 34 | - %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') 35 | - %g - like %G, but without the century 36 | - %G - The 4-digit year corresponding to the ISO week number 37 | - %h - same as %b 38 | - %H - hour as a decimal number using a 24-hour clock (range 00 to 23) 39 | - %I - hour as a decimal number using a 12-hour clock (range 01 to 12) 40 | - %j - day of the year as a decimal number (range 001 to 366) 41 | - %m - month as a decimal number (range 01 to 12) 42 | - %M - minute as a decimal number 43 | - %n - newline character 44 | - %p - either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale 45 | - %P - like %p, but lower case 46 | - %r - time in a.m. and p.m. notation equal to %I:%M:%S %p 47 | - %R - time in 24 hour notation equal to %H:%M 48 | - %S - second as a decimal number 49 | - %t - tab character 50 | - %T - current time, equal to %H:%M:%S 51 | - %u - weekday as a decimal number [1,7], with 1 representing Monday 52 | - %U - week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week 53 | - %V - The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. 54 | - %w - day of the week as a decimal, Sunday being 0 55 | - %W - week number of the current year as a decimal number, starting with the first Monday as the first day of the first week 56 | - %x - preferred date representation for the current locale without the time 57 | - %X - preferred time representation for the current locale without the date 58 | - %y - year as a decimal number without a century (range 00 to 99) 59 | - %Y - year as a decimal number including the century 60 | - %z - numerical time zone representation 61 | - %Z - time zone name or abbreviation 62 | - %% - a literal `%' character -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // strftime for CommonJS 2 | // 3 | // Based heavily on Philip S Tellis' version for client side javascript 4 | // Copyright (c) 2008, Philip S Tellis 5 | // Copyright (c) 2010, James Smith 6 | // 7 | 8 | function xPad(x, pad, r) { 9 | if(typeof(r) == 'undefined') { 10 | r=10; 11 | } 12 | 13 | for( ; parseInt(x, 10)1; r/=10) 14 | x = pad.toString() + x; 15 | 16 | return x.toString(); 17 | }; 18 | 19 | // Localised strings for English 20 | var locales = {}; 21 | locales.en = { 22 | a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 23 | A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 24 | b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 25 | B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 26 | c: '%a %d %b %Y %T %Z', 27 | p: ['AM', 'PM'], 28 | P: ['am', 'pm'], 29 | x: '%d/%m/%y', 30 | X: '%T' 31 | }; 32 | 33 | // Localised strings for US English 34 | locales['en-US'] = locales.en; 35 | locales['en-US'].c = '%a %d %b %Y %r %Z'; 36 | locales['en-US'].x = '%D'; 37 | locales['en-US'].X = '%r'; 38 | 39 | // Localised strings for British English 40 | locales['en-GB'] = locales.en; 41 | 42 | // Localised strings for Australian English 43 | locales['en-AU'] = locales['en-GB']; 44 | 45 | // List of supported format specifiers. 46 | var formats = { 47 | a: function(d) { return locales[d.locale].a[d.getDay()]; }, 48 | A: function(d) { return locales[d.locale].A[d.getDay()]; }, 49 | b: function(d) { return locales[d.locale].b[d.getMonth()]; }, 50 | B: function(d) { return locales[d.locale].B[d.getMonth()]; }, 51 | c: 'toLocaleString', 52 | C: function(d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); }, 53 | d: ['getDate', '0'], 54 | e: ['getDate', ' '], 55 | g: function(d) { return xPad(parseInt(formats.G(d)/100, 10), 0); }, 56 | G: function(d) { 57 | var y = d.getFullYear(); 58 | var V = parseInt(formats.V(d), 10); 59 | var W = parseInt(formats.W(d), 10); 60 | 61 | if(W > V) { 62 | y++; 63 | } else if(W===0 && V>=52) { 64 | y--; 65 | } 66 | 67 | return y; 68 | }, 69 | H: ['getHours', '0'], 70 | I: function(d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); }, 71 | j: function(d) { 72 | var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT'); 73 | ms += d.getTimezoneOffset()*60000; 74 | var doy = parseInt(ms/60000/60/24, 10)+1; 75 | return xPad(doy, 0, 100); 76 | }, 77 | l: function (d) { var l=d.getHours()%12; return xPad(l==0?12:l,' ')}, 78 | m: function(d) { return xPad(d.getMonth()+1, 0); }, 79 | M: ['getMinutes', '0'], 80 | p: function(d) { return locales[d.locale].p[d.getHours() >= 12 ? 1 : 0 ]; }, 81 | P: function(d) { return locales[d.locale].P[d.getHours() >= 12 ? 1 : 0 ]; }, 82 | S: ['getSeconds', '0'], 83 | u: function(d) { var dow = d.getDay(); return dow===0?7:dow; }, 84 | U: function(d) { 85 | var doy = parseInt(formats.j(d), 10); 86 | var rdow = 6-d.getDay(); 87 | var woy = parseInt((doy+rdow)/7, 10); 88 | return xPad(woy, 0); 89 | }, 90 | V: function(d) { 91 | var woy = parseInt(formats.W(d), 10); 92 | var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); 93 | var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); 94 | if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) 95 | { 96 | idow = 1; 97 | } 98 | else if(idow === 0) 99 | { 100 | idow = formats.V(new Date('' + (d.getFullYear()-1) + '/12/31')); 101 | } 102 | 103 | return xPad(idow, 0); 104 | }, 105 | w: 'getDay', 106 | W: function(d) { 107 | var doy = parseInt(formats.j(d), 10); 108 | var rdow = 7-formats.u(d); 109 | var woy = parseInt((doy+rdow)/7, 10); 110 | return xPad(woy, 0, 10); 111 | }, 112 | y: function(d) { return xPad(d.getFullYear()%100, 0); }, 113 | Y: 'getFullYear', 114 | z: function(d) { 115 | var o = d.getTimezoneOffset(); 116 | var H = xPad(parseInt(Math.abs(o/60), 10), 0); 117 | var M = xPad(o%60, 0); 118 | return (o>0?'-':'+') + H + M; 119 | }, 120 | Z: function(d) { return d.toString().replace(/^.*\(([^)]+)\)$/, '$1'); }, 121 | '%': function(d) { return '%'; } 122 | }; 123 | 124 | // List of aggregate format specifiers. 125 | var aggregates = { 126 | c: 'locale', 127 | D: '%m/%d/%y', 128 | h: '%b', 129 | n: '\n', 130 | r: '%I:%M:%S %p', 131 | R: '%H:%M', 132 | t: '\t', 133 | T: '%H:%M:%S', 134 | x: 'locale', 135 | X: 'locale' 136 | }; 137 | 138 | // Formats the date according to the specified format 139 | exports.strftime = function (d, fmt, locale) { 140 | d.locale = locale = locales[locale] ? locale : "en-US"; 141 | 142 | // First replace aggregates 143 | while(fmt.match(/%[cDhnrRtTxXzZ]/)) { 144 | fmt = fmt.replace(/%([cDhnrRtTxXzZ])/g, function(m0, m1) { 145 | var f = aggregates[m1]; 146 | return (f == 'locale' ? locales[locale][m1] : f); 147 | }); 148 | } 149 | 150 | // Now replace formats - we need a closure so that the date object gets passed through 151 | var str = fmt.replace(/%([aAbBCdegGHIjlmMpPSuUVwWyY%])/g, function(m0, m1) { 152 | var f = formats[m1]; 153 | if(typeof(f) == 'string') { 154 | return d[f](); 155 | } else if(typeof(f) == 'function') { 156 | return f.call(d, d); 157 | } else if(typeof(f) == 'object' && typeof(f[0]) == 'string') { 158 | return xPad(d[f[0]](), f[1]); 159 | } else { 160 | return m1; 161 | } 162 | }); 163 | 164 | return str; 165 | }; --------------------------------------------------------------------------------