UNPKG

@fto-consult/common

Version:

Un ensemble de bibliothèques et d'utilistaires communs pour le développement d'applications javascript

210 lines (187 loc) • 6.38 kB
let AM = 'am', PM = 'pm' , periodRegex = new RegExp('([ap](\\.?)(m\\.?)?)', 'i') , timeRegex = new RegExp('^(10|11|12|0?[1-9])(?::|\\.)?([0-5][0-9])?' + periodRegex.source + '?$', 'i') , formatRegex = new RegExp('^(h|hh)([:|\.])?(mm)?( ?)' + periodRegex.source + '?$', 'i'); /* * Time constructor works with(out) 'new' * @see : https://github.com/zackdever/time * @time (optional) string or number representing a time. * e.g. 7, 1234, '7', '7:00', '12.14' * * If not provided, current time is used. var t = Time('2p'); t.hours(); // 2 t.minutes(); // 0 t.period(); // 'pm' t.toString(); // '2:00 pm' t.nextDate(); // Sep 10 2:00 (assuming it is 1 o'clock Sep 10) t.format('hh:mm AM') // '02:00 PM' t.isValid(); // true Time.isValid('99:12'); // false */ export default function Time(time) { if (!(this instanceof Time)) return new Time(time); var hours, minutes, period = null; if (time) { var result = timeRegex.exec(sanitize(time)); if (result) { hours = parseInt(result[1], 10); minutes = result[2] ? parseInt(result[2], 10) : 0; period = parsePeriod(result[3]); } } else { // set to current time var d = new Date(); hours = d.getHours(); period = hours > 11 ? PM : AM; if (hours > 12) hours -= 12; if (hours === 0) hours = 12; minutes = d.getMinutes(); } // gets or sets hours this.hours = function(newHours) { if (!newHours) return hours; hours = parseInt(newHours, 10); }; // gets or sets minutes this.minutes = function(newMinutes) { if (!newMinutes) return minutes; minutes = parseInt(newMinutes, 10); }; // gets or sets period this.period = function(newPeriod) { if (!newPeriod) return period; period = parsePeriod(newPeriod); }; } Time.prototype.toDate = function(){ return new Date(0,0,0,this.hours(),this.minutes(),this.seconds()); } /* * Find the next immediate corresponding Date. * * Assume it's 3:15 pm Aug 10: * Time('3:15').nextDate() // 3:15 pm Aug 10 * Time('415').nextDate() // 4:15 pm Aug 10 * Time('2').nextDate() // 2:00 am Aug 11 */ Time.prototype.nextDate = function () { if (!this.isValid()) return null; var hours = this.hours() === 12 ? 0 : this.hours(); // uniformly handle am/pm adjustments if (this.period() === PM) hours += 12; var d = new Date(); d.setHours(hours); d.setMinutes(this.minutes()); d.setSeconds(0); d.setMilliseconds(0); // if it has already passed, add 12 hours at a time until it's in the future 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) return d; }; Time.isValid = function(time) { return timeRegex.test(sanitize(time)); }; Time.prototype.isValid = function() { return Time.isValid(toString(this)); }; /* * 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) { format = format || Time.DEFAULT_TIME_FORMAT; if (!this.isValid()) { return 'invalid time'; } else if (!formatRegex.test(format)) { return 'invalid format'; } return toString(this, format); }; /* * Alias for `format`. */ Time.prototype.toString = Time.prototype.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, format) { format = format || Time.DEFAULT_TIME_FORMAT; var bits = formatRegex.exec(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(); // show if in the format or if non-zero and middlebit is provided var minutes = (fMinutes || (fMiddlebit && time.minutes() !== 0)) ? padTime(time.minutes()) : ''; // show middlebit if we have minutes var middlebit = (minutes && fMiddlebit) ? fMiddlebit : ''; // show period if available and requested var period = ''; if (fPeriod && time.period()) { var firstPeriod = time.period().charAt(0); if (fPeriod.charAt(0) === fPeriod.charAt(0).toUpperCase()) { firstPeriod = firstPeriod.toUpperCase(); } period = firstPeriod + fPeriod.slice(1); } // only show space if it was requested by format and there's a period var space = (period && fPeriodSpace) ? fPeriodSpace : ''; return '' + hours + middlebit + minutes + space + period; } function padTime(time) { return time < 10 ? '0' + time : time; } /* * (private) Force @time to a string and remove all whitespace. * * @time input * @retun input as a string, with all white space removed */ function sanitize(time) { return time.toString().replace(/\s/g, ''); } /* * (private) */ 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; }