diff --git a/mods/js-date-format.js b/mods/js-date-format.js
new file mode 100644
index 0000000000000000000000000000000000000000..d21b35a596de445dfb56e21e6153e628882ef9c7
--- /dev/null
+++ b/mods/js-date-format.js
@@ -0,0 +1,290 @@
+/**
+* js-date-format (js-date-format.js)
+* v1.0
+* (c) Tony Brix (tonybrix.info) - 2014.
+* https://github.com/UziTech/js-date-format
+*
+* MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+* associated documentation files (the "Software"), to deal in the Software without restriction,
+* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+* subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial
+* portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+Date.prototype.setLocale = function (lang) {
+	if (lang && lang in Date.locales) {
+		this.locale = lang;
+	}
+};
+
+Date.prototype.getLocale = function () {
+	return this.locale || "en";
+};
+
+Date.prototype.getMonthName = function (lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].month_names[this.getMonth()];
+};
+
+Date.prototype.getMonthNameShort = function (lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].month_names_short[this.getMonth()];
+};
+
+Date.prototype.getDayName = function (lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].day_names[this.getDay()];
+};
+
+Date.prototype.getDayNameShort = function (lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].day_names_short[this.getDay()];
+};
+
+Date.prototype.getDateSuffix = function (lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].date_suffix(this.getDate());
+};
+
+Date.prototype.getMeridiem = function (isLower, lang) {
+	var locale = "en";
+	if (lang && lang in Date.locales) {
+		locale = lang;
+	} else if (this.locale && this.locale in Date.locales) {
+		locale = this.locale;
+	}
+	return Date.locales[locale].meridiem(this.getHours(), this.getMinutes(), isLower);
+};
+
+Date.prototype.getLastDate = function () {
+	return (new Date(this.getFullYear(), this.getMonth() + 1, 0)).getDate();
+};
+
+/* languages from http://momentjs.com */
+Date.locales = {
+	"en": {
+		month_names: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+		month_names_short: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+		day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+		day_names_short: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+		date_suffix: function (date) {
+			var day10 = ~~ (date % 100 / 10);
+			var day1 = date % 10;
+			if (day10 === 1) {
+				return "th";
+			} else if (day1 === 1) {
+				return "st";
+			} else if (day1 === 2) {
+				return "nd";
+			} else if (day1 === 3) {
+				return "rd";
+			} else {
+				return "th";
+			}
+		},
+		meridiem : function (hour, minute, isLower) {
+			if (hour < 12) {
+				return isLower ? "am" : "AM";
+			} else {
+				return isLower ? "pm" : "PM";
+			}
+		}
+	}
+};
+
+Date.prototype.format = function (formatString) {
+
+	var addPadding = function (value, length) {
+		var negative = ((value < 0) ? "-" : "");
+		var zeros = "0";
+		for (var i = 2; i < length; i++) {
+			zeros += "0";
+		}
+		return negative + (zeros + Math.abs(value).toString()).slice(-length);
+	};
+
+	var replacements = {
+		date: this,
+		YYYY: function () {
+			return this.date.getFullYear();
+		},
+		YY: function () {
+			return this.date.getFullYear() % 100;
+		},
+		MMMM: function () {
+			return this.date.getMonthName();
+		},
+		MMM: function () {
+			return this.date.getMonthNameShort();
+		},
+		MM: function () {
+			return addPadding((this.date.getMonth() + 1), 2);
+		},
+		M: function () {
+			return this.date.getMonth() + 1;
+		},
+		DDDD: function () {
+			return this.date.getDayName();
+		},
+		DDD: function () {
+			return this.date.getDayNameShort();
+		},
+		DD: function () {
+			return addPadding(this.date.getDate(), 2);
+		},
+		D: function () {
+			return this.date.getDate();
+		},
+		S: function () {
+			return this.date.getDateSuffix();
+		},
+		HH: function () {
+			return addPadding(this.date.getHours(), 2);
+		},
+		H: function () {
+			return this.date.getHours();
+		},
+		hh: function () {
+			var hour = this.date.getHours();
+			if (hour > 12) {
+				hour -= 12;
+			} else if (hour < 1) {
+				hour = 12;
+			}
+			return addPadding(hour, 2);
+		},
+		h: function () {
+			var hour = this.date.getHours();
+			if (hour > 12) {
+				hour -= 12;
+			} else if (hour < 1) {
+				hour = 12;
+			}
+			return hour;
+		},
+		mm: function () {
+			return addPadding(this.date.getMinutes(), 2);
+		},
+		m: function () {
+			return this.date.getMinutes();
+		},
+		ss: function () {
+			return addPadding(this.date.getSeconds(), 2);
+		},
+		s: function () {
+			return this.date.getSeconds();
+		},
+		fff: function () {
+			return addPadding(this.date.getMilliseconds(), 3);
+		},
+		ff: function () {
+			return addPadding(Math.floor(this.date.getMilliseconds() / 10), 2);
+		},
+		f: function () {
+			return Math.floor(this.date.getMilliseconds() / 100);
+		},
+		zzzz: function () {
+			return addPadding(Math.floor(-this.date.getTimezoneOffset() / 60), 2) + ":" + addPadding(-this.date.getTimezoneOffset() % 60, 2);
+		},
+		zzz: function () {
+			return Math.floor(-this.date.getTimezoneOffset() / 60) + ":" + addPadding(-this.date.getTimezoneOffset() % 60, 2);
+		},
+		zz: function () {
+			return addPadding(Math.floor(-this.date.getTimezoneOffset() / 60), 2);
+		},
+		z: function () {
+			return Math.floor(-this.date.getTimezoneOffset() / 60);
+		},
+		tt: function () {
+			return this.date.getMeridiem(true);
+		},
+		TT: function () {
+			return this.date.getMeridiem(false);
+		}
+	};
+
+
+	var formats = new Array();
+	while (formatString.length > 0) {
+		if (formatString[0] === "\"") {
+			var temp = /"[^"]*"/m.exec(formatString);
+			if (temp === null) {
+				formats.push(formatString.substring(1));
+				formatString = "";
+			} else {
+				temp = temp[0].substring(1, temp[0].length - 1);
+				formats.push(temp);
+				formatString = formatString.substring(temp.length + 2);
+			}
+		} else if (formatString[0] === "'") {
+			var temp = /'[^']*'/m.exec(formatString);
+			if (temp === null) {
+				formats.push(formatString.substring(1));
+				formatString = "";
+			} else {
+				temp = temp[0].substring(1, temp[0].length - 1);
+				formats.push(temp);
+				formatString = formatString.substring(temp.length + 2);
+			}
+		} else if (formatString[0] === "\\") {
+			if (formatString.length > 1) {
+				formats.push(formatString.substring(1, 2));
+				formatString = formatString.substring(2);
+			} else {
+				formats.push("\\");
+				formatString = "";
+			}
+		} else {
+			var foundMatch = false;
+			for (var i = formatString.length; i > 0; i--) {
+				if (formatString.substring(0, i) in replacements) {
+					formats.push(replacements[formatString.substring(0, i)]());
+					formatString = formatString.substring(i);
+					foundMatch = true;
+					break;
+				}
+			}
+			if (!foundMatch) {
+				formats.push(formatString[0]);
+				formatString = formatString.substring(1);
+			}
+		}
+	}
+
+	return formats.join("");
+};
\ No newline at end of file
diff --git a/web/root/pages/003_userlist.xjs b/web/root/pages/003_userlist.xjs
index ddb517f178e5ca45e6aafe180992c8d7a49f1fc3..246e0e37e193dd4641387bdd27b45e122354c2fd 100644
--- a/web/root/pages/003_userlist.xjs
+++ b/web/root/pages/003_userlist.xjs
@@ -22,6 +22,7 @@
 
 	// Most people won't need to edit below this line
 	load('sbbsdefs.js');
+	load('js-date-format.js');
 
 	if (typeof http_request.query.offset === 'undefined' ||
 		isNaN(parseInt(http_request.query.offset[0])) ||
@@ -166,13 +167,26 @@
 		for (var u = 0; u < users.length; u++) {
 			writeln('<tr>');
 			for (var c in columns) {
-				writeln(
-					'<td>' +
-					(	columns[c].type === 'date'
-						? system.timestr(users[u][c])
-						: users[u][c].toString()
-					) +	'</td>'
-				);
+				var cellString = '';
+				if ( columns[c].type === 'date' ) {
+					// Generate JS dates
+					var theDate = new Date( users[u][c] * 1000);
+					var todayDate = new Date();
+					// Find how many days between last login date and today.
+					var diff = (Math.abs(theDate.getTime() - todayDate.getTime()) ) / (1000 * 60 * 60 * 24);
+					// If the date is within the last week, print just the day of the week
+					if (diff < 8) {
+						cellString = theDate.getDayName();
+					}
+					// Otherwise, print a date
+					else {
+						cellString = theDate.format('MMM D, YYYY');
+					}
+				}
+				else {
+					cellString = users[u][c].toString();
+				}
+				writeln( '<td>' + cellString + '</td>' );
 			}
 			writeln('</tr>');
 		}