Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

* First commit

  • Loading branch information...
commit 3a05dddb2354f0511589f7a34fb57b2e3c2fb72e 0 parents
@joehewitt authored
3  .gitignore
@@ -0,0 +1,3 @@
+node_modules
+build*
+*.o
13 LICENSE
@@ -0,0 +1,13 @@
+Copyright 2011 Joe Hewitt
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
6 Makefile
@@ -0,0 +1,6 @@
+default: test
+
+test:
+ vows test/*-test.js
+
+.PHONY: test
26 README.md
@@ -0,0 +1,26 @@
+datetime
+========
+
+A date and time library.
+
+Installation
+------------
+
+ $ npm install datetime
+
+License
+-------
+
+Copyright 2011 Joe Hewitt
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
227 lib/datetime.js
@@ -0,0 +1,227 @@
+
+var locales = {
+ 'en-US': {
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ dayNamesAbbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August",
+ "September", "October", "November", "December"],
+ monthNamesAbbreviated: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ ampm: {'AM': 'AM', 'PM': 'PM'},
+
+ daySuffixes: {1: 'st', 2: 'nd', 3: 'rd', 4: 'th'},
+
+ dateTimeFormat: '%a %d %b %Y %T %Z',
+ dateFormat: '%d/%m/%y',
+ timeFormat: '%T',
+
+ secondAgo: 'a second ago',
+ secondsAgo: '%t seconds ago',
+ minuteAgo: 'a minute ago',
+ minutesAgo: '%t minutes ago',
+ hourAgo: 'an hour ago',
+ hoursAgo: '%t hours ago',
+ dayAgo: 'a day ago',
+ daysAgo: '%t days ago',
+ dayAgo: 'a day ago',
+ daysAgo: '%t days ago',
+ }
+};
+
+
+function getLocale(locale) {
+ return locales[locale] || locales['en-US'];
+}
+
+// *************************************************************************************************
+
+var formatRegex = /%([a-zA-Z%])/;
+
+var formatters = {
+ 'a': function(d, locale) {
+ return locale.dayNamesAbbreviated[d.getDay()];
+ },
+ 'A': function(d, locale) {
+ return locale.dayNames[d.getDay()];
+ },
+ 'b': function(d, locale) {
+ return locale.monthNamesAbbreviated[d.getMonth()];
+ },
+ 'B': function(d, locale) {
+ return locale.monthNames[d.getMonth()];
+ },
+ 'c': function(d, locale, t, l) {
+ return exports.format(d, locale.dateTimeFormat, t, l);
+ },
+ 'C': function(d, locale, t, l) {
+ return ''; // XXXjoe Century number
+ },
+ 'd': function(d, locale) {
+ return leadingZero(d.getDate());
+ },
+ 'D': function(d, locale, t, l) {
+ return exports.format(d, '%m/%d/%y', t, l);
+ },
+ 'e': function(d, locale) {
+ return leadingZero(d.getDate(), ' ');
+ },
+ 'g': function(d, locale) {
+ return ''; // XXXjoe year, different standard
+ },
+ 'G': function(d, locale) {
+ return ''; // XXXjoe year, different standard
+ },
+ 'h': function(d, locale) {
+ return this.b.apply(this, arguments);
+ },
+ 'H': function(d, locale) {
+ return leadingZero(d.getHours());
+ },
+ 'I': function(d, locale) {
+ var h = d.getHours();
+ var H = h == 0 || h == 12 ? 12 : h % 12;
+ return leadingZero(H);
+ },
+ 'j': function(d, locale) {
+ return ''; // XXXjoe Day of the year (001 - 366)
+ },
+ 'm': function(d, locale) {
+ return leadingZero(d.getMonth()+1);
+ },
+ 'M': function(d, locale) {
+ return leadingZero(d.getMinutes());
+ },
+ 'p': function(d, locale) {
+ return d.getHours() < 12 ? locale.ampm['AM'] : locale.ampm['PM'];
+ },
+ 'P': function(d, locale) {
+ return this.p.apply(this, arguments).toLowerCase();
+ },
+ 'r': function(d, locale, t, l) {
+ return exports.format(d, '%I:%M:%S %p', t, l);
+ },
+ 'R': function(d, locale, t, l) {
+ return exports.format(d, '%H:%M', t, l);
+ },
+ 'S': function(d, locale) {
+ return leadingZero(d.getSeconds());
+ },
+ 'T': function(d, locale, t, l) {
+ return exports.format(d, '%H:%M:%S', t, l);
+ },
+ 'u': function(d, locale) {
+ return d.getDay()+1;
+ },
+ 'U': function(d, locale) {
+ return ''; // XXXjoe Week number of year
+ },
+ 'V': function(d, locale) {
+ return ''; // XXXjoe Week number of year, different standard
+ },
+ 'w': function(d, locale) {
+ return d.getDay();
+ },
+ 'W': function(d, locale) {
+ return ''; // XXXjoe Week number of year, different standard
+ },
+ 'x': function(d, locale, t, l) {
+ return exports.format(d, locale.dateFormat, t, l);
+ },
+ 'X': function(d, locale, t, l) {
+ return exports.format(d, locale.timeFormat, t, l);
+ },
+ 'y': function(d, locale) {
+ return leadingZero(d.getYear() - 100);
+ },
+ 'Y': function(d, locale) {
+ return d.getFullYear();
+ },
+ 'z': function(d, locale) {
+ var offset = d.getTimezoneOffset();
+ var hour = leadingZero(Math.round(Math.abs(offset / 60)));
+ var min = leadingZero(offset % 60);
+ return (offset > 0 ? '-' : '+') + hour + min;
+ },
+ 'Z': function(d, locale) {
+ return d.toString().replace(/^.*\(([^)]+)\)$/, '$1');
+ },
+ '%': function(d, locale) {
+ return '%';
+ },
+
+ // NON-STANDARD ADDITIONS
+ 'i': function(d, locale) {
+ var h = d.getHours();
+ return h == 0 || h == 12 ? 12 : h % 12;
+ },
+
+ 'k': function(d, locale) {
+ var day = d.getDate();
+ if (day in locale.daySuffixes) {
+ return locale.daySuffixes[day];
+ } else {
+ return locale.daySuffixes[4];
+ }
+ },
+};
+
+function leadingZero(n, leading) {
+ return n > 10 ? n : (leading ? leading : '0')+n;
+}
+
+// *************************************************************************************************
+
+var second = exports.second = 1000;
+var minute = exports.minute = second*60;
+var hour = exports.hour = minute*60;
+var day = exports.day = hour*24;
+var week = exports.week = day*7;
+
+// *************************************************************************************************
+
+exports.format = function(d, format, timezone, locale) {
+ var localeData = getLocale(locale);
+ var parts = [];
+ var separated = format.split(formatRegex);
+ for (var i = 0; i < separated.length; ++i) {
+ var part = separated[i];
+ if (part) {
+ var formatter = formatters[part];
+ if (formatter) {
+ parts.push(formatter.apply(formatters, [d, localeData, timezone, locale]));
+ } else {
+ parts.push(part);
+ }
+ }
+ }
+ return parts.join('');
+};
+
+exports.formatAgo = function(d, timezone, baseTime, locale) {
+ var localeData = getLocale(locale);
+ if (!baseTime) {
+ baseTime = new Date();
+ }
+
+ var delta = baseTime - d;
+ if (delta < minute) {
+ var n = Math.round(delta/second);
+ var format = n == 1 ? localeData.secondAgo : localeData.secondsAgo;
+ return format.replace('%t', n);
+ } else if (delta < hour) {
+ var n = Math.round(delta/minute);
+ var format = n == 1 ? localeData.minuteAgo : localeData.minutesAgo;
+ return format.replace('%t', n);
+ } else if (delta < day) {
+ var n = Math.round(delta/hour);
+ var format = n == 1 ? localeData.hourAgo : localeData.hoursAgo;
+ return format.replace('%t', n);
+ } else if (delta < week) {
+ return exports.format(d, '%A at %i:%M%P', timezone, locale);
+ } else if (d.getYear() == baseTime.getYear()) {
+ return exports.format(d, '%B%e%k at %i:%M%P', timezone, locale);
+ } else {
+ return exports.format(d, '%B%e%k, %Y at %i:%M%P', timezone, locale);
+ }
+};
13 package.json
@@ -0,0 +1,13 @@
+{
+ "name": "datetime",
+ "description": "Date and time formatting",
+ "url": "http://github.com/joehewitt/datetime",
+ "keywords": ["date", "time"],
+ "author": "Joe Hewitt <joe@joehewitt.com>",
+ "contributors": [],
+ "dependencies": {"vows": ">=0.5.4"},
+ "version": "0.0.1",
+ "main": "./lib/datetime",
+ "directories": { "test": "./test" },
+ "engines": { "node": ">=0.4.0" }
+}
288 test/datetime-test.js
@@ -0,0 +1,288 @@
+var path = require('path'),
+ assert = require('assert'),
+ vows = require('vows');
+
+require.paths.unshift(path.join(__dirname, '..', 'lib'));
+
+var datetime = require('datetime');
+
+// *************************************************************************************************
+
+vows.describe('datetime basics').addBatch({
+ 'A time in PM': {
+ topic: new Date('March 5, 2008 3:01:04 PM'),
+
+ 'with %a': function(topic) {
+ assert.equal(datetime.format(topic, '%a'), 'Wed');
+ },
+
+ 'with %A': function(topic) {
+ assert.equal(datetime.format(topic, '%A'), 'Wednesday');
+ },
+
+ 'with %b': function(topic) {
+ assert.equal(datetime.format(topic, '%b'), 'Mar');
+ },
+
+ 'with %B': function(topic) {
+ assert.equal(datetime.format(topic, '%B'), 'March');
+ },
+
+ 'with %c': function(topic) {
+ assert.equal(datetime.format(topic, '%c'), 'Wed 05 Mar 2008 15:01:04 PST');
+ },
+
+ 'with %C': function(topic) {
+ assert.equal(datetime.format(topic, '%C'), '?');
+ },
+
+ 'with %d': function(topic) {
+ assert.equal(datetime.format(topic, '%d'), '05');
+ },
+
+ 'with %D': function(topic) {
+ assert.equal(datetime.format(topic, '%D'), '03/05/08');
+ },
+
+ 'with %e': function(topic) {
+ assert.equal(datetime.format(topic, '%e'), ' 5');
+ },
+
+ 'with %g': function(topic) {
+ assert.equal(datetime.format(topic, '%g'), '?');
+ },
+
+ 'with %G': function(topic) {
+ assert.equal(datetime.format(topic, '%G'), '?');
+ },
+
+ 'with %h': function(topic) {
+ assert.equal(datetime.format(topic, '%h'), 'Mar');
+ },
+
+ 'with %H': function(topic) {
+ assert.equal(datetime.format(topic, '%H'), '15');
+ },
+
+ 'with %I': function(topic) {
+ assert.equal(datetime.format(topic, '%I'), '03');
+ },
+
+ 'with %j': function(topic) {
+ assert.equal(datetime.format(topic, '%j'), '?');
+ },
+
+ 'with %m': function(topic) {
+ assert.equal(datetime.format(topic, '%m'), '03');
+ },
+
+ 'with %M': function(topic) {
+ assert.equal(datetime.format(topic, '%M'), '01');
+ },
+
+ 'with %p': function(topic) {
+ assert.equal(datetime.format(topic, '%p'), 'PM');
+ },
+
+ 'with %P': function(topic) {
+ assert.equal(datetime.format(topic, '%P'), 'pm');
+ },
+
+ 'with %r': function(topic) {
+ assert.equal(datetime.format(topic, '%r'), '03:01:04 PM');
+ },
+
+ 'with %R': function(topic) {
+ assert.equal(datetime.format(topic, '%R'), '15:01');
+ },
+
+ 'with %S': function(topic) {
+ assert.equal(datetime.format(topic, '%S'), '04');
+ },
+
+ 'with %T': function(topic) {
+ assert.equal(datetime.format(topic, '%T'), '15:01:04');
+ },
+
+ 'with %u': function(topic) {
+ assert.equal(datetime.format(topic, '%u'), '4');
+ },
+
+ 'with %U': function(topic) {
+ assert.equal(datetime.format(topic, '%U'), '?');
+ },
+
+ 'with %V': function(topic) {
+ assert.equal(datetime.format(topic, '%V'), '?');
+ },
+
+ 'with %w': function(topic) {
+ assert.equal(datetime.format(topic, '%w'), '3');
+ },
+
+ 'with %W': function(topic) {
+ assert.equal(datetime.format(topic, '%W'), '?');
+ },
+
+ 'with %x': function(topic) {
+ assert.equal(datetime.format(topic, '%x'), '05/03/08');
+ },
+
+ 'with %X': function(topic) {
+ assert.equal(datetime.format(topic, '%X'), '15:01:04');
+ },
+
+ 'with %y': function(topic) {
+ assert.equal(datetime.format(topic, '%y'), '08');
+ },
+
+ 'with %Y': function(topic) {
+ assert.equal(datetime.format(topic, '%Y'), '2008');
+ },
+
+ 'with %z': function(topic) {
+ assert.equal(datetime.format(topic, '%z'), '-0800');
+ },
+
+ 'with %Z': function(topic) {
+ assert.equal(datetime.format(topic, '%Z'), 'PST');
+ },
+
+ 'with %%': function(topic) {
+ assert.equal(datetime.format(topic, '%%'), '%');
+ },
+ },
+
+ 'A time in AM': {
+ topic: new Date('March 5, 2008 3:01:04 AM'),
+
+ 'with %H': function(topic) {
+ assert.equal(datetime.format(topic, '%H'), '03');
+ },
+
+ 'with %I': function(topic) {
+ assert.equal(datetime.format(topic, '%I'), '03');
+ },
+ },
+
+ 'A time at midnight': {
+ topic: new Date('March 3, 2008 12:01:04 AM'),
+
+ 'with %H': function(topic) {
+ assert.equal(datetime.format(topic, '%H'), '00');
+ },
+
+ 'with %I': function(topic) {
+ assert.equal(datetime.format(topic, '%I'), '12');
+ },
+ },
+
+ 'A time at noon': {
+ topic: new Date('March 3, 2008 12:01:04 PM'),
+
+ 'with %H': function(topic) {
+ assert.equal(datetime.format(topic, '%H'), '12');
+ },
+
+ 'with %I': function(topic) {
+ assert.equal(datetime.format(topic, '%I'), '12');
+ },
+ },
+
+ 'A day on the first': {
+ topic: new Date('March 1, 2008'),
+
+ 'with %k': function(topic) {
+ assert.equal(datetime.format(topic, '%k'), 'st');
+ },
+ },
+
+ 'A day on the second': {
+ topic: new Date('March 2, 2008'),
+
+ 'with %k': function(topic) {
+ assert.equal(datetime.format(topic, '%k'), 'nd');
+ },
+ },
+
+ 'A day on the third': {
+ topic: new Date('March 3, 2008'),
+
+ 'with %k': function(topic) {
+ assert.equal(datetime.format(topic, '%k'), 'rd');
+ },
+ },
+
+ 'A day on the fourth': {
+ topic: new Date('March 4, 2008'),
+
+ 'with %k': function(topic) {
+ assert.equal(datetime.format(topic, '%k'), 'th');
+ },
+ },
+
+ 'A day on the fifth': {
+ topic: new Date('March 5, 2008'),
+
+ 'with %k': function(topic) {
+ assert.equal(datetime.format(topic, '%k'), 'th');
+ },
+ },
+
+ 'A time': {
+ topic: new Date('March 5, 2008'),
+
+ 'formatted with hyphens': function(topic) {
+ assert.equal(datetime.format(topic, '%Y-%m-%d'), '2008-03-05');
+ },
+ },
+
+ 'A time': {
+ topic: new Date('March 5, 2008 3:30 pm'),
+
+ 'at singular seconds ago': function(topic) {
+ var base = new Date('March 5, 2008 3:30:01 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'a second ago');
+ },
+
+ 'at plural seconds ago': function(topic) {
+ var base = new Date('March 5, 2008 3:30:15 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), '15 seconds ago');
+ },
+
+ 'at singular minutes ago': function(topic) {
+ var base = new Date('March 5, 2008 3:31 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'a minute ago');
+ },
+
+ 'at plural minutes ago': function(topic) {
+ var base = new Date('March 5, 2008 3:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), '15 minutes ago');
+ },
+
+ 'at singular hours ago': function(topic) {
+ var base = new Date('March 5, 2008 4:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'an hour ago');
+ },
+
+ 'at plural hours ago': function(topic) {
+ var base = new Date('March 5, 2008 5:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), '2 hours ago');
+ },
+
+ 'at a day ago': function(topic) {
+ var base = new Date('March 6, 2008 5:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'Wednesday at 3:30pm');
+ },
+
+ 'at a week ago': function(topic) {
+ var base = new Date('March 13, 2008 5:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'March 5th at 3:30pm');
+ },
+
+ 'at a year ago': function(topic) {
+ var base = new Date('March 13, 2009 5:45 pm');
+ assert.equal(datetime.formatAgo(topic, null, base), 'March 5th, 2008 at 3:30pm');
+ },
+ },
+}).export(module);
Please sign in to comment.
Something went wrong with that request. Please try again.