From: Tim Wood Date: Mon, 2 May 2011 17:53:27 +0000 (-0700) Subject: Added to npm. Removed dependancy on underscore. Now, underscore.date can be used... X-Git-Tag: 0.4.0~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02bb265a0c11377737643d1575ed323803cb2554;p=thirdparty%2Fmoment.git Added to npm. Removed dependancy on underscore. Now, underscore.date can be used independantly from underscore --- diff --git a/build.js b/build.js new file mode 100755 index 000000000..672bdb617 --- /dev/null +++ b/build.js @@ -0,0 +1,19 @@ +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); +})(); diff --git a/lib/underscore.date.js b/lib/underscore.date.js deleted file mode 100644 index 8e8ef82a4..000000000 --- a/lib/underscore.date.js +++ /dev/null @@ -1,317 +0,0 @@ -// 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, _)); diff --git a/lib/underscore.date.min.js b/lib/underscore.date.min.js deleted file mode 100644 index 885e2fe63..000000000 --- a/lib/underscore.date.min.js +++ /dev/null @@ -1,8 +0,0 @@ -// 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.length11?"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,_) diff --git a/package.json b/package.json new file mode 100755 index 000000000..ba5379b47 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "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 (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" } + ] +} diff --git a/test/customize.html b/test/customize.html index 5fd882fda..ff7f2e615 100644 --- a/test/customize.html +++ b/test/customize.html @@ -4,7 +4,6 @@ Underscore.date customization test suite - diff --git a/test/customizeDate.js b/test/customizeDate.js index 5cb92c438..01e1ea736 100644 --- a/test/customizeDate.js +++ b/test/customizeDate.js @@ -1,5 +1,7 @@ $(function() { + _ = _date; + module("Customize"); _.date().customize({ diff --git a/test/customizePartial.html b/test/customizePartial.html index 2c2c9361c..3f754bfae 100644 --- a/test/customizePartial.html +++ b/test/customizePartial.html @@ -4,7 +4,6 @@ Underscore.date customization test suite - diff --git a/test/customizePartial.js b/test/customizePartial.js index 12c3601e9..71f61b205 100644 --- a/test/customizePartial.js +++ b/test/customizePartial.js @@ -1,18 +1,20 @@ $(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'; @@ -39,22 +41,22 @@ $(function() { 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"); }); }); diff --git a/test/date.js b/test/date.js index 3f660fbd9..479a0a30f 100644 --- a/test/date.js +++ b/test/date.js @@ -1,13 +1,15 @@ $(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()"); }); @@ -37,9 +39,9 @@ $(function() { }); 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"); }); diff --git a/test/speed.js b/test/speed.js index 671e693f9..c8cb5604e 100644 --- a/test/speed.js +++ b/test/speed.js @@ -1,5 +1,7 @@ (function() { + _ = _date; + var date1 = new Date(2010, 2, 6, 15, 25, 50, 125), date2 = new Date(1000), rt1 = 1000 * 60 * 60 * 24 * 365 * 5, diff --git a/test/test.html b/test/test.html index c69879082..8315a4a40 100644 --- a/test/test.html +++ b/test/test.html @@ -4,7 +4,6 @@ Underscore.date test suite - diff --git a/underscore.date.js b/underscore.date.js new file mode 100644 index 000000000..64c48a6e8 --- /dev/null +++ b/underscore.date.js @@ -0,0 +1,338 @@ +// 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; + } + +}()); diff --git a/underscore.date.min.js b/underscore.date.min.js new file mode 100644 index 000000000..4be77a9c8 --- /dev/null +++ b/underscore.date.min.js @@ -0,0 +1 @@ +(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.length11?"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