Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first stab at format support. no new tests, but existing ones pass.

  • Loading branch information...
commit 8b5ba3f524c390564d0c6655a2fd2be931b9c89b 1 parent b35a063
Zack Dever authored
Showing with 94 additions and 27 deletions.
  1. +94 −27 time.js
121 time.js
View
@@ -1,10 +1,12 @@
-(function() {
+(function () {
- var am = 'am'
- , pm = 'pm'
- , periodRegex = new RegExp('([ap]\\.?(m\\.?)?)', 'i')
+ var AM = 'am'
+ , PM = 'pm'
+ , periodRegex = new RegExp('([ap](\\.?)(m\\.?)?)', 'i')
, timeRegex = new RegExp('^(10|11|12|[1-9])(?::|\\.)?([0-5][0-9])?'
- + periodRegex.source + '?$', 'i');
+ + periodRegex.source + '?$', 'i')
+ , formatRegex = new RegExp('^(h|hh)([:|\.])?(mm)?( ?)'
+ + periodRegex.source + '?$', 'i');
// play nice with both node.js and browser
if (typeof module !== 'undefined' && module.exports) module.exports = Time;
@@ -34,7 +36,7 @@
// set to current time
var d = new Date();
hours = d.getHours();
- period = hours > 11 ? pm : am;
+ period = hours > 11 ? PM : AM;
if (hours > 12) hours -= 12;
if (hours === 0) hours = 12;
minutes = d.getMinutes();
@@ -44,19 +46,19 @@
this.hours = function(newHours) {
if (!newHours) return hours;
hours = parseInt(newHours);
- }
+ };
// gets or sets minutes
this.minutes = function(newMinutes) {
if (!newMinutes) return minutes;
minutes = parseInt(newMinutes);
- }
+ };
// gets or sets period
this.period = function(newPeriod) {
if (!newPeriod) return period;
period = parsePeriod(newPeriod);
- }
+ };
}
/*
@@ -71,7 +73,7 @@
if (!this.isValid()) return null;
var hours = this.hours() === 12 ? 0 : this.hours(); // uniformly handle am/pm adjustments
- if (this.period() === pm) hours += 12;
+ if (this.period() === PM) hours += 12;
var d = new Date();
d.setHours(hours);
d.setMinutes(this.minutes());
@@ -82,41 +84,106 @@
while (new Date() > d) d.setHours(d.getHours() + 12);
// make sure we're in the correct period
- if (d.getHours() > 11 && this.period() === am) d.setHours(d.getHours() + 12)
- else if (d.getHours() < 12 && this.period() === pm) d.setHours(d.getHours() + 12)
+ if (d.getHours() > 11 && this.period() === AM) d.setHours(d.getHours() + 12)
+ else if (d.getHours() < 12 && this.period() === PM) d.setHours(d.getHours() + 12)
return d;
- }
+ };
Time.isValid = function(time) {
return timeRegex.test(sanitize(time));
- }
+ };
Time.prototype.isValid = function() {
return Time.isValid(toString(this));
- }
+ };
/*
- * h:mm
+ * Alias for `format`.
*/
- Time.prototype.toString = function() {
- if (!this.isValid()) return 'invalid time'
- return toString(this);
- }
+ Time.prototype.toString = Time.prototype.format;
/*
- * (private) Format Time into hh:mm for validation test.
+ * This can be safely changed if so desired.
+ */
+ Time.DEFAULT_TIME_FORMAT = 'h:mm am';
+
+ /*
+ * Formats the time to the given format, or h:mm if one is not provided.
+ *
+ * If periods are specified in the format, they are only printed if known.
+ *
+ * If the time isn't valid, return 'invalid time'.
+ * If the format isn't valid, return 'invalid format'.
+ *
+ * This isn't every combination, but hopefully you get the gist of things.
+ * h:mm 12:00 (default)
+ * hh:mm 01:00
+ * h 1
+ * h 1:55 (input specified minutes, so we show them)
+ * h. 1.55 (if minutes are shown, use . for separator)
+ * hpm 1am
+ * h:mm a 1:55 p
+ * h:mm a 1:55 (input didn't specify period)
+ * h.mm am 1.55 pm
+ * h.mm A 1.55 P
+ * hh:mm a.m. 01:55 a.m.
+ * h:mma 1:55a
+ * h.mm 1.55
+ */
+ Time.prototype.format = function(format) {
+ if (!this.isValid()) {
+ return 'invalid time';
+ } else if (!timeRegex.test(format)) {
+ return 'invalid format';
+ }
+ return toString(this, format);
+ };
+
+ /*
+ * (private) Format Time in the given format.
*
* @time Time instance
* @retun hh:mm e.g. 3:00, 12:23, undefined:undefined
*/
- function toString(time) {
- var minutes = time.minutes() < 10 ? '0' + time.minutes() : time.minutes()
- , result = time.hours() + ':' + minutes;
+ function toString(time, format) {
+ var bits = formatRegex.exec(format || Time.DEFAULT_TIME_FORMAT);
+ var fHour = bits[1];
+ var fMiddlebit = bits[2];
+ var fMinutes = bits[3];
+ var fPeriodSpace = bits[4];
+ var fPeriod = bits[5];
+ var fFirstPeriod = bits[6];
+ var fPeriodM = bits[7];
+
+ // always show hour
+ var hours = fHour.length == 2 ? padTime(time.hours()) : time.hours();
+
+ // only hide minutes if they aren't in the format, and not 0
+ var minutes = (fMinutes || time.minutes()) ? padTime(time.minutes()) : '';
+
+ // only show middlebit if we have minutes
+ var middlebit = minutes ? fMiddlebit : '';
+
+ // always show period if available
+ var period = (time.period() == undefined) ? '' : time.period();
+ if (period) {
+ var firstPeriod = period.charAt(0);
+ if (fPeriod.charAt(0) === fPeriod.charAt(0).toUpperCase()) {
+ firstPeriod = firstPeriod.toUpperCase();
+ }
+ period = firstPeriod + fPeriod.slice(1);
+ }
- return (time.period() == undefined) ? result : result + ' ' + time.period();
+ // only show space if it was requested by format and there's a period
+ var space = (period && fPeriodSpace) ? fPeriodSpace : '';
+
+ return '' + hours + middlebit + minutes + period;
}
+ function padTime(time) {
+ return time < 10 ? '0' + time : time;
+ }
/*
* (private) Force @time to a string and remove all whitespace.
*
@@ -132,7 +199,7 @@
*/
function parsePeriod(period) {
if (!period || !period.match(periodRegex)) return null;
- else if (period.match(/^p/i) != null) return pm;
- return (period.match(/^a/i) != null) ? am : null;
+ else if (period.match(/^p/i) != null) return PM;
+ return (period.match(/^a/i) != null) ? AM : null;
}
})();
Please sign in to comment.
Something went wrong with that request. Please try again.