I am looking to customize a date value in the following format:
var d = new Date();
myobj.format(d, "dddd (ddd) S dd'd'.MM (MMM MMMM).yyyy HH:mm:ss.fff t tt T TT (o) {Z}");
I prefer not to utilize date.js because of its large size. The issue with the format-helper from stevenlevithan is the interchange of capital and lowercase 'M' characters. I want a consistent formatString that can be used in both C# and JavaScript.
Currently, I have developed my own solution which seems to be working well.
However, after moving the "format" function into the namespace myobj, the this-context gets lost within the format-function.
When calling the function "format" with .apply(this, arguments)
, the correct this-context is obtained, but the argument "m" is lost.
I wish to avoid having to call ord using the namespace structure (myobj.ord(bla)), and instead, be able to call it like "this.ord(bla)" or "aaa.ord(bla)", allowing for easy changes to the namespace name.
So, how can I either pass an extra argument to the anonymous function in the replace-regex or retain the "this"-context without losing m?
/* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
https://github.com/datejs/Datejs/blob/master/src/core.js
https://code.google.com/p/datejs/wiki/FormatSpecifiers
http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
http://blog.stevenlevithan.com/archives/date-time-format
*/
// https://github.com/datejs/Datejs/blob/master/src/globalization/en-US.js
var $i18n =
{
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
amDesignator: "AM",
pmDesignator: "PM",
}
var myobj =
{
// Pad number with 0
p: function (val, len)
{
val = String(val);
len = len || 2;
while (val.length < len) val = "0" + val;
return val;
}
// Pad Milliseconds
, mp: function (d, n)
{
var i = 3, res = p(d.getMilliseconds(), 3).substr(0, n);
for (; i < n; ++i)
res += "0";
return res;
}
, tzo: function (d)
{
var o = d.getTimezoneOffset();
return (o > 0 ? "-" : "+") + p(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
}
, tz: function (date)
{
var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
timezoneClip = /[^-+\dA-Z]/g;
return (String(date).match(timezone) || [""]).pop().replace(timezoneClip, "");
}
, ord: function (num)
{
if (num <= 0)
return num.toString();
switch (num % 100)
{
case 11:
case 12:
case 13:
return num + "th";
}
switch (num % 10)
{
case 1:
return num + "st";
case 2:
return num + "nd";
case 3:
return num + "rd";
default:
return num + "th";
}
} // End Fn ord
, format: function (x, formatString)
{
// "S dd'd'.MM (MMMM).yyyy ".replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,
return formatString.replace(/d{1,4}|M{1,4}|f{1,7}|yy(?:yy)?|([HhmsTt])\1?|[oSZ]|"[^"]*"|'[^']*'/g,
function (m, aaa)
{
console.log("foo");
console.log(this);
console.log(aaa);
if (m.charAt(0) === "\\")
{
return m.replace("\\", "");
}
x.h = x.getHours;
switch (m)
{
case "hh":
return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
case "h":
return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
case "HH":
return p(x.h());
case "H":
return x.h();
case "mm":
return p(x.getMinutes());
case "m":
return x.getMinutes();
case "ss":
return p(x.getSeconds());
case "s":
return x.getSeconds();
case "yyyy":
return p(x.getFullYear(), 4);
case "yy":
return p(x.getFullYear());
case "dddd":
return $i18n.dayNames[x.getDay()];
case "ddd":
return $i18n.abbreviatedDayNames[x.getDay()];
case "dd":
return p(x.getDate());
case "d":
return x.getDate();
case "MMMM":
return $i18n.monthNames[x.getMonth()];
case "MMM":
return $i18n.abbreviatedMonthNames[x.getMonth()];
case "MM":
return p((x.getMonth() + 1));
case "M":
return x.getMonth() + 1;
case "t":
return (x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1)).toLowerCase();
case "tt":
return (x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator).toLowerCase();;
case "T":
return x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1);
case "TT":
return x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator;
case "S":
console.log(this);
return this.ord(x.getDate());
case "fffffff":
return mp(x, 7);
case "ffffff":
return mp(x, 6);
case "fffff":
return mp(x, 5);
case "ffff":
return mp(x, 4);
case "fff":
return mp(x, 3);
case "ff":
return mp(x, 2);
case "f":
return mp(x, 1);
case "o":
return tzo(d);
case "Z":
return tz(d);
default:
return m;
} // End Switch
} // End Fn
//.apply(this, arguments)
);
}
};
Edit: The solution is simple, just use bind instead of apply:
/* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
https://github.com/datejs/Datejs/blob/master/src/core.js
https://code.google.com/p/datejs/wiki/FormatSpecifiers
http://stackoverflow.com/questions/3552461/how-to-format-a-javascript-date
http://blog.stevenlevithan.com/archives/date-time-format
http://stackoverflow.com/questions/6002808/is-there-any-way-to-get-current-time-in-nanoseconds-using-javascript
*/
// https://github.com/datejs/Datejs/blob/master/src/globalization/en-US.js
var $i18n =
{
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
amDesignator: "AM",
pmDesignator: "PM",
}
var myobj =
{
// Pad number with 0
p: function (val, len)
{
val = String(val);
len = len || 2;
while (val.length < len) val = "0" + val;
return val;
}
// Pad Milliseconds
, mp: function (d, n)
{
var i = 3, res = this.p(d.getMilliseconds(), 3).substr(0, n);
for (; i < n; ++i)
res += "0";
return res;
}
, tzo: function (d)
{
var o = d.getTimezoneOffset();
return (o > 0 ? "-" : "+") + this.p(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
}
, tz: function (date)
{
var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
timezoneClip = /[^-+\dA-Z]/g;
return (String(date).match(timezone) || [""]).pop().replace(timezoneClip, "");
}
, ord: function (num)
{
if (num <= 0)
return num.toString();
switch (num % 100)
{
case 11:
case 12:
case 13:
return num + "th";
}
switch (num % 10)
{
case 1:
return num + "st";
case 2:
return num + "nd";
case 3:
return num + "rd";
default:
return num + "th";
}
} // End Fn ord
,"formatString": function(str)
{
if (!str)
return str;
str = str.toString();
if (arguments.length < 2)
return str;
var t = typeof arguments[1],
args = "string" == t || "number" == t ? Array.prototype.slice.call(arguments) : arguments[1];
for (var arg in args)
str = str.replace(new RegExp("\\{" + arg + "\\}", "gi"), args[arg]);
return str
}
, "format": function (x, formatString)
{
// "S dd'd'.MM (MMMM).yyyy ".replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,
return formatString.replace(/d{1,4}|M{1,4}|f{1,7}|yy(?:yy)?|([HhmsTt])\1?|[oSZ]|"[^"]*"|'[^']*'/g,
function (m)
{
var p = this.p
,mp = this.mp.bind(this)
,tzo = this.tzo.bind(this)
,tz = this.tz.bind(this)
,ord = this.ord.bind(this);
x.h = x.getHours;
if (m.charAt(0) === "\\")
{
return m.replace("\\", "");
}
switch (m)
{
case "hh":
return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
case "h":
return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
case "HH":
return p(x.h());
case "H":
return x.h();
case "mm":
return p(x.getMinutes());
case "m":
return x.getMinutes();
case "ss":
return p(x.getSeconds());
case "s":
return x.getSeconds();
case "yyyy":
return p(x.getFullYear(), 4);
case "yy":
return p(x.getFullYear());
case "dddd":
return $i18n.dayNames[x.getDay()];
case "ddd":
return $i18n.abbreviatedDayNames[x.getDay()];
case "dd":
return p(x.getDate());
case "d":
return x.getDate();
case "MMMM":
return $i18n.monthNames[x.getMonth()];
case "MMM":
return $i18n.abbreviatedMonthNames[x.getMonth()];
case "MM":
return p((x.getMonth() + 1));
case "M":
return x.getMonth() + 1;
case "t":
return (x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1)).toLowerCase();
case "tt":
return (x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator).toLowerCase();;
case "T":
return x.h() < 12 ? $i18n.amDesignator.substring(0, 1) : $i18n.pmDesignator.substring(0, 1);
case "TT":
return x.h() < 12 ? $i18n.amDesignator : $i18n.pmDesignator;
case "S":
return ord(x.getDate());
case "fffffff":
return mp(x, 7);
case "ffffff":
return mp(x, 6);
case "fffff":
return mp(x, 5);
case "ffff":
return mp(x, 4);
case "fff":
return mp(x, 3);
case "ff":
return mp(x, 2);
case "f":
return mp(x, 1);
case "o":
return tzo(x);
case "Z":
return tz(x);
default:
return m;
} // End Switch
} // End Fn
.bind(this)
//.apply(this, arguments)
);
}
};
var x = new Date();
myobj.format(x, "dddd (ddd) S dd'd'.MM (MMM MMMM).yyyy HH:mm:ss.fff t tt T TT (o) {Z}")
myobj.formatString("hello {foo} name", { foo: "bar" });
// myobj.formatString("hello {foo} name");