2  strftime for Javascript
 
   3  Copyright (c) 2008, Philip S Tellis <philip@bluesmoon.info>
 
   6  This code is distributed under the terms of the BSD licence
 
   8  Redistribution and use of this software in source and binary forms, with or without modification,
 
   9  are permitted provided that the following conditions are met:
 
  11    * Redistributions of source code must retain the above copyright notice, this list of conditions
 
  12      and the following disclaimer.
 
  13    * Redistributions in binary form must reproduce the above copyright notice, this list of
 
  14      conditions and the following disclaimer in the documentation and/or other materials provided
 
  15      with the distribution.
 
  16    * The names of the contributors to this file may not be used to endorse or promote products
 
  17      derived from this software without specific prior written permission.
 
  19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 
  20 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
  21 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 
  22 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
  23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
  24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 
  25 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
  26 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  31  * \author Philip S Tellis \<philip@bluesmoon.info\>
 
  34  * \brief Javascript implementation of strftime
 
  36  * Implements strftime for the Date object in javascript based on the PHP implementation described at
 
  37  * http://www.php.net/strftime  This is in turn based on the Open Group specification defined
 
  38  * at http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html This implementation does not
 
  39  * include modified conversion specifiers (i.e., Ex and Ox)
 
  41  * The following format specifiers are supported:
 
  45  * \%a, \%A, \%b and \%B should be localised for non-English locales.
 
  48  * This library may be used as follows:
 
  52  *     var ymd = d.strftime('%Y/%m/%d');
 
  53  *     var iso = d.strftime('%Y-%m-%dT%H:%M:%S%z');
 
  57  * \sa \link Date.prototype.strftime Date.strftime \endlink for a description of each of the supported format specifiers
 
  58  * \sa Date.ext.locales for localisation information
 
  59  * \sa http://www.php.net/strftime for the PHP implementation which is the basis for this
 
  60  * \sa http://tech.bluesmoon.info/2008/04/strftime-in-javascript.html for feedback
 
  63 //! Date extension object - all supporting objects go in here.
 
  70 \brief Left pad a number with something
 
  71 \details Takes a number and pads it to the left with the passed in pad character
 
  72 \param x        The number to pad
 
  73 \param pad      The string to pad with
 
  74 \param r        [optional] Upper limit for pad.  A value of 10 pads to 2 digits, a value of 100 pads to 3 digits.
 
  77 \return The number left padded with the pad character.  This function returns a string and not a number.
 
  79 Date.ext.util.xPad=function(x, pad, r)
 
  81         if(typeof(r) == 'undefined')
 
  85         for( ; parseInt(x, 10)<r && r>1; r/=10)
 
  86                 x = pad.toString() + x;
 
  91 \brief Currently selected locale.
 
  93 The locale for a specific date object may be changed using \code Date.locale = "new-locale"; \endcode
 
  94 The default will be based on the lang attribute of the HTML tag of your document
 
  96 Date.prototype.locale = 'en-GB';
 
  98 if(document.getElementsByTagName('html') && document.getElementsByTagName('html')[0].lang)
 
 100         Date.prototype.locale = document.getElementsByTagName('html')[0].lang;
 
 105 \brief Localised strings for days of the week and months of the year.
 
 107 To create your own local strings, add a locale object to the locales object.
 
 108 The key of your object should be the same as your locale name.  For example:
 
 113 Names are case sensitive and are described at http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
 
 114 Your locale object must contain the following keys:
 
 115 \param a        Short names of days of week starting with Sunday
 
 116 \param A        Long names days of week starting with Sunday
 
 117 \param b        Short names of months of the year starting with January
 
 118 \param B        Long names of months of the year starting with February
 
 119 \param c        The preferred date and time representation in your locale
 
 120 \param p        AM or PM in your locale
 
 121 \param P        am or pm in your locale
 
 122 \param x        The  preferred date representation for the current locale without the time.
 
 123 \param X        The preferred time representation for the current locale without the date.
 
 125 \sa Date.ext.locales.en for a sample implementation
 
 126 \sa \ref localisation for detailed documentation on localising strftime for your own locale
 
 128 Date.ext.locales = { };
 
 131  * \brief Localised strings for English (British).
 
 133  * This will be used for any of the English dialects unless overridden by a country specific one.
 
 134  * This is the default locale if none specified
 
 136 Date.ext.locales.en = {
 
 137         a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
 
 138         A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
 
 139         b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
 
 140         B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
 
 141         c: '%a %d %b %Y %T %Z',
 
 149 // Localised strings for US English
 
 150 Date.ext.locales['en-US'] = Date.ext.locales.en;
 
 151 Date.ext.locales['en-US'].c = '%a %d %b %Y %r %Z';
 
 152 Date.ext.locales['en-US'].x = '%D';
 
 153 Date.ext.locales['en-US'].X = '%r';
 
 155 // Localised strings for British English
 
 156 Date.ext.locales['en-GB'] = Date.ext.locales.en;
 
 158 // Localised strings for Australian English
 
 159 Date.ext.locales['en-AU'] = Date.ext.locales['en-GB'];
 
 162 //! \brief List of supported format specifiers.
 
 165  * \arg \%a - abbreviated weekday name according to the current locale
 
 166  * \arg \%A - full weekday name according to the current locale
 
 167  * \arg \%b - abbreviated month name according to the current locale
 
 168  * \arg \%B - full month name according to the current locale
 
 169  * \arg \%c - preferred date and time representation for the current locale
 
 170  * \arg \%C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
 
 171  * \arg \%d - day of the month as a decimal number (range 01 to 31)
 
 172  * \arg \%D - same as %m/%d/%y
 
 173  * \arg \%e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
 
 174  * \arg \%g - like %G, but without the century
 
 175  * \arg \%G - The 4-digit year corresponding to the ISO week number
 
 176  * \arg \%h - same as %b
 
 177  * \arg \%H - hour as a decimal number using a 24-hour clock (range 00 to 23)
 
 178  * \arg \%I - hour as a decimal number using a 12-hour clock (range 01 to 12)
 
 179  * \arg \%j - day of the year as a decimal number (range 001 to 366)
 
 180  * \arg \%m - month as a decimal number (range 01 to 12)
 
 181  * \arg \%M - minute as a decimal number
 
 182  * \arg \%n - newline character
 
 183  * \arg \%p - either `AM' or `PM' according to the given time value, or the corresponding strings for the current locale
 
 184  * \arg \%P - like %p, but lower case
 
 185  * \arg \%r - time in a.m. and p.m. notation equal to %I:%M:%S %p
 
 186  * \arg \%R - time in 24 hour notation equal to %H:%M
 
 187  * \arg \%S - second as a decimal number
 
 188  * \arg \%t - tab character
 
 189  * \arg \%T - current time, equal to %H:%M:%S
 
 190  * \arg \%u - weekday as a decimal number [1,7], with 1 representing Monday
 
 191  * \arg \%U - week number of the current year as a decimal number, starting with
 
 192  *            the first Sunday as the first day of the first week
 
 193  * \arg \%V - The ISO 8601:1988 week number of the current year as a decimal number,
 
 194  *            range 01 to 53, where week 1 is the first week that has at least 4 days
 
 195  *            in the current year, and with Monday as the first day of the week.
 
 196  * \arg \%w - day of the week as a decimal, Sunday being 0
 
 197  * \arg \%W - week number of the current year as a decimal number, starting with the
 
 198  *            first Monday as the first day of the first week
 
 199  * \arg \%x - preferred date representation for the current locale without the time
 
 200  * \arg \%X - preferred time representation for the current locale without the date
 
 201  * \arg \%y - year as a decimal number without a century (range 00 to 99)
 
 202  * \arg \%Y - year as a decimal number including the century
 
 203  * \arg \%z - numerical time zone representation
 
 204  * \arg \%Z - time zone name or abbreviation
 
 205  * \arg \%% - a literal `\%' character
 
 208         a: function(d) { return Date.ext.locales[d.locale].a[d.getDay()]; },
 
 209         A: function(d) { return Date.ext.locales[d.locale].A[d.getDay()]; },
 
 210         b: function(d) { return Date.ext.locales[d.locale].b[d.getMonth()]; },
 
 211         B: function(d) { return Date.ext.locales[d.locale].B[d.getMonth()]; },
 
 213         C: function(d) { return Date.ext.util.xPad(parseInt(d.getFullYear()/100, 10), 0); },
 
 216         g: function(d) { return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100, 10), 0); },
 
 218                         var y = d.getFullYear();
 
 219                         var V = parseInt(Date.ext.formats.V(d), 10);
 
 220                         var W = parseInt(Date.ext.formats.W(d), 10);
 
 224                         } else if(W===0 && V>=52) {
 
 230         H: ['getHours', '0'],
 
 231         I: function(d) { var I=d.getHours()%12; return Date.ext.util.xPad(I===0?12:I, 0); },
 
 233                         var ms = d - new Date('' + d.getFullYear() + '/1/1 GMT');
 
 234                         ms += d.getTimezoneOffset()*60000;
 
 235                         var doy = parseInt(ms/60000/60/24, 10)+1;
 
 236                         return Date.ext.util.xPad(doy, 0, 100);
 
 238         m: function(d) { return Date.ext.util.xPad(d.getMonth()+1, 0); },
 
 239         M: ['getMinutes', '0'],
 
 240         p: function(d) { return Date.ext.locales[d.locale].p[d.getHours() >= 12 ? 1 : 0 ]; },
 
 241         P: function(d) { return Date.ext.locales[d.locale].P[d.getHours() >= 12 ? 1 : 0 ]; },
 
 242         S: ['getSeconds', '0'],
 
 243         u: function(d) { var dow = d.getDay(); return dow===0?7:dow; },
 
 245                         var doy = parseInt(Date.ext.formats.j(d), 10);
 
 246                         var rdow = 6-d.getDay();
 
 247                         var woy = parseInt((doy+rdow)/7, 10);
 
 248                         return Date.ext.util.xPad(woy, 0);
 
 251                         var woy = parseInt(Date.ext.formats.W(d), 10);
 
 252                         var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay();
 
 253                         // First week is 01 and not 00 as in the case of %U and %W,
 
 254                         // so we add 1 to the final result except if day 1 of the year
 
 255                         // is a Monday (then %W returns 01).
 
 256                         // We also need to subtract 1 if the day 1 of the year is 
 
 257                         // Friday-Sunday, so the resulting equation becomes:
 
 258                         var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1);
 
 259                         if(idow == 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4)
 
 265                                 idow = Date.ext.formats.V(new Date('' + (d.getFullYear()-1) + '/12/31'));
 
 268                         return Date.ext.util.xPad(idow, 0);
 
 272                         var doy = parseInt(Date.ext.formats.j(d), 10);
 
 273                         var rdow = 7-Date.ext.formats.u(d);
 
 274                         var woy = parseInt((doy+rdow)/7, 10);
 
 275                         return Date.ext.util.xPad(woy, 0, 10);
 
 277         y: function(d) { return Date.ext.util.xPad(d.getFullYear()%100, 0); },
 
 280                         var o = d.getTimezoneOffset();
 
 281                         var H = Date.ext.util.xPad(parseInt(Math.abs(o/60), 10), 0);
 
 282                         var M = Date.ext.util.xPad(o%60, 0);
 
 283                         return (o>0?'-':'+') + H + M;
 
 286           // does not work reliably (for example on Windows with CP1251), using numeric representations
 
 287           //function(d) { return d.toString().replace(/^.*\(([^)]+)\)$/, '$1'); },
 
 289       var o = d.getTimezoneOffset();
 
 290       var H = Date.ext.util.xPad(parseInt(Math.abs(o/60), 10), 0);
 
 291       var M = Date.ext.util.xPad(o%60, 0);
 
 292       return (o>0?'-':'+') + H + M;
 
 294         '%': function(d) { return '%'; }
 
 298 \brief List of aggregate format specifiers.
 
 300 Aggregate format specifiers map to a combination of basic format specifiers.
 
 301 These are implemented in terms of Date.ext.formats.
 
 303 A format specifier that maps to 'locale' is read from Date.ext.locales[current-locale].
 
 307 Date.ext.aggregates = {
 
 321 // Cache timezone values because they will never change for a given JS instance
 
 322 Date.ext.aggregates.z = Date.ext.formats.z(new Date());
 
 323 Date.ext.aggregates.Z = Date.ext.formats.Z(new Date());
 
 326 //! List of unsupported format specifiers.
 
 329  * All format specifiers supported by the PHP implementation are supported by
 
 330  * this javascript implementation.
 
 332 Date.ext.unsupported = { };
 
 336  * \brief Formats the date according to the specified format.
 
 337  * \param fmt   The format to format the date in.  This may be a combination of the following:
 
 340  * \return      A string representation of the date formatted based on the passed in parameter
 
 341  * \sa http://www.php.net/strftime for documentation on format specifiers
 
 343 Date.prototype.strftime=function(fmt)
 
 345         // Fix locale if declared locale hasn't been defined
 
 346         // After the first call this condition should never be entered unless someone changes the locale
 
 347         if(!(this.locale in Date.ext.locales))
 
 349                 if(this.locale.replace(/-[a-zA-Z]+$/, '') in Date.ext.locales)
 
 351                         this.locale = this.locale.replace(/-[a-zA-Z]+$/, '');
 
 355                         this.locale = 'en-GB';
 
 360         // First replace aggregates
 
 361         while(fmt.match(/%[cDhnrRtTxXzZ]/))
 
 363                 fmt = fmt.replace(/%([cDhnrRtTxXzZ])/g, function(m0, m1)
 
 365                                         var f = Date.ext.aggregates[m1];
 
 366                                         return (f == 'locale' ? Date.ext.locales[d.locale][m1] : f);
 
 371         // Now replace formats - we need a closure so that the date object gets passed through
 
 372         var str = fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g, function(m0, m1) 
 
 374                                 var f = Date.ext.formats[m1];
 
 375                                 if(typeof(f) == 'string') {
 
 377                                 } else if(typeof(f) == 'function') {
 
 379                                 } else if(typeof(f) == 'object' && typeof(f[0]) == 'string') {
 
 380                                         return Date.ext.util.xPad(d[f[0]](), f[1]);
 
 390  * \mainpage strftime for Javascript
 
 392  * \section toc Table of Contents
 
 394  * - <a class="el" href="strftime.js">Download full source</a> / <a class="el" href="strftime-min.js">minified</a>
 
 396  * - \subpage format_specifiers
 
 397  * - \subpage localisation
 
 398  * - \link strftime.js API Documentation \endlink
 
 400  * - \subpage changelog
 
 402  * - <a class="el" href="http://tech.bluesmoon.info/2008/04/strftime-in-javascript.html">Feedback</a>
 
 403  * - \subpage copyright_licence
 
 405  * \section intro_sec Introduction
 
 407  * C and PHP developers have had access to a built in strftime function for a long time.
 
 408  * This function is an easy way to format dates and times for various display needs.
 
 410  * This library brings the flexibility of strftime to the javascript Date object
 
 412  * Use this library if you frequently need to format dates in javascript in a variety of ways.  For example,
 
 413  * if you have PHP code that writes out formatted dates, and want to mimic the functionality using
 
 414  * progressively enhanced javascript, then this library can do exactly what you want.
 
 419  * \page usage Example usage
 
 421  * \section usage_sec Usage
 
 422  * This library may be used as follows:
 
 424  *     var d = new Date();
 
 426  *     var ymd = d.strftime('%Y/%m/%d');
 
 427  *     var iso = d.strftime('%Y-%m-%dT%H:%M:%S%z');
 
 431  * \subsection examples Examples
 
 433  * To get the current time in hours and minutes:
 
 435  *      var d = new Date();
 
 436  *      d.strftime("%H:%M");
 
 439  * To get the current time with seconds in AM/PM notation:
 
 441  *      var d = new Date();
 
 445  * To get the year and day of the year for August 23, 2009:
 
 447  *      var d = new Date('2009/8/23');
 
 448  *      d.strftime("%Y-%j");
 
 451  * \section demo_sec Demo
 
 453  * Try your own examples on the \subpage demo page.  You can use any of the supported
 
 454  * \subpage format_specifiers.
 
 459  * \page localisation Localisation
 
 460  * You can localise strftime by implementing the short and long forms for days of the
 
 461  * week and months of the year, and the localised aggregates for the preferred date
 
 462  * and time representation for your locale.  You need to add your locale to the
 
 463  * Date.ext.locales object.
 
 465  * \section localising_fr Localising for french
 
 467  * For example, this is how we'd add French language strings to the locales object:
 
 468  * \dontinclude index.html
 
 469  * \skip Generic french
 
 471  * The % format specifiers are all defined in \ref formats.  You can use any of those.
 
 473  * This locale definition may be included in your own source file, or in the HTML file
 
 474  * including \c strftime.js, however it must be defined \em after including \c strftime.js
 
 476  * The above definition includes generic french strings and formats that are used in France.
 
 477  * Other french speaking countries may have other representations for dates and times, so we
 
 478  * need to override this for them.  For example, Canadian french uses a Y-m-d date format,
 
 479  * while French french uses d.m.Y.  We fix this by defining Canadian french to be the same
 
 480  * as generic french, and then override the format specifiers for \c x for the \c fr-CA locale:
 
 483  * You can now use any of the French locales at any time by setting \link Date.prototype.locale Date.locale \endlink
 
 484  * to \c "fr", \c "fr-FR", \c "fr-CA", or any other french dialect:
 
 486  *     var d = new Date("2008/04/22");
 
 489  *     d.strftime("%A, %d %B == %x");
 
 493  *     mardi, 22 avril == 22.04.2008
 
 495  * While changing the locale to "fr-CA":
 
 497  *     d.locale = "fr-CA";
 
 499  *     d.strftime("%A, %d %B == %x");
 
 503  *     mardi, 22 avril == 2008-04-22
 
 506  * You can use any of the format specifiers defined at \ref formats
 
 508  * The locale for all dates defaults to the value of the \c lang attribute of your HTML document if
 
 509  * it is set, or to \c "en" otherwise.
 
 511  * Your locale definitions \b MUST be added to the locale object before calling
 
 512  * \link Date.prototype.strftime Date.strftime \endlink.
 
 514  * \sa \ref formats for a list of format specifiers that can be used in your definitions
 
 517  * \section locale_names Locale names
 
 519  * Locale names are defined in RFC 1766. Typically, a locale would be a two letter ISO639
 
 520  * defined language code and an optional ISO3166 defined country code separated by a -
 
 522  * eg: fr-FR, de-DE, hi-IN
 
 524  * \sa http://www.ietf.org/rfc/rfc1766.txt
 
 525  * \sa http://www.loc.gov/standards/iso639-2/php/code_list.php
 
 526  * \sa http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
 
 528  * \section locale_fallback Locale fallbacks
 
 530  * If a locale object corresponding to the fully specified locale isn't found, an attempt will be made
 
 531  * to fall back to the two letter language code.  If a locale object corresponding to that isn't found
 
 532  * either, then the locale will fall back to \c "en".  No warning will be issued.
 
 534  * For example, if we define a locale for de:
 
 536  * Then set the locale to \c "de-DE":
 
 538  *     d.locale = "de-DE";
 
 540  *     d.strftime("%a, %d %b");
 
 542  * In this case, the \c "de" locale will be used since \c "de-DE" has not been defined:
 
 547  * Swiss german will return the same since it will also fall back to \c "de":
 
 549  *     d.locale = "de-CH";
 
 551  *     d.strftime("%a, %d %b");
 
 557  * We need to override the \c a specifier for Swiss german, since it's different from German german:
 
 559  * We now get the correct results:
 
 561  *     d.locale = "de-CH";
 
 563  *     d.strftime("%a, %d %b");
 
 569  * \section builtin_locales Built in locales
 
 571  * This library comes with pre-defined locales for en, en-GB, en-US and en-AU.
 
 576  * \page format_specifiers Format specifiers
 
 578  * \section specifiers Format specifiers
 
 579  * strftime has several format specifiers defined by the Open group at 
 
 580  * http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html
 
 582  * PHP added a few of its own, defined at http://www.php.net/strftime
 
 584  * This javascript implementation supports all the PHP specifiers
 
 586  * \subsection supp Supported format specifiers:
 
 589  * \subsection unsupportedformats Unsupported format specifiers:
 
 590  * \copydoc unsupported
 
 595  * \page demo strftime demo
 
 596  * <div style="float:right;width:45%;">
 
 599  * \htmlinclude index.html
 
 606  * \section how_tos Usage
 
 608  * \subsection howtouse Is there a manual on how to use this library?
 
 610  * Yes, see \ref usage
 
 612  * \subsection wheretoget Where can I get a minified version of this library?
 
 614  * The minified version is available <a href="strftime-min.js" title="Minified strftime.js">here</a>.
 
 616  * \subsection which_specifiers Which format specifiers are supported?
 
 618  * See \ref format_specifiers
 
 622  * \subsection why_lib Why this library?
 
 624  * I've used the strftime function in C, PHP and the Unix shell, and found it very useful
 
 625  * to do date formatting.  When I needed to do date formatting in javascript, I decided
 
 626  * that it made the most sense to just reuse what I'm already familiar with.
 
 628  * \subsection why_another Why another strftime implementation for Javascript?
 
 630  * Yes, there are other strftime implementations for Javascript, but I saw problems with
 
 631  * all of them that meant I couldn't use them directly.  Some implementations had bad
 
 632  * designs.  For example, iterating through all possible specifiers and scanning the string
 
 633  * for them.  Others were tied to specific libraries like prototype.
 
 635  * Trying to extend any of the existing implementations would have required only slightly
 
 636  * less effort than writing this from scratch.  In the end it took me just about 3 hours
 
 637  * to write the code and about 6 hours battling with doxygen to write these docs.
 
 639  * I also had an idea of how I wanted to implement this, so decided to try it.
 
 641  * \subsection why_extend_date Why extend the Date class rather than subclass it?
 
 643  * I tried subclassing Date and failed.  I didn't want to waste time on figuring
 
 644  * out if there was a problem in my code or if it just wasn't possible.  Adding to the
 
 645  * Date.prototype worked well, so I stuck with it.
 
 647  * I did have some worries because of the way for..in loops got messed up after json.js added
 
 648  * to the Object.prototype, but that isn't an issue here since {} is not a subclass of Date.
 
 650  * My last doubt was about the Date.ext namespace that I created.  I still don't like this,
 
 651  * but I felt that \c ext at least makes clear that this is external or an extension.
 
 653  * It's quite possible that some future version of javascript will add an \c ext or a \c locale
 
 654  * or a \c strftime property/method to the Date class, but this library should probably
 
 655  * check for capabilities before doing what it does.
 
 657  * \section curiosity Curiosity
 
 659  * \subsection how_big How big is the code?
 
 661  * \arg 26K bytes with documentation
 
 662  * \arg 4242 bytes minified using <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>
 
 663  * \arg 1477 bytes minified and gzipped
 
 665  * \subsection how_long How long did it take to write this?
 
 667  * 15 minutes for the idea while I was composing this blog post:
 
 668  * http://tech.bluesmoon.info/2008/04/javascript-date-functions.html
 
 670  * 3 hours in one evening to write v1.0 of the code and 6 hours the same
 
 671  * night to write the docs and this manual.  As you can tell, I'm fairly
 
 674  * Versions 1.1 and 1.2 were done in a couple of hours each, and version 1.3
 
 677  * \section contributing Contributing
 
 679  * \subsection how_to_rfe How can I request features or make suggestions?
 
 681  * You can leave a comment on my blog post about this library here:
 
 682  * http://tech.bluesmoon.info/2008/04/strftime-in-javascript.html
 
 684  * \subsection how_to_contribute Can I/How can I contribute code to this library?
 
 686  * Yes, that would be very nice, thank you.  You can do various things.  You can make changes
 
 687  * to the library, and make a diff against the current file and mail me that diff at
 
 688  * philip@bluesmoon.info, or you could just host the new file on your own servers and add
 
 689  * your name to the copyright list at the top stating which parts you've added.
 
 691  * If you do mail me a diff, let me know how you'd like to be listed in the copyright section.
 
 693  * \subsection copyright_signover Who owns the copyright on contributed code?
 
 695  * The contributor retains copyright on contributed code.
 
 697  * In some cases I may use contributed code as a template and write the code myself.  In this
 
 698  * case I'll give the contributor credit for the idea, but will not add their name to the
 
 699  * copyright holders list.
 
 704  * \page copyright_licence Copyright & Licence
 
 706  * \section copyright Copyright
 
 707  * \dontinclude strftime.js
 
 711  * \section licence Licence
 
 713  * \until SUCH DAMAGE.
 
 717  * \page changelog ChangeLog
 
 719  * \par 1.3 - 2008/06/17:
 
 720  * - Fixed padding issue with negative timezone offsets in %r
 
 721  *   reported and fixed by Mikko <mikko.heimola@iki.fi>
 
 722  * - Added support for %P
 
 723  * - Internationalised %r, %p and %P
 
 725  * \par 1.2 - 2008/04/27:
 
 726  * - Fixed support for c (previously it just returned toLocaleString())
 
 727  * - Add support for c, x and X
 
 728  * - Add locales for en-GB, en-US and en-AU
 
 729  * - Make en-GB the default locale (previous was en)
 
 730  * - Added more localisation docs
 
 732  * \par 1.1 - 2008/04/27:
 
 733  * - Fix bug in xPad which wasn't padding more than a single digit
 
 734  * - Fix bug in j which had an off by one error for days after March 10th because of daylight savings
 
 735  * - Add support for g, G, U, V and W
 
 737  * \par 1.0 - 2008/04/22:
 
 738  * - Initial release with support for a, A, b, B, c, C, d, D, e, H, I, j, m, M, p, r, R, S, t, T, u, w, y, Y, z, Z, and %