--- /dev/null
+var fs = require('fs'),
+ uglify = require('uglify-js');
+
+function makeFile(filename, contents) {
+ fs.writeFileSync(filename, contents);
+ console.log(filename + " saved");
+}
+
+(function() {
+ var output = fs.readFileSync('./underscore.date.js', 'utf8'),
+ ast,
+ ugly;
+ ast = uglify.parser.parse(output);
+ ast = uglify.uglify.ast_mangle(ast);
+ ast = uglify.uglify.ast_squeeze(ast);
+ ugly = uglify.uglify.gen_code(ast);
+
+ makeFile('./underscore.date.min.js', ugly);
+})();
+++ /dev/null
-// Underscore.date
-//
-// (c) 2011 Tim Wood
-// Underscore.date is freely distributable under the terms of the MIT license.
-//
-// Version 0.3.2
-
-/*global _:false */
-
-
-(function(Date, _, undefined){
- // function to return first three characters for minification of wordsMonthsShort +
- // wordsWeekdaysShort arrays.
- function firstThreeLetters(input){
- return input.slice(0, 3);
- }
- // assign variables here so they can be overwritten for i18n or customization
- var self = this, _d,
- wordsMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- wordsMonthsShort = _.map(wordsMonths, firstThreeLetters),
- wordsWeekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
- wordsWeekdaysShort = _.map(wordsWeekdays, firstThreeLetters),
- wordsTimeAgo = {
- future: "in %s",
- past: "%s ago",
- s: "seconds",
- m: "a minute",
- mm: "%d minutes",
- h: "an hour",
- hh: "%d hours",
- d: "a day",
- dd: "%d days",
- M: "a month",
- MM: "%d months",
- y: "a year",
- yy: "%d years"
- },
- createOrdinal = function(number) {
- var b = number % 10;
- return (~~ (number % 100 / 10) === 1) ? 'th' :
- (b === 1) ? 'st' :
- (b === 2) ? 'nd' :
- (b === 3) ? 'rd' : 'th';
- };
-
- // left zero fill a number
- // see http://jsperf.com/left-zero-filling for performance comparison
- function leftZeroFill(number, targetLength) {
- var output = number + '';
- while (output.length < targetLength) {
- output = '0' + output;
- }
- return output;
- }
-
- // helper function for _.addTime and _.subtractTime
- function dateAddRemove(_this, input, adding){
- var self = _this.date,
- ms = (input.ms || 0) +
- (input.s || 0) * 1e3 + // 1000
- (input.m || 0) * 6e4 + // 1000 * 60
- (input.h || 0) * 36e5 + // 1000 * 60 * 60
- (input.d || 0) * 864e5 + // 1000 * 60 * 60 * 24
- (input.w || 0) * 6048e5, // 1000 * 60 * 60 * 24 * 7
- M = (input.M || 0) +
- (input.y || 0) * 12,
- currentDate;
- if (ms) {
- self.setMilliseconds(self.getMilliseconds() + ms * adding);
- }
- if (M) {
- currentDate = self.getDate();
- self.setDate(1);
- self.setMonth(self.getMonth() + M * adding);
- self.setDate(Math.min(new Date(self.getFullYear(), self.getMonth() + 1, 0).getDate(), currentDate));
- }
- return _this;
- }
-
- // convert an array to a date.
- // the array should mirror the parameters below
- // note: all values past the year are optional and will default to the lowest possible value.
- // [year, month, day , hour, minute, second, millisecond]
- function dateFromArray(input) {
- return new Date(input[0], input[1] || 0, input[2] || 1, input[3] || 0, input[4] || 0, input[5] || 0, input[6] || 0);
- }
-
- // convert any input to a date
- //
- // undefined = _.now()
- // date = date
- // array = new Date(array)
- // number = new Date(number)
- // string = new Date(string)
- function makeInputDate(input){
- return input === undefined ? new Date() :
- input instanceof _Date ? input.date :
- _.isDate(input) ? input :
- _.isArray(input) && input.length > 2 ? dateFromArray(input) :
- new Date(input);
- }
-
- // convert any input to milliseconds
- //
- // undefined = _.now()
- // number = number
- // date = date.gettime()
- // array = new Date(array).getTime()
- // string = new Date(string).getTime()
- function makeInputMilliseconds(input){
- return isNaN(input) ? makeInputDate(input).getTime() : input;
- }
-
- // helper function for _.relativeTime
- function substituteTimeAgo(string, number) {
- return wordsTimeAgo[string].replace(/%d/i, number || 1);
- }
-
- // _Date prototype object
- function _Date(input) {
- this.date = makeInputDate(input);
- return this;
- }
-
- var _DateProto = _Date.prototype;
-
- _DateProto.format = function(inputString) {
- // shortcuts to this and getting time functions
- // done to save bytes in minification
- var date = this.date,
- currentMonth = date.getMonth(),
- currentDate = date.getDate(),
- currentYear = date.getFullYear(),
- currentDay = date.getDay(),
- currentHours = date.getHours(),
- currentMinutes = date.getMinutes(),
- currentSeconds = date.getSeconds(),
- currentString = date.toString(),
- charactersToReplace = /(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?)/g,
- nonuppercaseLetters = /[^A-Z]/g;
- // check if the character is a format
- // return formatted string or non string.
- //
- // uses switch/case instead of an object of named functions (like http://phpjs.org/functions/date:380)
- // for minification and performance
- // see http://jsperf.com/object-of-functions-vs-switch for performance comparison
- function replaceFunction(input) {
- // create a couple variables to be used later inside one of the cases.
- var a, b;
- switch (input) {
- // MONTH
- case 'M' :
- return currentMonth + 1;
- case 'Mo' :
- return (currentMonth + 1) + createOrdinal(currentMonth + 1);
- case 'MM' :
- return leftZeroFill(currentMonth + 1, 2);
- case 'MMM' :
- return wordsMonthsShort[currentMonth];
- case 'MMMM' :
- return wordsMonths[currentMonth];
- // DAY OF MONTH
- case 'D' :
- return currentDate;
- case 'Do' :
- return currentDate + createOrdinal(currentDate);
- case 'DD' :
- return leftZeroFill(currentDate, 2);
- // DAY OF YEAR
- case 'DDD' :
- a = new Date(currentYear, currentMonth, currentDate);
- b = new Date(currentYear, 0, 1);
- return ~~ (((a - b) / 864e5) + 1.5);
- case 'DDDo' :
- a = replaceFunction('DDD');
- return a + createOrdinal(a);
- case 'DDDD' :
- return leftZeroFill(replaceFunction('DDD'), 3);
- // WEEKDAY
- case 'd' :
- return currentDay;
- case 'do' :
- return currentDay + createOrdinal(currentDay);
- case 'ddd' :
- return wordsWeekdaysShort[currentDay];
- case 'dddd' :
- return wordsWeekdays[currentDay];
- // WEEK OF YEAR
- case 'w' :
- a = new Date(currentYear, currentMonth, currentDate - currentDay + 5);
- b = new Date(a.getFullYear(), 0, 4);
- return ~~ ((a - b) / 864e5 / 7 + 1.5);
- case 'wo' :
- a = replaceFunction('w');
- return a + createOrdinal(a);
- case 'ww' :
- return leftZeroFill(replaceFunction('w'), 2);
- // YEAR
- case 'YY' :
- return (currentYear + '').slice(-2);
- case 'YYYY' :
- return currentYear;
- // AM / PM
- case 'a' :
- return currentHours > 11 ? 'pm' : 'am';
- case 'A' :
- return currentHours > 11 ? 'PM' : 'AM';
- // 24 HOUR
- case 'H' :
- return currentHours;
- case 'HH' :
- return leftZeroFill(currentHours, 2);
- // 12 HOUR
- case 'h' :
- return currentHours % 12 || 12;
- case 'hh' :
- return leftZeroFill(currentHours % 12 || 12, 2);
- // MINUTE
- case 'm' :
- return currentMinutes;
- case 'mm' :
- return leftZeroFill(currentMinutes, 2);
- // SECOND
- case 's' :
- return currentSeconds;
- case 'ss' :
- return leftZeroFill(currentSeconds, 2);
- // TIMEZONE
- case 'z' :
- return replaceFunction('zz').replace(nonuppercaseLetters, '');
- case 'zz' :
- a = currentString.indexOf('(');
- if (a > -1) {
- return currentString.slice(a + 1, currentString.indexOf(')'));
- }
- return currentString.slice(currentString.indexOf(':')).replace(nonuppercaseLetters, '');
- // DEFAULT
- default :
- return input.replace("\\", "");
- }
- }
- return inputString.replace(charactersToReplace, replaceFunction);
- };
-
- _DateProto.add = function(input) {
- return dateAddRemove(this, input, 1);
- };
-
- _DateProto.subtract = function(input) {
- return dateAddRemove(this, input, -1);
- };
-
- _DateProto.customize = function(input) {
- var inputOrdinal = input.ordinal;
- _.extend(wordsWeekdays, input.weekdays);
- _.extend(wordsWeekdaysShort, input.weekdaysShort);
- _.extend(wordsMonths, input.months);
- _.extend(wordsMonthsShort, input.monthsShort);
- _.extend(wordsTimeAgo, input.relativeTime);
- if (inputOrdinal && _.isFunction(inputOrdinal)) {
- createOrdinal = inputOrdinal;
- }
- };
-
- function msApart(time, now) {
- return makeInputMilliseconds(time) - makeInputMilliseconds(now);
- }
-
- function relativeTime(milliseconds) {
- var seconds = Math.abs(milliseconds) / 1000,
- minutes = seconds / 60,
- hours = minutes / 60,
- days = hours / 24,
- years = days / 365;
- return seconds < 45 && substituteTimeAgo('s', ~~ seconds) ||
- seconds < 90 && substituteTimeAgo('m') ||
- minutes < 45 && substituteTimeAgo('mm', ~~ minutes) ||
- minutes < 90 && substituteTimeAgo('h') ||
- hours < 24 && substituteTimeAgo('hh', ~~ hours) ||
- hours < 48 && substituteTimeAgo('d') ||
- days < 25 && substituteTimeAgo('dd', ~~ days) ||
- days < 45 && substituteTimeAgo('M') ||
- days < 350 && substituteTimeAgo('MM', ~~ ((days + 15) / 30)) ||
- years < 2 && substituteTimeAgo('y') ||
- substituteTimeAgo('yy', ~~ years);
- }
-
- _DateProto.from = function(time, withoutSuffix, asMilliseconds) {
- var difference = msApart(this.date, time),
- string = difference < 0 ? wordsTimeAgo.past : wordsTimeAgo.future;
- return asMilliseconds ? difference :
- withoutSuffix ? relativeTime(difference) :
- string.replace(/%s/i, relativeTime(difference));
- };
-
- _DateProto.fromNow = function(withoutSuffix, asMilliseconds) {
- return this.from(_.now(), withoutSuffix, asMilliseconds);
- };
-
- _DateProto.isLeapYear = function() {
- return _.isLeapYear(this.date.getFullYear());
- };
-
- // integrate with underscore.js
- _.mixin({
- date : function(input) {
- return new _Date(input);
- },
- now : function(asTimestamp) {
- return asTimestamp ? new Date().getTime() : _.date();
- },
- isLeapYear : function(year) {
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
- }
- });
-
-}(Date, _));
+++ /dev/null
-// Underscore.date
-//
-// (c) 2011 Tim Wood
-// Underscore.date is freely distributable under the terms of the MIT license.
-//
-// Version 0.3.2
-
-(function(a,b,c){function v(a){var b=Math.abs(a)/1e3,c=b/60,d=c/60,e=d/24,f=e/365;return b<45&&r("s",~~b)||b<90&&r("m")||c<45&&r("mm",~~c)||c<90&&r("h")||d<24&&r("hh",~~d)||d<48&&r("d")||e<25&&r("dd",~~e)||e<45&&r("M")||e<350&&r("MM",~~((e+15)/30))||f<2&&r("y")||r("yy",~~f)}function u(a,b){return q(a)-q(b)}function s(a){this.date=p(a);return this}function r(a,b){return k[a].replace(/%d/i,b||1)}function q(a){return isNaN(a)?p(a).getTime():a}function p(d){return d===c?new a:d instanceof s?d.date:b.isDate(d)?d:b.isArray(d)&&d.length>2?o(d):new a(d)}function o(b){return new a(b[0],b[1]||0,b[2]||1,b[3]||0,b[4]||0,b[5]||0,b[6]||0)}function n(b,c,d){var e=b.date,f=(c.ms||0)+(c.s||0)*1e3+(c.m||0)*6e4+(c.h||0)*36e5+(c.d||0)*864e5+(c.w||0)*6048e5,g=(c.M||0)+(c.y||0)*12,h;f&&e.setMilliseconds(e.getMilliseconds()+f*d),g&&(h=e.getDate(),e.setDate(1),e.setMonth(e.getMonth()+g*d),e.setDate(Math.min((new a(e.getFullYear(),e.getMonth()+1,0)).getDate(),h)));return b}function m(a,b){var c=a+"";while(c.length<b)c="0"+c;return c}function d(a){return a.slice(0,3)}var e=this,f,g=["January","February","March","April","May","June","July","August","September","October","November","December"],h=b.map(g,d),i=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],j=b.map(i,d),k={future:"in %s",past:"%s ago",s:"seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},l=function(a){var b=a%10;return~~(a%100/10)===1?"th":b===1?"st":b===2?"nd":b===3?"rd":"th"},t=s.prototype;t.format=function(b){function t(b){var c,r;switch(b){case"M":return d+1;case"Mo":return d+1+l(d+1);case"MM":return m(d+1,2);case"MMM":return h[d];case"MMMM":return g[d];case"D":return e;case"Do":return e+l(e);case"DD":return m(e,2);case"DDD":c=new a(f,d,e),r=new a(f,0,1);return~~((c-r)/864e5+1.5);case"DDDo":c=t("DDD");return c+l(c);case"DDDD":return m(t("DDD"),3);case"d":return k;case"do":return k+l(k);case"ddd":return j[k];case"dddd":return i[k];case"w":c=new a(f,d,e-k+5),r=new a(c.getFullYear(),0,4);return~~((c-r)/864e5/7+1.5);case"wo":c=t("w");return c+l(c);case"ww":return m(t("w"),2);case"YY":return(f+"").slice(-2);case"YYYY":return f;case"a":return n>11?"pm":"am";case"A":return n>11?"PM":"AM";case"H":return n;case"HH":return m(n,2);case"h":return n%12||12;case"hh":return m(n%12||12,2);case"m":return o;case"mm":return m(o,2);case"s":return p;case"ss":return m(p,2);case"z":return t("zz").replace(s,"");case"zz":c=q.indexOf("(");if(c>-1)return q.slice(c+1,q.indexOf(")"));return q.slice(q.indexOf(":")).replace(s,"");default:return b.replace("\\","")}}var c=this.date,d=c.getMonth(),e=c.getDate(),f=c.getFullYear(),k=c.getDay(),n=c.getHours(),o=c.getMinutes(),p=c.getSeconds(),q=c.toString(),r=/(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?)/g,s=/[^A-Z]/g;return b.replace(r,t)},t.add=function(a){return n(this,a,1)},t.subtract=function(a){return n(this,a,-1)},t.customize=function(a){var c=a.ordinal;b.extend(i,a.weekdays),b.extend(j,a.weekdaysShort),b.extend(g,a.months),b.extend(h,a.monthsShort),b.extend(k,a.relativeTime),c&&b.isFunction(c)&&(l=c)},t.from=function(a,b,c){var d=u(this.date,a),e=d<0?k.past:k.future;return c?d:b?v(d):e.replace(/%s/i,v(d))},t.fromNow=function(a,c){return this.from(b.now(),a,c)},t.isLeapYear=function(){return b.isLeapYear(this.date.getFullYear())},b.mixin({date:function(a){return new s(a)},now:function(c){return c?(new a).getTime():b.date()},isLeapYear:function(a){return a%4===0&&a%100!==0||a%400===0}})})(Date,_)
--- /dev/null
+{
+ "name": "underscore.date",
+ "version": "0.4.0",
+ "description": "Underscore.date is a JavaScript Date utility library built on top of Underscore.js",
+ "homepage": "https://github.com/timrwood/underscore.date",
+ "author": "Tim Wood <washwithcare@gmail.com> (http://timwoodcreates.com/)",
+ "keywords": [
+ "underscore",
+ "date"
+ ],
+ "main": "./underscore.date",
+ "engines": {
+ "node": "*"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/timrwood/underscore.date.git"
+ },
+ "bugs": {
+ "url": "https://github.com/timrwood/underscore.date/issues"
+ },
+ "licenses" : [
+ { "type" : "MIT" }
+ ]
+}
<title>Underscore.date customization test suite</title>
<link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
<script type="text/javascript" src="vendor/jquery.js"></script>
- <script type="text/javascript" src="vendor/underscore.js"></script>
<script type="text/javascript" src="../lib/underscore.date.js"></script>
<script type="text/javascript" src="vendor/qunit.js"></script>
<script type="text/javascript" src="customizeDate.js"></script>
$(function() {
+ _ = _date;
+
module("Customize");
_.date().customize({
<title>Underscore.date customization test suite</title>
<link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
<script type="text/javascript" src="vendor/jquery.js"></script>
- <script type="text/javascript" src="vendor/underscore.js"></script>
<script type="text/javascript" src="../lib/underscore.date.js"></script>
<script type="text/javascript" src="vendor/qunit.js"></script>
<script type="text/javascript" src="customizePartial.js"></script>
$(function() {
+ _ = _date;
+
module("Customize");
_.date().customize({
months : ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
weekdays : ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
relativeTime : {
- future: "%s from now",
- past: "%s ago",
- s: "moments",
- M: "a month",
- MM: "%d months",
- y: "a year",
- yy: "%d years"
+ future: "test %s from now",
+ past: "test %s ago",
+ s: "test moments",
+ M: "test a month",
+ MM: "test %d months",
+ y: "test a year",
+ yy: "test %d years"
},
ordinal : function(number) {
return 'o';
test("_.date().relative()", 11, function() {
var start = _.date([2007, 1, 28]);
- equal(start.from(_.date([2007, 1, 28]).add({s:30}), true), "moments");
+ equal(start.from(_.date([2007, 1, 28]).add({s:30}), true), "test moments");
equal(start.from(_.date([2007, 1, 28]).add({s:60}), true), "a minute");
equal(start.from(_.date([2007, 1, 28]).add({m:5}), true), "5 minutes");
equal(start.from(_.date([2007, 1, 28]).add({h:1}), true), "an hour");
equal(start.from(_.date([2007, 1, 28]).add({h:5}), true), "5 hours");
equal(start.from(_.date([2007, 1, 28]).add({d:1}), true), "a day");
equal(start.from(_.date([2007, 1, 28]).add({d:5}), true), "5 days");
- equal(start.from(_.date([2007, 1, 28]).add({M:1}), true), "a month");
- equal(start.from(_.date([2007, 1, 28]).add({M:5}), true), "5 months");
- equal(start.from(_.date([2007, 1, 28]).add({y:1}), true), "a year");
- equal(start.from(_.date([2007, 1, 28]).add({y:5}), true), "5 years");
+ equal(start.from(_.date([2007, 1, 28]).add({M:1}), true), "test a month");
+ equal(start.from(_.date([2007, 1, 28]).add({M:5}), true), "test 5 months");
+ equal(start.from(_.date([2007, 1, 28]).add({y:1}), true), "test a year");
+ equal(start.from(_.date([2007, 1, 28]).add({y:5}), true), "test 5 years");
});
test("_.fromNow()", 2, function() {
- equal(_.date(30000).from(0), "moments from now");
- equal(_.date(0).from(30000), "moments ago");
+ equal(_.date(30000).from(0), "test test moments from now");
+ equal(_.date(0).from(30000), "test test moments ago");
});
});
$(function() {
+ _ = _date;
+
module("Date");
test("_.date()", 6, function() {
- ok(_.isDate(_.date([2010, 1, 12]).date), "[2010, 1, 12]");
- ok(_.isDate(_.date([2010, 1, 12, 1]).date), "[2010, 1, 12, 1]");
- ok(_.isDate(_.date().date), "undefined");
- ok(_.isDate(_.date("Aug 9, 1995").date), "Aug 9, 1995");
- ok(_.isDate(_.date("Mon, 25 Dec 1995 13:30:00 GMT").date), "Mon, 25 Dec 1995 13:30:00 GMT");
+ ok(_.date([2010, 1, 12]).date instanceof Date, "[2010, 1, 12]");
+ ok(_.date([2010, 1, 12, 1]).date instanceof Date, "[2010, 1, 12, 1]");
+ ok(_.date().date instanceof Date, "undefined");
+ ok(_.date("Aug 9, 1995").date instanceof Date, "Aug 9, 1995");
+ ok(_.date("Mon, 25 Dec 1995 13:30:00 GMT").date instanceof Date, "Mon, 25 Dec 1995 13:30:00 GMT");
deepEqual(_.date(new Date(2010, 1, 14, 15, 25, 50, 125)), _.date([2010, 1, 14, 15, 25, 50, 125]), "constructing with array === constructing with new Date()");
});
});
test("_.date().add() + _.date().subtract()", 5, function() {
- equal(_([2010, 1, 14, 15, 25, 50, 125]).date().add({ms:200,s:10,m:10,h:2,d:3,M:2,y:3}).format("MMMM Do YYYY, h:mm:ss a"), "April 17th 2013, 5:36:00 pm");
- equal(_([2010, 0, 31]).date().format("MMMM Do YYYY"), "January 31st 2010");
- equal(_([2010, 0, 31]).date().add({M:1}).format("MMMM Do YYYY"), "February 28th 2010");
+ equal(_.date([2010, 1, 14, 15, 25, 50, 125]).add({ms:200,s:10,m:10,h:2,d:3,M:2,y:3}).format("MMMM Do YYYY, h:mm:ss a"), "April 17th 2013, 5:36:00 pm");
+ equal(_.date([2010, 0, 31]).format("MMMM Do YYYY"), "January 31st 2010");
+ equal(_.date([2010, 0, 31]).add({M:1}).format("MMMM Do YYYY"), "February 28th 2010");
equal(_.date([2007, 1, 28]).format("MMMM Do YYYY"), "February 28th 2007");
equal(_.date([2007, 1, 28]).subtract({M:1}).format("MMMM Do YYYY"), "January 28th 2007");
});
(function() {
+ _ = _date;
+
var date1 = new Date(2010, 2, 6, 15, 25, 50, 125),
date2 = new Date(1000),
rt1 = 1000 * 60 * 60 * 24 * 365 * 5,
<title>Underscore.date test suite</title>
<link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
<script type="text/javascript" src="vendor/jquery.js"></script>
- <script type="text/javascript" src="vendor/underscore.js"></script>
<script type="text/javascript" src="../lib/underscore.date.js"></script>
<script type="text/javascript" src="vendor/qunit.js"></script>
<script type="text/javascript" src="vendor/jslitmus.js"></script>
--- /dev/null
+// Underscore.date
+//
+// (c) 2011 Tim Wood
+// Underscore.date is freely distributable under the terms of the MIT license.
+//
+// Version 0.4.0
+
+(function(undefined){
+ // Establish the root object, "window" in the browser, or "global" on the server.
+ var root = this;
+
+ // assign variables here so they can be overwritten for i18n or customization
+ var self = this, _date,
+ wordsMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ wordsMonthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ wordsWeekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ wordsWeekdaysShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ wordsTimeAgo = {
+ future: "in %s",
+ past: "%s ago",
+ s: "seconds",
+ m: "a minute",
+ mm: "%d minutes",
+ h: "an hour",
+ hh: "%d hours",
+ d: "a day",
+ dd: "%d days",
+ M: "a month",
+ MM: "%d months",
+ y: "a year",
+ yy: "%d years"
+ },
+ createOrdinal = function(number) {
+ var b = number % 10;
+ return (~~ (number % 100 / 10) === 1) ? 'th' :
+ (b === 1) ? 'st' :
+ (b === 2) ? 'nd' :
+ (b === 3) ? 'rd' : 'th';
+ };
+
+ // left zero fill a number
+ // see http://jsperf.com/left-zero-filling for performance comparison
+ function leftZeroFill(number, targetLength) {
+ var output = number + '';
+ while (output.length < targetLength) {
+ output = '0' + output;
+ }
+ return output;
+ }
+
+ // helper function for _.addTime and _.subtractTime
+ function dateAddRemove(_this, input, adding){
+ var self = _this.date,
+ ms = (input.ms || 0) +
+ (input.s || 0) * 1e3 + // 1000
+ (input.m || 0) * 6e4 + // 1000 * 60
+ (input.h || 0) * 36e5 + // 1000 * 60 * 60
+ (input.d || 0) * 864e5 + // 1000 * 60 * 60 * 24
+ (input.w || 0) * 6048e5, // 1000 * 60 * 60 * 24 * 7
+ M = (input.M || 0) +
+ (input.y || 0) * 12,
+ currentDate;
+ if (ms) {
+ self.setMilliseconds(self.getMilliseconds() + ms * adding);
+ }
+ if (M) {
+ currentDate = self.getDate();
+ self.setDate(1);
+ self.setMonth(self.getMonth() + M * adding);
+ self.setDate(Math.min(new Date(self.getFullYear(), self.getMonth() + 1, 0).getDate(), currentDate));
+ }
+ return _this;
+ }
+
+ // convert an array to a date.
+ // the array should mirror the parameters below
+ // note: all values past the year are optional and will default to the lowest possible value.
+ // [year, month, day , hour, minute, second, millisecond]
+ function dateFromArray(input) {
+ return new Date(input[0], input[1] || 0, input[2] || 1, input[3] || 0, input[4] || 0, input[5] || 0, input[6] || 0);
+ }
+
+ // check if is an array
+ function isArray(input) {
+ return Object.prototype.toString.call(input) === '[object Array]';
+ }
+
+ // convert any input to a date
+ //
+ // undefined = _.now()
+ // date = date
+ // array = new Date(array)
+ // number = new Date(number)
+ // string = new Date(string)
+ function makeInputDate(input){
+ return input === undefined ? new Date() :
+ input instanceof _Date ? input.date :
+ input instanceof Date ? input :
+ isArray(input) && input.length > 2 ? dateFromArray(input) :
+ new Date(input);
+ }
+
+ // convert any input to milliseconds
+ //
+ // undefined = _.now()
+ // number = number
+ // date = date.gettime()
+ // array = new Date(array).getTime()
+ // string = new Date(string).getTime()
+ function makeInputMilliseconds(input){
+ return isNaN(input) ? makeInputDate(input).getTime() : input;
+ }
+
+ // helper function for _.relativeTime
+ function substituteTimeAgo(string, number) {
+ return wordsTimeAgo[string].replace(/%d/i, number || 1);
+ }
+
+ function msApart(time, now) {
+ return makeInputMilliseconds(time) - makeInputMilliseconds(now);
+ }
+
+ function relativeTime(milliseconds) {
+ var seconds = Math.abs(milliseconds) / 1000,
+ minutes = seconds / 60,
+ hours = minutes / 60,
+ days = hours / 24,
+ years = days / 365;
+ return seconds < 45 && substituteTimeAgo('s', ~~ seconds) ||
+ seconds < 90 && substituteTimeAgo('m') ||
+ minutes < 45 && substituteTimeAgo('mm', ~~ minutes) ||
+ minutes < 90 && substituteTimeAgo('h') ||
+ hours < 24 && substituteTimeAgo('hh', ~~ hours) ||
+ hours < 48 && substituteTimeAgo('d') ||
+ days < 25 && substituteTimeAgo('dd', ~~ days) ||
+ days < 45 && substituteTimeAgo('M') ||
+ days < 350 && substituteTimeAgo('MM', ~~ ((days + 15) / 30)) ||
+ years < 2 && substituteTimeAgo('y') ||
+ substituteTimeAgo('yy', ~~ years);
+ }
+
+ // _Date prototype object
+ function _Date(input) {
+ this.date = makeInputDate(input);
+ return this;
+ }
+
+ var _DateProto = _Date.prototype = {
+
+ format : function(inputString) {
+ // shortcuts to this and getting time functions
+ // done to save bytes in minification
+ var date = this.date,
+ currentMonth = date.getMonth(),
+ currentDate = date.getDate(),
+ currentYear = date.getFullYear(),
+ currentDay = date.getDay(),
+ currentHours = date.getHours(),
+ currentMinutes = date.getMinutes(),
+ currentSeconds = date.getSeconds(),
+ currentString = date.toString(),
+ charactersToReplace = /(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?)/g,
+ nonuppercaseLetters = /[^A-Z]/g;
+ // check if the character is a format
+ // return formatted string or non string.
+ //
+ // uses switch/case instead of an object of named functions (like http://phpjs.org/functions/date:380)
+ // for minification and performance
+ // see http://jsperf.com/object-of-functions-vs-switch for performance comparison
+ function replaceFunction(input) {
+ // create a couple variables to be used later inside one of the cases.
+ var a, b;
+ switch (input) {
+ // MONTH
+ case 'M' :
+ return currentMonth + 1;
+ case 'Mo' :
+ return (currentMonth + 1) + createOrdinal(currentMonth + 1);
+ case 'MM' :
+ return leftZeroFill(currentMonth + 1, 2);
+ case 'MMM' :
+ return wordsMonthsShort[currentMonth];
+ case 'MMMM' :
+ return wordsMonths[currentMonth];
+ // DAY OF MONTH
+ case 'D' :
+ return currentDate;
+ case 'Do' :
+ return currentDate + createOrdinal(currentDate);
+ case 'DD' :
+ return leftZeroFill(currentDate, 2);
+ // DAY OF YEAR
+ case 'DDD' :
+ a = new Date(currentYear, currentMonth, currentDate);
+ b = new Date(currentYear, 0, 1);
+ return ~~ (((a - b) / 864e5) + 1.5);
+ case 'DDDo' :
+ a = replaceFunction('DDD');
+ return a + createOrdinal(a);
+ case 'DDDD' :
+ return leftZeroFill(replaceFunction('DDD'), 3);
+ // WEEKDAY
+ case 'd' :
+ return currentDay;
+ case 'do' :
+ return currentDay + createOrdinal(currentDay);
+ case 'ddd' :
+ return wordsWeekdaysShort[currentDay];
+ case 'dddd' :
+ return wordsWeekdays[currentDay];
+ // WEEK OF YEAR
+ case 'w' :
+ a = new Date(currentYear, currentMonth, currentDate - currentDay + 5);
+ b = new Date(a.getFullYear(), 0, 4);
+ return ~~ ((a - b) / 864e5 / 7 + 1.5);
+ case 'wo' :
+ a = replaceFunction('w');
+ return a + createOrdinal(a);
+ case 'ww' :
+ return leftZeroFill(replaceFunction('w'), 2);
+ // YEAR
+ case 'YY' :
+ return (currentYear + '').slice(-2);
+ case 'YYYY' :
+ return currentYear;
+ // AM / PM
+ case 'a' :
+ return currentHours > 11 ? 'pm' : 'am';
+ case 'A' :
+ return currentHours > 11 ? 'PM' : 'AM';
+ // 24 HOUR
+ case 'H' :
+ return currentHours;
+ case 'HH' :
+ return leftZeroFill(currentHours, 2);
+ // 12 HOUR
+ case 'h' :
+ return currentHours % 12 || 12;
+ case 'hh' :
+ return leftZeroFill(currentHours % 12 || 12, 2);
+ // MINUTE
+ case 'm' :
+ return currentMinutes;
+ case 'mm' :
+ return leftZeroFill(currentMinutes, 2);
+ // SECOND
+ case 's' :
+ return currentSeconds;
+ case 'ss' :
+ return leftZeroFill(currentSeconds, 2);
+ // TIMEZONE
+ case 'z' :
+ return replaceFunction('zz').replace(nonuppercaseLetters, '');
+ case 'zz' :
+ a = currentString.indexOf('(');
+ if (a > -1) {
+ return currentString.slice(a + 1, currentString.indexOf(')'));
+ }
+ return currentString.slice(currentString.indexOf(':')).replace(nonuppercaseLetters, '');
+ // DEFAULT
+ default :
+ return input.replace("\\", "");
+ }
+ }
+ return inputString.replace(charactersToReplace, replaceFunction);
+ },
+ add : function(input) {
+ return dateAddRemove(this, input, 1);
+ },
+ subtract : function(input) {
+ return dateAddRemove(this, input, -1);
+ },
+ customize : function(input) {
+ var inputOrdinal = input.ordinal,
+ inputRelativeTime = input.relativeTime;
+ if (input.weekdays) {
+ wordsWeekdays = input.weekdays;
+ }
+ if (input.weekdaysShort) {
+ wordsWeekdaysShort = input.weekdaysShort;
+ }
+ if (input.months) {
+ wordsMonths = input.months;
+ }
+ if (input.monthsShort) {
+ wordsMonthsShort = input.monthsShort;
+ }
+ if (inputRelativeTime) {
+ for (var key in inputRelativeTime) {
+ if (inputRelativeTime.hasOwnProperty(key)) {
+ wordsTimeAgo[key] = inputRelativeTime[key];
+ }
+ }
+ }
+ if (inputOrdinal && inputOrdinal instanceof Function) {
+ createOrdinal = inputOrdinal;
+ }
+ },
+ from : function(time, withoutSuffix, asMilliseconds) {
+ var difference = msApart(this.date, time),
+ string = difference < 0 ? wordsTimeAgo.past : wordsTimeAgo.future;
+ return asMilliseconds ? difference :
+ withoutSuffix ? relativeTime(difference) :
+ string.replace(/%s/i, relativeTime(difference));
+ },
+ fromNow : function(withoutSuffix, asMilliseconds) {
+ return this.from(_date.now(), withoutSuffix, asMilliseconds);
+ },
+ isLeapYear : function() {
+ return _date.isLeapYear(this.date.getFullYear());
+ }
+ };
+
+ _date = {
+ date : function(input) {
+ return new _Date(input);
+ },
+ now : function(asTimestamp) {
+ return asTimestamp ? new Date().getTime() : _date.date();
+ },
+ isLeapYear : function(year) {
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+ }
+ };
+
+ // CommonJS module is defined
+ if (typeof window === 'undefined' && typeof module !== 'undefined') {
+ // Export module
+ module.exports = _date;
+ // Integrate with Underscore.js
+ } else if (root._ !== undefined) {
+ root._.mixin(_date);
+ // Or define it
+ } else {
+ root._ = _date;
+ }
+
+}());
--- /dev/null
+(function(a){function t(a){this.date=o(a);return this}function s(a){var b=Math.abs(a)/1e3,c=b/60,d=c/60,e=d/24,f=e/365;return b<45&&q("s",~~b)||b<90&&q("m")||c<45&&q("mm",~~c)||c<90&&q("h")||d<24&&q("hh",~~d)||d<48&&q("d")||e<25&&q("dd",~~e)||e<45&&q("M")||e<350&&q("MM",~~((e+15)/30))||f<2&&q("y")||q("yy",~~f)}function r(a,b){return p(a)-p(b)}function q(a,b){return i[a].replace(/%d/i,b||1)}function p(a){return isNaN(a)?o(a).getTime():a}function o(b){return b===a?new Date:b instanceof t?b.date:b instanceof Date?b:n(b)&&b.length>2?m(b):new Date(b)}function n(a){return Object.prototype.toString.call(a)==="[object Array]"}function m(a){return new Date(a[0],a[1]||0,a[2]||1,a[3]||0,a[4]||0,a[5]||0,a[6]||0)}function l(a,b,c){var d=a.date,e=(b.ms||0)+(b.s||0)*1e3+(b.m||0)*6e4+(b.h||0)*36e5+(b.d||0)*864e5+(b.w||0)*6048e5,f=(b.M||0)+(b.y||0)*12,g;e&&d.setMilliseconds(d.getMilliseconds()+e*c),f&&(g=d.getDate(),d.setDate(1),d.setMonth(d.getMonth()+f*c),d.setDate(Math.min((new Date(d.getFullYear(),d.getMonth()+1,0)).getDate(),g)));return a}function k(a,b){var c=a+"";while(c.length<b)c="0"+c;return c}var b=this,c=this,d,e=["January","February","March","April","May","June","July","August","September","October","November","December"],f=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],g=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],h=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],i={future:"in %s",past:"%s ago",s:"seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},j=function(a){var b=a%10;return~~(a%100/10)===1?"th":b===1?"st":b===2?"nd":b===3?"rd":"th"},u=t.prototype={format:function(a){function s(a){var b,q;switch(a){case"M":return c+1;case"Mo":return c+1+j(c+1);case"MM":return k(c+1,2);case"MMM":return f[c];case"MMMM":return e[c];case"D":return d;case"Do":return d+j(d);case"DD":return k(d,2);case"DDD":b=new Date(i,c,d),q=new Date(i,0,1);return~~((b-q)/864e5+1.5);case"DDDo":b=s("DDD");return b+j(b);case"DDDD":return k(s("DDD"),3);case"d":return l;case"do":return l+j(l);case"ddd":return h[l];case"dddd":return g[l];case"w":b=new Date(i,c,d-l+5),q=new Date(b.getFullYear(),0,4);return~~((b-q)/864e5/7+1.5);case"wo":b=s("w");return b+j(b);case"ww":return k(s("w"),2);case"YY":return(i+"").slice(-2);case"YYYY":return i;case"a":return m>11?"pm":"am";case"A":return m>11?"PM":"AM";case"H":return m;case"HH":return k(m,2);case"h":return m%12||12;case"hh":return k(m%12||12,2);case"m":return n;case"mm":return k(n,2);case"s":return o;case"ss":return k(o,2);case"z":return s("zz").replace(r,"");case"zz":b=p.indexOf("(");if(b>-1)return p.slice(b+1,p.indexOf(")"));return p.slice(p.indexOf(":")).replace(r,"");default:return a.replace("\\","")}}var b=this.date,c=b.getMonth(),d=b.getDate(),i=b.getFullYear(),l=b.getDay(),m=b.getHours(),n=b.getMinutes(),o=b.getSeconds(),p=b.toString(),q=/(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?)/g,r=/[^A-Z]/g;return a.replace(q,s)},add:function(a){return l(this,a,1)},subtract:function(a){return l(this,a,-1)},customize:function(a){var b=a.ordinal,c=a.relativeTime;a.weekdays&&(g=a.weekdays),a.weekdaysShort&&(h=a.weekdaysShort),a.months&&(e=a.months),a.monthsShort&&(f=a.monthsShort);if(c)for(var d in c)c.hasOwnProperty(d)&&(i[d]=c[d]);b&&b instanceof Function&&(j=b)},from:function(a,b,c){var d=r(this.date,a),e=d<0?i.past:i.future;return c?d:b?s(d):e.replace(/%s/i,s(d))},fromNow:function(a,b){return this.from(d.now(),a,b)},isLeapYear:function(){return d.isLeapYear(this.date.getFullYear())}};d={date:function(a){return new t(a)},now:function(a){return a?(new Date).getTime():d.date()},isLeapYear:function(a){return a%4===0&&a%100!==0||a%400===0}},typeof window=="undefined"&&typeof module!="undefined"?module.exports=d:b._!==a?b._.mixin(d):b._=d})()
\ No newline at end of file