diff --git a/.codeclimate.yml b/.codeclimate.yml index 1dd4f75..9488f4c 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -5,6 +5,11 @@ engines: enabled: true eslint: enabled: true + checks: + complexity: + enabled: false + max-statements: + enabled: false fixme: enabled: true duplication: diff --git a/.gitignore b/.gitignore index bf5f217..3c5db2f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ bower_components node_modules +/coverage diff --git a/bower.json b/bower.json index 47d1c0f..fff6d9e 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "kairos", - "version": "1.1.0", + "version": "2.0.0", "description": "A non date-based time calculator", "homepage": "https://github.com/kairos", "repository": { @@ -29,7 +29,7 @@ "test" ], "devDependencies": { - "mocha": "~2.3.4", + "mocha": "~2.4.5", "assert": "~0.1.0" } } diff --git a/build/kairos-debug.js b/build/kairos-debug.js index 96c4a01..535393c 100644 --- a/build/kairos-debug.js +++ b/build/kairos-debug.js @@ -1,7 +1,7 @@ /** * Kairos.js - A non date-based time calculator * @author Rodrigo Gomes da Silva - * @version v1.1.0 + * @version v2.0.0 * @link https://github.com/kairos * @license BSD-2-Clause */ @@ -9,10 +9,16 @@ * @module Kairos */ (function () { + 'use strict'; var Kairos = {}; + // Set defaults + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + Kairos._autoParser = false; + // global on the server, window in the browser var previous_Kairos; @@ -28,11 +34,11 @@ } /** - * Avoid conflict in case of another instance of Kairos is already in the scope + * Avoid conflict in case of another instance of Kairos is already in the scope. * * @memberof module:Kairos * @method noConflict - * @returns {Object} + * @returns {Object} Previous Kairos object */ Kairos.noConflict = function () { root.Kairos = previous_Kairos; @@ -40,234 +46,301 @@ }; /** - * Validates if the given expression is valid. + * Sets Kairos time expression pattern. + * Pattern structure is the following: + * # -> sign + * h -> hours + * m -> minutes + * s -> seconds + * S -> milliseconds * * @memberof module:Kairos - * @method validateExpression - * @param {String|Number} expression Time expression - * @returns {Boolean} + * @method setPattern + * @param {String} pattern The pattern to parse and format time expressions + * @example Kairos.setPattern('#hh:mm:ss.SSS'); */ - Kairos.validateExpression = function (expression) { - var regex = /^[+-]?\d+(?::?\d{1,2}(?::\d{1,2}(?::\d{1,3})?)?)?$/; - return regex.test(expression); + Kairos.setPattern = function (pattern) { + Kairos._validator = Kairos.Lexicon.getValidator(pattern); + Kairos._pattern = pattern; }; /** - * Return a Kairos.Gnomon instance. - * + * Gets current Kairos pattern. + * + * @memberof module:Kairos + * @method getPattern + * @returns {String} Current Kairos pattern + */ + Kairos.getPattern = function () { + return Kairos._pattern; + }; + + /** + * Sets Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method setAutoParser + * @param {Boolean} yN True to use or false to not use auto parser + * @example Kairos.setAutoParser(true); + */ + Kairos.setAutoParser = function (yN) { + Kairos._autoParser = !!yN; + }; + + /** + * Gets current Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method getAutoParser + * @returns {Boolean} True if auto parse is being used or false if not + */ + Kairos.getAutoParser = function () { + return Kairos._autoParser; + }; + + /** + * Validates the give expression with the current or given pattern. + * + * @memberof module:Kairos + * @method validate + * @param {String} expression Time expression to validate + * @param {String} pattern Pattern to test the expression + * @example Kairos.validate('10:30', 'hh:mm'); + * @returns {Boolean} True if valid, false if invalid + */ + Kairos.validate = function (expression, pattern) { + return Kairos.Lexicon.validate(expression, pattern); + }; + + /** + * Returns a new Kairos.Engine instance. + * + * @memberof module:Kairos + * @method new + * @param {String|Number|kairos.Engine} time Time expression to create an instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance from the given time + */ + Kairos.new = function (time, pattern) { + return new Kairos.Engine(time, pattern); + }; + + /** + * Returns an instance of Kairos.Engine with absolute time. + * * @memberof module:Kairos - * @method with - * @param {String|Number} expression Time expression - * @returns {Kairos.Gnomon} + * @method absolute + * @param {String|Number|kairos.Engine} time Time expression to get its absolute value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with absolute value */ - Kairos.with = function (expression) { - return new Kairos.Gnomon(expression); + Kairos.absolute = function (time, pattern) { + return Kairos.new(time, pattern).toAbsolute(); }; /** - * Sums augend time with addend time + * Sums augend time with addend time. * * @memberof module:Kairos * @method plus - * @param {String|Number} augend Augend time expression - * @param {String|Number} addend Addend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} augend Augend time expression + * @param {String|Number|kairos.Engine} addend Addend time expression + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the sum result */ - Kairos.plus = function (augend, addend) { - return Kairos.with(augend).plus(addend).toExpression(); + Kairos.plus = function (augend, addend, pattern) { + return Kairos.new(augend, pattern).plus(addend, pattern); }; /** - * Subtracts minuend time with subtrahend time + * Subtracts minuend time with subtrahend time. * * @memberof module:Kairos * @method minus - * @param {String|Number} minuend Minuend time expression - * @param {String|Number} subtrahend Subtrahend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} minuend Minuend time expression + * @param {String|Number|kairos.Engine} subtrahend Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with subtract result */ - Kairos.minus = function (minuend, subtrahend) { - return Kairos.with(minuend).minus(subtrahend).toExpression(); + Kairos.minus = function (minuend, subtrahend, pattern) { + return Kairos.new(minuend, pattern).minus(subtrahend, pattern); }; /** - * Multiplies multiplier by the multiplicand + * Multiplies multiplier by the multiplicand. * * @memberof module:Kairos * @method multiply - * @param {String|Number} multiplier Multiplier time expression - * @param {String|Number} multiplicand Multiplicand number - * @returns {String} + * @param {String|Number|kairos.Engine} multiplier Multiplier time expression + * @param {Number} multiplicand Multiplicand value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with multiplication result */ - Kairos.multiply = function (multiplier, multiplicand) { - return Kairos.with(multiplier).multiply(multiplicand).toExpression(); + Kairos.multiply = function (multiplier, multiplicand, pattern) { + return Kairos.new(multiplier, pattern).multiply(multiplicand); }; /** - * Divides dividend by the divisor + * Divides dividend by the divisor. * * @memberof module:Kairos * @method divide - * @param {String|Number} dividend Dividend time expression - * @param {Number} divisor Dividor number - * @returns {String} + * @param {String|Number|kairos.Engine} dividend Dividend time expression + * @param {Number} divisor Divisor value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with division result */ - Kairos.divide = function (dividend, divisor) { - return Kairos.with(dividend).divide(divisor).toExpression(); + Kairos.divide = function (dividend, divisor, pattern) { + return Kairos.new(dividend, pattern).divide(divisor); }; /** - * Returns a fraction of the current time + * Returns a fraction of the current time. * * @memberof module:Kairos * @method getFraction - * @param {String|Number} time - * @param {Number} numerator - * @param {Number} denominator - * @returns {String} + * @param {String|Number|Kairos.Engine} time Time expression to extract a fraction + * @param {Number} numerator Numerator value + * @param {Number} denominator Denominator value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the fraction extracted */ - Kairos.getFraction = function (time, numerator, denominator) { + Kairos.getFraction = function (time, numerator, denominator, pattern) { if (numerator > denominator) { throw new Error('Improper fraction'); } - return Kairos.with(time).multiply(numerator).divide(denominator).toExpression(); + return Kairos.new(time, pattern).multiply(numerator).divide(denominator); }; /** - * Returns a time expression representing the time between starting time and ending time + * Returns a time expression representing the time between starting time and ending time. * * @memberof module:Kairos * @method getInterval - * @param {String|Number} time1 time expression representing the starting time - * @param {String|Number} time2 time expression representing the ending time - * @returns {String} - */ - Kairos.getInterval = function (starting, ending) { - var st = new Kairos.Gnomon(starting); - var en = new Kairos.Gnomon(ending); - if (st.compareTo(en) > 0) { - throw new Error('Starting time must be bigger than ending time'); - } - return en.minus(st).toExpression(); + * @param {String|Number|Kairos.Engine} time1 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String|Number|Kairos.Engine} time2 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the interval between time1 and time2 + */ + Kairos.getInterval = function (time1, time2, pattern) { + return Kairos.new(time1, pattern).minus(time2, pattern).toAbsolute(); }; /** - * Converts the given time expression to milliseconds + * Converts the given time expression to milliseconds. * * @memberof module:Kairos * @method toMilliseconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total milliseconds in the time expression */ - Kairos.toMilliseconds = function (expression) { - return Kairos.with(expression).toMilliseconds(); + Kairos.toMilliseconds = function (time, pattern) { + return Kairos.new(time, pattern).toMilliseconds(); }; /** - * Converts the given time expression to seconds + * Converts the given time expression to seconds. * * @memberof module:Kairos * @method toSeconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total seconds in the time expression */ - Kairos.toSeconds = function (expression) { - return Kairos.with(expression).toSeconds(); + Kairos.toSeconds = function (time, pattern) { + return Kairos.new(time, pattern).toSeconds(); }; /** - * Converts the given time expression to minutes + * Converts the given time expression to minutes. * * @memberof module:Kairos * @method toMinutes - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total minutes in the time expression */ - Kairos.toMinutes = function (expression) { - return Kairos.with(expression).toMinutes(); + Kairos.toMinutes = function (time, pattern) { + return Kairos.new(time, pattern).toMinutes(); }; /** - * Converts the given time expression to hours + * Converts the given time expression to hours. * * @memberof module:Kairos * @method toHours - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total hours in the time expression */ - Kairos.toHours = function (expression) { - return Kairos.with(expression).toHours(); + Kairos.toHours = function (time, pattern) { + return Kairos.new(time, pattern).toHours(); }; /** * Compares first time with second time and returns -1, 0 or 1 if first value - * is smaller, equals or bigger than second value + * is smaller, equals or bigger than second value. * * @memberof module:Kairos * @method compare - * @param {String|Number} time1 Time expression - * @param {String|Number} time2 Time expression for comparation - * @returns {Number} + * @param {String|Number} comparand Time to compare with + * @param {String|Number} comparator Time to be compared with + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.compare = function (time1, time2) { - return Kairos.with(time1).compareTo(time2); + Kairos.compare = function (comparand, comparator, pattern) { + return Kairos.new(comparand, pattern).compareTo(comparator, pattern); }; /** - * Returns the minimum value from the given values + * Returns the minimum value from the given values. * * @memberof module:Kairos * @method min - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the lowest value found in the list */ - Kairos.min = function (values) { + Kairos.min = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var min = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() < current.toMilliseconds() ? previous : current ); + return Kairos.compare(previous, current, pattern) < 0 ? previous : current; }); - - return (min instanceof Kairos.Gnomon) ? min.toExpression() : new Kairos.Gnomon(min).toExpression(); + + return Kairos.new(min, pattern); }; /** - * Returns the maximum value from the given values + * Returns the maximum value from the given values. * * @memberof module:Kairos * @method max - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {String} Kairos.Engine instance with the greatest value found in the list */ - Kairos.max = function (values) { + Kairos.max = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var max = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() > current.toMilliseconds() ? previous : current ); + return Kairos.new(previous, pattern).compareTo(current, pattern) > 0 ? previous : current; }); - return (max instanceof Kairos.Gnomon) ? max.toExpression() : new Kairos.Gnomon(max).toExpression(); + return Kairos.new(max, pattern); }; // Node.js if (typeof module === 'object' && module.exports) { - //=include /engine/Gnomon.js + //=include /Lexicon.js + //=include /Engine.js module.exports = Kairos; } // AMD / RequireJS @@ -286,87 +359,321 @@ return x < 0 ? Math.ceil(x) : Math.floor(x); }; }()); +/** + * @module Lexicon + */ (function () { + 'use strict'; /** - * - * @type {{SECOND: number, MINUTE: number, HOUR: number}} + * @type {{HOURS: string, MINUTES: string, SECONDS: string, MILLISECONDS: string}} */ - var MILLIS = { - SECOND: 1000, - MINUTE: 60 * 1000, - HOUR: 60 * 60 * 1000 + var TOKENS = { + SIGN: '#', HOURS: 'h', MINUTES: 'm', + SECONDS: 's', MILLISECONDS: 'S' }; + Kairos.Lexicon = {}; + /** - * Gnomon is the time engine for Kairos. It's name references the first solar clock ever made. - * - * @param {String|Number} expression Time expression - * @constructor + * Gets a regex from a pattern. + * + * @memberof module:Lexicon + * @method getValidator + * @param {String} [pattern] Pattern to convert + * @example Kairos.Lexicon.getValidator('#hh:mm:ss.SSS'); + * @returns {RegExp} + */ + Kairos.Lexicon.getValidator = function (pattern) { + if (typeof pattern !== 'string') { + pattern = Kairos._pattern; + } + if (pattern === Kairos._pattern) { + return Kairos._validator; + } + + var regex = ''; + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + regex += '^[+-]?'; + break; + case TOKENS.HOURS: + case TOKENS.MINUTES: + case TOKENS.SECONDS: + case TOKENS.MILLISECONDS: + regex += '\\d'; + break; + default: + regex += cur.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); + } + } + + return new RegExp(regex); + }; + + /** + * Validates if given expression matches the current pattern. + * + * @memberof module:Lexicon + * @method validate + * @param {String} expression Time expression to be validated + * @param {String} [pattern] Pattern to validate + * @example Kairos.Lexicon.validate('10:00:00.000', 'hh:mm:ss.SSS'); + * @returns {Boolean} True if expression is valid, false if expression is invalid */ - Kairos.Gnomon = function (expression) { - if (typeof expression === 'number') { + Kairos.Lexicon.validate = function (expression, pattern) { + return Kairos.Lexicon.getValidator(pattern).test(expression); + }; - this.milliseconds = expression; + /** + * Parses given time expression to a Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method parse + * @param {String} expression Time expression to be parsed + * @param {String} [pattern] Pattern to parse + * @example Kairos.Lexicon.parse('01:00:03', 'hh:mm:ss'); + * @returns {Kairos.Engine} Given expression parsed to Kairos.Engine + */ + Kairos.Lexicon.parse = function (expression, pattern) { + if (!pattern) { + pattern = Kairos._pattern; + } + if (!Kairos.Lexicon.validate(expression, pattern)) { + throw new Error('Cannot parse expression. Time format doesn\'t match the current time pattern.'); + } - } else if (typeof expression === 'string' && expression.length > 0) { - - if (!Kairos.validateExpression(expression)) { - throw new Error('Invalid time expression'); + var sign = true, hours = '', minutes = '', seconds = '', milliseconds = ''; + + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + var validSign = (['+', '-'].indexOf(expression[i]) !== -1); + if (!validSign) { + pattern = pattern.slice(0, i) + pattern.slice(i + 1); + len--; + i--; + } else { + sign = expression[i] === '+'; + } + break; + case TOKENS.HOURS: + hours += expression[i]; + break; + case TOKENS.MINUTES: + minutes += expression[i]; + break; + case TOKENS.SECONDS: + seconds += expression[i]; + break; + case TOKENS.MILLISECONDS: + milliseconds += expression[i]; + break; } + } + + var result = Kairos.new() + .addHours(hours ? +hours : 0) + .addMinutes(minutes ? +minutes : 0) + .addSeconds(seconds ? +seconds : 0) + .addMilliseconds(milliseconds ? +milliseconds : 0); - var timeSteps = expression.split(':'); - var positive = expression.slice(0, 1)[0] !== '-'; + if (!sign) { + result.milliseconds =- result.milliseconds; + } - for (var i = 0, len = timeSteps.length; i < len; i++) { - var timeStep = timeSteps[i]; + return result; + }; - timeStep = Math.abs(timeStep); - switch (i) { - case 0: - this.milliseconds = _parse(this, MILLIS.HOUR, timeStep); - break; - case 1: - this.milliseconds = _parse(this, MILLIS.MINUTE, timeStep); + /** + * Returns a formated string from an Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method format + * @param {Kairos.Engine} instance The instance to format + * @param {String} [pattern] Pattern to format + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example Kairos.Lexicon.format(Kairos.new('10:30'), 'mm:hh'); + * @returns {String} Formated time expression + */ + Kairos.Lexicon.format = function (instance, pattern, allowOverflow) { + if (!pattern) { + pattern = Kairos._pattern; + } + + var sign = instance.milliseconds >= 0, + hours = String(Math.abs(instance.getHours())), + minutes = String(Math.abs(instance.getMinutes())), + seconds = String(Math.abs(instance.getSeconds())), + milliseconds = String(Math.abs(instance.getMilliseconds())); + + var result = '', + hasOverflow = (hours.length > (pattern.match(/h/g) || []).length); + + for (var i = pattern.length - 1; i >= 0; i--) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + result = (sign ? '+' : '-') + result; + break; + case TOKENS.HOURS: + if (hasOverflow) { + if (allowOverflow) { + result = hours + result; + allowOverflow = false; + } + break; + } + result = (hours.slice(-1) || '0') + result; + if (hours.length > 0) { + hours = hours.slice(0, hours.length - 1); + } + break; + case TOKENS.MINUTES: + result = (minutes.slice(-1) || '0') + result; + if (minutes.length > 0) { + minutes = minutes.slice(0, minutes.length - 1); + } + break; + case TOKENS.SECONDS: + result = (seconds.slice(-1) || '0') + result; + if (seconds.length > 0) { + seconds = seconds.slice(0, seconds.length - 1); + } + break; + case TOKENS.MILLISECONDS: + result = (milliseconds.slice(-1) || '0') + result; + if (milliseconds.length > 0) { + milliseconds = milliseconds.slice(0, milliseconds.length - 1); + } + break; + default: + result = cur + result; + } + } + + return result; + }; + + /** + * Tries to extract a pattern from the given expression. + * + * @memberof module:Lexicon + * @method findPattern + * @param {String} expression Expression to be analysed + * @example Kairos.Lexicon.findPattern('01:05:30'); + * @returns {String} Extracted pattern + */ + Kairos.Lexicon.findPattern = function (expression) { + var pattern = '', + currentStep = TOKENS.HOURS; + for (var i = 0, len = expression.length; len > i; i++) { + var cur = expression[i]; + + if (['+', '-'].indexOf(cur) !== -1) { + pattern += TOKENS.SIGN; + continue; + } + + if (!isNaN(cur)) { + pattern += currentStep || cur; + continue; + } + + if (isNaN(cur)) { + pattern += cur; + switch (currentStep) { + case TOKENS.HOURS: + currentStep = TOKENS.MINUTES; break; - case 2: - this.milliseconds = _parse(this, MILLIS.SECOND, timeStep); + case TOKENS.MINUTES: + currentStep = TOKENS.SECONDS; break; - case 3: - this.milliseconds = _parse(this, 1, timeStep); + case TOKENS.SECONDS: + currentStep = TOKENS.MILLISECONDS; break; + default: + currentStep = false; } + continue; } - if (!positive) { - this.milliseconds = -Math.abs(this.milliseconds); + } + + return pattern; + }; +}()); +(function () { + + 'use strict'; + + /** + * @type {{SECOND: number, MINUTE: number, HOUR: number}} + */ + var MILLIS = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000 + }; + + /** + * Kairos time engine. + * + * @param {String|Number|Kairos.Engine} expression Literal time expression, milliseconds or a Kairos.Engine instance + * @pattern {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('10:30', 'hh:mm'); + * @constructor + */ + Kairos.Engine = function (expression, pattern) { + if (!expression) { + return; + } + + if (expression instanceof Kairos.Engine) { + return expression; + } + + if (typeof expression === 'number') { + this.milliseconds = expression; + return this; + } + + if (typeof expression === 'string' && expression.length > 0) { + if (Kairos.getAutoParser()) { + pattern = Kairos.Lexicon.findPattern(expression); } + return new Kairos.Lexicon.parse(expression, pattern); } + + throw new Error('Invalid arguments'); }; /** - * @param {Kairos.Gnomon} instance + * @param {Kairos.Engine} instance * @param {Number} millis * @param {Number} time * @returns {Number} * @private */ - var _parse = function (instance, millis, time) { + Kairos.Engine.prototype._resolveStep = function (millis, time) { switch (millis) { case 1: - instance.removeMilliseconds(instance.getMilliseconds()); + this.removeMilliseconds(this.getMilliseconds()); break; case MILLIS.SECOND: - instance.removeSeconds(instance.getSeconds()); + this.removeSeconds(this.getSeconds()); break; case MILLIS.MINUTE: - instance.removeMinutes(instance.getMinutes()); + this.removeMinutes(this.getMinutes()); break; case MILLIS.HOUR: - instance.removeHours(instance.getHours()); + this.removeHours(this.getHours()); break; } - return instance.milliseconds + (time * millis); + return this.milliseconds + (time * millis); }; /** @@ -374,271 +681,305 @@ * @default 0 * @protected */ - Kairos.Gnomon.prototype.milliseconds = 0; + Kairos.Engine.prototype.milliseconds = 0; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Sets hours fraction in the current instance. + * + * @param {Number} hours Hours to set + * @example new Kairos.Engine('01:00').setHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setHours = function (hours) { - this.milliseconds = _parse(this, MILLIS.HOUR, hours); + Kairos.Engine.prototype.setHours = function (hours) { + this.milliseconds = this._resolveStep(MILLIS.HOUR, hours); return this; }; /** - * - * @returns {*|Number} + * Gets hours fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getHours(); + * @returns {Number} Hours fraction from the instance */ - Kairos.Gnomon.prototype.getHours = function () { + Kairos.Engine.prototype.getHours = function () { return Math.trunc(this.milliseconds / MILLIS.HOUR); }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Sets minutes fraction in the current instance. + * + * @param {Number} minutes Minutes to set + * @example new Kairos.Engine('01:00').setMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMinutes = function (minutes) { - this.milliseconds = _parse(this, MILLIS.MINUTE, minutes); + Kairos.Engine.prototype.setMinutes = function (minutes) { + this.milliseconds = this._resolveStep(MILLIS.MINUTE, minutes); return this; }; /** - * - * @returns {*|Number} + * Gets minutes fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMinutes(); + * @returns {Number} Minutes fraction from the instance */ - Kairos.Gnomon.prototype.getMinutes = function () { + Kairos.Engine.prototype.getMinutes = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toHours()) * MILLIS.HOUR)) / MILLIS.MINUTE); }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Sets seconds fraction in the current instance. + * + * @param {Number} seconds Seconds to set + * @example new Kairos.Engine('01:00').setSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setSeconds = function (seconds) { - this.milliseconds = _parse(this, MILLIS.SECOND, seconds); + Kairos.Engine.prototype.setSeconds = function (seconds) { + this.milliseconds = this._resolveStep(MILLIS.SECOND, seconds); return this; }; /** - * - * @returns {*|Number} + * Gets seconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getSeconds(); + * @returns {Number} Seconds fraction from the instance */ - Kairos.Gnomon.prototype.getSeconds = function () { + Kairos.Engine.prototype.getSeconds = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toMinutes()) * MILLIS.MINUTE)) / MILLIS.SECOND); }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Sets milliseconds fraction in the current instance. + * + * @param {Number} milliseconds Milliseconds to set + * @example new Kairos.Engine('01:00').setMilliseconds(200); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMilliseconds = function (milliseconds) { - this.milliseconds = _parse(this, 1, milliseconds); + Kairos.Engine.prototype.setMilliseconds = function (milliseconds) { + this.milliseconds = this._resolveStep(1, milliseconds); return this; }; /** - * - * @returns {Number|*} + * Gets milliseconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMilliseconds(); + * @returns {Number} Milliseconds fraction from the instance */ - Kairos.Gnomon.prototype.getMilliseconds = function () { + Kairos.Engine.prototype.getMilliseconds = function () { return Math.trunc(this.milliseconds - (Math.trunc(this.toSeconds()) * MILLIS.SECOND)); }; /** + * Adds hours to the current instance. * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * @param {Number} hours Hours to add + * @example new Kairos.Engine('01:00').addHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addHours = function (hours) { + Kairos.Engine.prototype.addHours = function (hours) { this.milliseconds += (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Adds minutes to the current instance. + * + * @param {Number} minutes Minutes to add + * @example new Kairos.Engine('01:00').addMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMinutes = function (minutes) { + Kairos.Engine.prototype.addMinutes = function (minutes) { this.milliseconds += (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Adds seconds in the current instance. + * + * @param {Number} seconds Seconds to add + * @example new Kairos.Engine('01:00').addSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addSeconds = function (seconds) { + Kairos.Engine.prototype.addSeconds = function (seconds) { this.milliseconds += (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Adds milliseconds in the current instance. + * + * @param {Number} milliseconds Milliseconds to add + * @example new Kairos.Engine('01:00').addMilliseconds(500); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.addMilliseconds = function (milliseconds) { this.milliseconds += milliseconds; return this; }; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Removes hours from the current instance. + * + * @param {Number} hours Hours to remove + * @example new Kairos.Engine('01:00').removeHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeHours = function (hours) { + Kairos.Engine.prototype.removeHours = function (hours) { this.milliseconds -= (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Removes minutes from the current instance. + * + * @param {Number} minutes Minutes to remove + * @example new Kairos.Engine('01:00').removeMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMinutes = function (minutes) { + Kairos.Engine.prototype.removeMinutes = function (minutes) { this.milliseconds -= (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Removes seconds from the current instance. + * + * @param {Number} seconds Seconds to remove + * @example new Kairos.Engine('01:00').removeSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeSeconds = function (seconds) { + Kairos.Engine.prototype.removeSeconds = function (seconds) { this.milliseconds -= (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Removes milliseconds from the current instance. + * + * @example new Kairos.Engine('01:00').removeMilliseconds(50); + * @param {Number} milliseconds Milliseconds to remove + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.removeMilliseconds = function (milliseconds) { this.milliseconds -= milliseconds; return this; }; /** - * - * @returns {Number} hours within the time expression + * Returns total hours within the current instance. + * + * @example new Kairos.Engine('01:00').toHours(); + * @returns {Number} Hours within the current instance */ - Kairos.Gnomon.prototype.toHours = function () { + Kairos.Engine.prototype.toHours = function () { return (this.milliseconds / MILLIS.HOUR); }; /** - * - * @returns {Number} minutes within the time expression + * Returns total minutes within the current instance. + * + * @example new Kairos.Engine('01:00').toMinutes(); + * @returns {Number} Minutes within the current instance */ - Kairos.Gnomon.prototype.toMinutes = function () { + Kairos.Engine.prototype.toMinutes = function () { return (this.milliseconds / MILLIS.MINUTE); }; /** - * - * @returns {Number} seconds within the time expression + * Returns total seconds within the current instance. + * + * @example new Kairos.Engine('01:00').toSeconds(); + * @returns {Number} Seconds within the current instance */ - Kairos.Gnomon.prototype.toSeconds = function () { + Kairos.Engine.prototype.toSeconds = function () { return (this.milliseconds / MILLIS.SECOND); }; /** - * - * @returns {Number} milliseconds within the time expression + * Returns total milliseconds within the current instance. + * + * @example new Kairos.Engine('01:00').toMilliseconds(); + * @returns {Number} Milliseconds within the current instance */ - Kairos.Gnomon.prototype.toMilliseconds = function () { + Kairos.Engine.prototype.toMilliseconds = function () { return this.milliseconds; }; /** - * - * @returns {String} - */ - Kairos.Gnomon.prototype.toExpression = function () { - var expression = ''; - // Hours - var hours = Math.trunc(Math.abs(this.getHours())); - expression += ((String(hours).length > 1) ? '' : '0') + hours + ':'; - // Minutes - expression += ('00' + Math.trunc(Math.abs(this.getMinutes()))).slice(-2); - // Seconds - if (this.getSeconds() !== 0 || this.getMilliseconds() !== 0) { - expression += ':' + ('00' + Math.trunc(Math.abs(this.getSeconds()))).slice(-2); - } - // Millis - if (this.getMilliseconds() !== 0) { - expression += ':' + ('000' + Math.trunc(Math.abs(this.getMilliseconds()))).slice(-3); - } - - if (this.milliseconds < 0) { - expression = '-' + expression; - } - return expression; + * Makes the current instance's value absolute. + * + * @example new Kairos.Engine('01:00').toAbsolute(); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.toAbsolute = function () { + this.milliseconds = Math.abs(this.milliseconds); + return this; }; /** - * - * @param {Number|String|Kairos.Gnomon} addend - * @returns {Kairos.Gnomon} self + * Sums the given addend. + * + * @param {Number|String|Kairos.Engine} addend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.plus = function (addend) { - addend = (addend instanceof Kairos.Gnomon) ? addend : new Kairos.Gnomon(addend); + Kairos.Engine.prototype.plus = function (addend, pattern) { + addend = new Kairos.Engine(addend, pattern); this.milliseconds += addend.toMilliseconds(); return this; }; /** + * Subtracts the given subtrahend. * - * @param {Number|String|Kairos.Gnomon} subtrahend - * @returns {Kairos.Gnomon} self + * @param {Number|String|Kairos.Engine} subtrahend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.minus = function (subtrahend) { - subtrahend = (subtrahend instanceof Kairos.Gnomon) ? subtrahend : new Kairos.Gnomon(subtrahend); + Kairos.Engine.prototype.minus = function (subtrahend, pattern) { + subtrahend = new Kairos.Engine(subtrahend, pattern); this.milliseconds -= subtrahend.toMilliseconds(); return this; }; /** - * - * @param {Number} multiplicand - * @returns {Kairos.Gnomon} self + * Multiply by the given multiplicand. + * + * @param {Number} multiplicand Multiplicand value + * @example new Kairos.Engine('01:00').multiply(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.multiply = function (multiplicand) { + Kairos.Engine.prototype.multiply = function (multiplicand) { this.milliseconds *= multiplicand; return this; }; /** - * - * @param {Number} dividend - * @returns {Kairos.Gnomon} self + * Divies by the given dividend. + * + * @param {Number} divisor Divisor value + * @example new Kairos.Engine('01:00').divide(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.divide = function (dividend) { - this.milliseconds /= dividend; + Kairos.Engine.prototype.divide = function (divisor) { + this.milliseconds /= divisor; return this; }; /** * Compares with another instance. - * Smaller -1 - * Equals 0 - * Bigger 1 * - * @param {String|Number|Kairos.Gnomon} another Expression to compare with - * @returns {Number} + * @param {String|Number|Kairos.Engine} another Expression to compare with + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').compareTo('00:30'); + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.Gnomon.prototype.compareTo = function (another) { - another = (another instanceof Kairos.Gnomon) ? another : new Kairos.Gnomon(another); + Kairos.Engine.prototype.compareTo = function (another, pattern) { + another = new Kairos.Engine(another, pattern); if (this.milliseconds < another.toMilliseconds()) { return -1; @@ -650,4 +991,20 @@ return 1; } }; + + /** + * Returns a string representation of the object. + * + * @param {String} pattern Pattern to format the time expression + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example new Kairos.Engine('22:10').toString('hh:mm'); + * @returns {String} String representing the instance time + */ + Kairos.Engine.prototype.toString = function (pattern, allowOverflow) { + if (typeof pattern === 'boolean') { + allowOverflow = pattern; + pattern = null; + } + return Kairos.Lexicon.format(this, pattern, allowOverflow); + }; }()); \ No newline at end of file diff --git a/build/kairos-min.js b/build/kairos-min.js index 9cd7c00..03fc03d 100644 --- a/build/kairos-min.js +++ b/build/kairos-min.js @@ -1,9 +1,10 @@ /** * Kairos.js - A non date-based time calculator * @author Rodrigo Gomes da Silva - * @version v1.1.0 + * @version v2.0.0 * @link https://github.com/kairos * @license BSD-2-Clause */ -!function(){"use strict";var n,o={},t="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this;null!==t&&(n=t.Kairos),o.noConflict=function(){return t.Kairos=n,o},o.validateExpression=function(n){var o=/^[+-]?\d+(?::?\d{1,2}(?::\d{1,2}(?::\d{1,3})?)?)?$/;return o.test(n)},o["with"]=function(n){return new o.Gnomon(n)},o.plus=function(n,t){return o["with"](n).plus(t).toExpression()},o.minus=function(n,t){return o["with"](n).minus(t).toExpression()},o.multiply=function(n,t){return o["with"](n).multiply(t).toExpression()},o.divide=function(n,t){return o["with"](n).divide(t).toExpression()},o.getFraction=function(n,t,e){if(t>e)throw new Error("Improper fraction");return o["with"](n).multiply(t).divide(e).toExpression()},o.getInterval=function(n,t){var e=new o.Gnomon(n),i=new o.Gnomon(t);if(e.compareTo(i)>0)throw new Error("Starting time must be bigger than ending time");return i.minus(e).toExpression()},o.toMilliseconds=function(n){return o["with"](n).toMilliseconds()},o.toSeconds=function(n){return o["with"](n).toSeconds()},o.toMinutes=function(n){return o["with"](n).toMinutes()},o.toHours=function(n){return o["with"](n).toHours()},o.compare=function(n,t){return o["with"](n).compareTo(t)},o.min=function(n){n instanceof Array||(n=Array.prototype.slice.call(arguments));var t=n.reduce(function(n,t){return n instanceof o.Gnomon||(n=new o.Gnomon(n?n:0)),t instanceof o.Gnomon||(t=new o.Gnomon(t?t:0)),n.toMilliseconds()t.toMilliseconds()?n:t});return t instanceof o.Gnomon?t.toExpression():new o.Gnomon(t).toExpression()},"object"==typeof module&&module.exports?module.exports=o:"function"==typeof define&&define.amd?define([],function(){return o}):t.Kairos=o,Math.trunc=Math.trunc||function(n){return 0>n?Math.ceil(n):Math.floor(n)}}(); -!function(){"use strict";var o={SECOND:1e3,MINUTE:6e4,HOUR:36e5};Kairos.Gnomon=function(i){if("number"==typeof i)this.milliseconds=i;else if("string"==typeof i&&i.length>0){if(!Kairos.validateExpression(i))throw new Error("Invalid time expression");for(var t=i.split(":"),n="-"!==i.slice(0,1)[0],e=0,r=t.length;r>e;e++){var c=t[e];switch(c=Math.abs(c),e){case 0:this.milliseconds=s(this,o.HOUR,c);break;case 1:this.milliseconds=s(this,o.MINUTE,c);break;case 2:this.milliseconds=s(this,o.SECOND,c);break;case 3:this.milliseconds=s(this,1,c)}}n||(this.milliseconds=-Math.abs(this.milliseconds))}};var s=function(s,i,t){switch(i){case 1:s.removeMilliseconds(s.getMilliseconds());break;case o.SECOND:s.removeSeconds(s.getSeconds());break;case o.MINUTE:s.removeMinutes(s.getMinutes());break;case o.HOUR:s.removeHours(s.getHours())}return s.milliseconds+t*i};Kairos.Gnomon.prototype.milliseconds=0,Kairos.Gnomon.prototype.setHours=function(i){return this.milliseconds=s(this,o.HOUR,i),this},Kairos.Gnomon.prototype.getHours=function(){return Math.trunc(this.milliseconds/o.HOUR)},Kairos.Gnomon.prototype.setMinutes=function(i){return this.milliseconds=s(this,o.MINUTE,i),this},Kairos.Gnomon.prototype.getMinutes=function(){return Math.trunc(Math.trunc(this.milliseconds-Math.trunc(this.toHours())*o.HOUR)/o.MINUTE)},Kairos.Gnomon.prototype.setSeconds=function(i){return this.milliseconds=s(this,o.SECOND,i),this},Kairos.Gnomon.prototype.getSeconds=function(){return Math.trunc(Math.trunc(this.milliseconds-Math.trunc(this.toMinutes())*o.MINUTE)/o.SECOND)},Kairos.Gnomon.prototype.setMilliseconds=function(o){return this.milliseconds=s(this,1,o),this},Kairos.Gnomon.prototype.getMilliseconds=function(){return Math.trunc(this.milliseconds-Math.trunc(this.toSeconds())*o.SECOND)},Kairos.Gnomon.prototype.addHours=function(s){return this.milliseconds+=o.HOUR*s,this},Kairos.Gnomon.prototype.addMinutes=function(s){return this.milliseconds+=o.MINUTE*s,this},Kairos.Gnomon.prototype.addSeconds=function(s){return this.milliseconds+=o.SECOND*s,this},Kairos.Gnomon.prototype.addMilliseconds=function(o){return this.milliseconds+=o,this},Kairos.Gnomon.prototype.removeHours=function(s){return this.milliseconds-=o.HOUR*s,this},Kairos.Gnomon.prototype.removeMinutes=function(s){return this.milliseconds-=o.MINUTE*s,this},Kairos.Gnomon.prototype.removeSeconds=function(s){return this.milliseconds-=o.SECOND*s,this},Kairos.Gnomon.prototype.removeMilliseconds=function(o){return this.milliseconds-=o,this},Kairos.Gnomon.prototype.toHours=function(){return this.milliseconds/o.HOUR},Kairos.Gnomon.prototype.toMinutes=function(){return this.milliseconds/o.MINUTE},Kairos.Gnomon.prototype.toSeconds=function(){return this.milliseconds/o.SECOND},Kairos.Gnomon.prototype.toMilliseconds=function(){return this.milliseconds},Kairos.Gnomon.prototype.toExpression=function(){var o="",s=Math.trunc(Math.abs(this.getHours()));return o+=(String(s).length>1?"":"0")+s+":",o+=("00"+Math.trunc(Math.abs(this.getMinutes()))).slice(-2),(0!==this.getSeconds()||0!==this.getMilliseconds())&&(o+=":"+("00"+Math.trunc(Math.abs(this.getSeconds()))).slice(-2)),0!==this.getMilliseconds()&&(o+=":"+("000"+Math.trunc(Math.abs(this.getMilliseconds()))).slice(-3)),this.milliseconds<0&&(o="-"+o),o},Kairos.Gnomon.prototype.plus=function(o){return o=o instanceof Kairos.Gnomon?o:new Kairos.Gnomon(o),this.milliseconds+=o.toMilliseconds(),this},Kairos.Gnomon.prototype.minus=function(o){return o=o instanceof Kairos.Gnomon?o:new Kairos.Gnomon(o),this.milliseconds-=o.toMilliseconds(),this},Kairos.Gnomon.prototype.multiply=function(o){return this.milliseconds*=o,this},Kairos.Gnomon.prototype.divide=function(o){return this.milliseconds/=o,this},Kairos.Gnomon.prototype.compareTo=function(o){return o=o instanceof Kairos.Gnomon?o:new Kairos.Gnomon(o),this.millisecondso.toMilliseconds()?1:void 0}}(); \ No newline at end of file +!function(){"use strict";var n={};n._pattern="#hh:mm:ss.SSS",n._validator=new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/),n._autoParser=!1;var t,e="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this;null!==e&&(t=e.Kairos),n.noConflict=function(){return e.Kairos=t,n},n.setPattern=function(t){n._validator=n.Lexicon.getValidator(t),n._pattern=t},n.getPattern=function(){return n._pattern},n.setAutoParser=function(t){n._autoParser=!!t},n.getAutoParser=function(){return n._autoParser},n.validate=function(t,e){return n.Lexicon.validate(t,e)},n["new"]=function(t,e){return new n.Engine(t,e)},n.absolute=function(t,e){return n["new"](t,e).toAbsolute()},n.plus=function(t,e,r){return n["new"](t,r).plus(e,r)},n.minus=function(t,e,r){return n["new"](t,r).minus(e,r)},n.multiply=function(t,e,r){return n["new"](t,r).multiply(e)},n.divide=function(t,e,r){return n["new"](t,r).divide(e)},n.getFraction=function(t,e,r,o){if(e>r)throw new Error("Improper fraction");return n["new"](t,o).multiply(e).divide(r)},n.getInterval=function(t,e,r){return n["new"](t,r).minus(e,r).toAbsolute()},n.toMilliseconds=function(t,e){return n["new"](t,e).toMilliseconds()},n.toSeconds=function(t,e){return n["new"](t,e).toSeconds()},n.toMinutes=function(t,e){return n["new"](t,e).toMinutes()},n.toHours=function(t,e){return n["new"](t,e).toHours()},n.compare=function(t,e,r){return n["new"](t,r).compareTo(e,r)},n.min=function(t,e){t instanceof Array||(e=null,t=Array.prototype.slice.call(arguments));var r=t.reduce(function(t,r){return n.compare(t,r,e)<0?t:r});return n["new"](r,e)},n.max=function(t,e){t instanceof Array||(e=null,t=Array.prototype.slice.call(arguments));var r=t.reduce(function(t,r){return n["new"](t,e).compareTo(r,e)>0?t:r});return n["new"](r,e)},"object"==typeof module&&module.exports?module.exports=n:"function"==typeof define&&define.amd?define([],function(){return n}):e.Kairos=n,Math.trunc=Math.trunc||function(n){return 0>n?Math.ceil(n):Math.floor(n)}}(); +!function(){"use strict";var e={SIGN:"#",HOURS:"h",MINUTES:"m",SECONDS:"s",MILLISECONDS:"S"};Kairos.Lexicon={},Kairos.Lexicon.getValidator=function(a){if("string"!=typeof a&&(a=Kairos._pattern),a===Kairos._pattern)return Kairos._validator;for(var r="",s=0,t=a.length;t>s;s++){var i=a[s];switch(i){case e.SIGN:r+="^[+-]?";break;case e.HOURS:case e.MINUTES:case e.SECONDS:case e.MILLISECONDS:r+="\\d";break;default:r+=i.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")}}return new RegExp(r)},Kairos.Lexicon.validate=function(e,a){return Kairos.Lexicon.getValidator(a).test(e)},Kairos.Lexicon.parse=function(a,r){if(r||(r=Kairos._pattern),!Kairos.Lexicon.validate(a,r))throw new Error("Cannot parse expression. Time format doesn't match the current time pattern.");for(var s=!0,t="",i="",n="",c="",o=0,l=r.length;l>o;o++){var S=r[o];switch(S){case e.SIGN:var d=-1!==["+","-"].indexOf(a[o]);d?s="+"===a[o]:(r=r.slice(0,o)+r.slice(o+1),l--,o--);break;case e.HOURS:t+=a[o];break;case e.MINUTES:i+=a[o];break;case e.SECONDS:n+=a[o];break;case e.MILLISECONDS:c+=a[o]}}var g=Kairos["new"]().addHours(t?+t:0).addMinutes(i?+i:0).addSeconds(n?+n:0).addMilliseconds(c?+c:0);return s||(g.milliseconds=-g.milliseconds),g},Kairos.Lexicon.format=function(a,r,s){r||(r=Kairos._pattern);for(var t=a.milliseconds>=0,i=String(Math.abs(a.getHours())),n=String(Math.abs(a.getMinutes())),c=String(Math.abs(a.getSeconds())),o=String(Math.abs(a.getMilliseconds())),l="",S=i.length>(r.match(/h/g)||[]).length,d=r.length-1;d>=0;d--){var g=r[d];switch(g){case e.SIGN:l=(t?"+":"-")+l;break;case e.HOURS:if(S){s&&(l=i+l,s=!1);break}l=(i.slice(-1)||"0")+l,i.length>0&&(i=i.slice(0,i.length-1));break;case e.MINUTES:l=(n.slice(-1)||"0")+l,n.length>0&&(n=n.slice(0,n.length-1));break;case e.SECONDS:l=(c.slice(-1)||"0")+l,c.length>0&&(c=c.slice(0,c.length-1));break;case e.MILLISECONDS:l=(o.slice(-1)||"0")+l,o.length>0&&(o=o.slice(0,o.length-1));break;default:l=g+l}}return l},Kairos.Lexicon.findPattern=function(a){for(var r="",s=e.HOURS,t=0,i=a.length;i>t;t++){var n=a[t];if(-1===["+","-"].indexOf(n))if(isNaN(n))if(isNaN(n))switch(r+=n,s){case e.HOURS:s=e.MINUTES;break;case e.MINUTES:s=e.SECONDS;break;case e.SECONDS:s=e.MILLISECONDS;break;default:s=!1}else;else r+=s||n;else r+=e.SIGN}return r}}(); +!function(){"use strict";var i={SECOND:1e3,MINUTE:6e4,HOUR:36e5};Kairos.Engine=function(i,t){if(i){if(i instanceof Kairos.Engine)return i;if("number"==typeof i)return this.milliseconds=i,this;if("string"==typeof i&&i.length>0)return Kairos.getAutoParser()&&(t=Kairos.Lexicon.findPattern(i)),new Kairos.Lexicon.parse(i,t);throw new Error("Invalid arguments")}},Kairos.Engine.prototype._resolveStep=function(t,n){switch(t){case 1:this.removeMilliseconds(this.getMilliseconds());break;case i.SECOND:this.removeSeconds(this.getSeconds());break;case i.MINUTE:this.removeMinutes(this.getMinutes());break;case i.HOUR:this.removeHours(this.getHours())}return this.milliseconds+n*t},Kairos.Engine.prototype.milliseconds=0,Kairos.Engine.prototype.setHours=function(t){return this.milliseconds=this._resolveStep(i.HOUR,t),this},Kairos.Engine.prototype.getHours=function(){return Math.trunc(this.milliseconds/i.HOUR)},Kairos.Engine.prototype.setMinutes=function(t){return this.milliseconds=this._resolveStep(i.MINUTE,t),this},Kairos.Engine.prototype.getMinutes=function(){return Math.trunc(Math.trunc(this.milliseconds-Math.trunc(this.toHours())*i.HOUR)/i.MINUTE)},Kairos.Engine.prototype.setSeconds=function(t){return this.milliseconds=this._resolveStep(i.SECOND,t),this},Kairos.Engine.prototype.getSeconds=function(){return Math.trunc(Math.trunc(this.milliseconds-Math.trunc(this.toMinutes())*i.MINUTE)/i.SECOND)},Kairos.Engine.prototype.setMilliseconds=function(i){return this.milliseconds=this._resolveStep(1,i),this},Kairos.Engine.prototype.getMilliseconds=function(){return Math.trunc(this.milliseconds-Math.trunc(this.toSeconds())*i.SECOND)},Kairos.Engine.prototype.addHours=function(t){return this.milliseconds+=i.HOUR*t,this},Kairos.Engine.prototype.addMinutes=function(t){return this.milliseconds+=i.MINUTE*t,this},Kairos.Engine.prototype.addSeconds=function(t){return this.milliseconds+=i.SECOND*t,this},Kairos.Engine.prototype.addMilliseconds=function(i){return this.milliseconds+=i,this},Kairos.Engine.prototype.removeHours=function(t){return this.milliseconds-=i.HOUR*t,this},Kairos.Engine.prototype.removeMinutes=function(t){return this.milliseconds-=i.MINUTE*t,this},Kairos.Engine.prototype.removeSeconds=function(t){return this.milliseconds-=i.SECOND*t,this},Kairos.Engine.prototype.removeMilliseconds=function(i){return this.milliseconds-=i,this},Kairos.Engine.prototype.toHours=function(){return this.milliseconds/i.HOUR},Kairos.Engine.prototype.toMinutes=function(){return this.milliseconds/i.MINUTE},Kairos.Engine.prototype.toSeconds=function(){return this.milliseconds/i.SECOND},Kairos.Engine.prototype.toMilliseconds=function(){return this.milliseconds},Kairos.Engine.prototype.toAbsolute=function(){return this.milliseconds=Math.abs(this.milliseconds),this},Kairos.Engine.prototype.plus=function(i,t){return i=new Kairos.Engine(i,t),this.milliseconds+=i.toMilliseconds(),this},Kairos.Engine.prototype.minus=function(i,t){return i=new Kairos.Engine(i,t),this.milliseconds-=i.toMilliseconds(),this},Kairos.Engine.prototype.multiply=function(i){return this.milliseconds*=i,this},Kairos.Engine.prototype.divide=function(i){return this.milliseconds/=i,this},Kairos.Engine.prototype.compareTo=function(i,t){return i=new Kairos.Engine(i,t),this.millisecondsi.toMilliseconds()?1:void 0},Kairos.Engine.prototype.toString=function(i,t){return"boolean"==typeof i&&(t=i,i=null),Kairos.Lexicon.format(this,i,t)}}(); \ No newline at end of file diff --git a/build/kairos-node.js b/build/kairos-node.js index c0c8a24..3fdc35d 100644 --- a/build/kairos-node.js +++ b/build/kairos-node.js @@ -1,7 +1,7 @@ /** * Kairos.js - A non date-based time calculator * @author Rodrigo Gomes da Silva - * @version v1.1.0 + * @version v2.0.0 * @link https://github.com/kairos * @license BSD-2-Clause */ @@ -9,10 +9,16 @@ * @module Kairos */ (function () { + 'use strict'; var Kairos = {}; + // Set defaults + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + Kairos._autoParser = false; + // global on the server, window in the browser var previous_Kairos; @@ -28,11 +34,11 @@ } /** - * Avoid conflict in case of another instance of Kairos is already in the scope + * Avoid conflict in case of another instance of Kairos is already in the scope. * * @memberof module:Kairos * @method noConflict - * @returns {Object} + * @returns {Object} Previous Kairos object */ Kairos.noConflict = function () { root.Kairos = previous_Kairos; @@ -40,314 +46,614 @@ }; /** - * Validates if the given expression is valid. + * Sets Kairos time expression pattern. + * Pattern structure is the following: + * # -> sign + * h -> hours + * m -> minutes + * s -> seconds + * S -> milliseconds * * @memberof module:Kairos - * @method validateExpression - * @param {String|Number} expression Time expression - * @returns {Boolean} + * @method setPattern + * @param {String} pattern The pattern to parse and format time expressions + * @example Kairos.setPattern('#hh:mm:ss.SSS'); */ - Kairos.validateExpression = function (expression) { - var regex = /^[+-]?\d+(?::?\d{1,2}(?::\d{1,2}(?::\d{1,3})?)?)?$/; - return regex.test(expression); + Kairos.setPattern = function (pattern) { + Kairos._validator = Kairos.Lexicon.getValidator(pattern); + Kairos._pattern = pattern; }; /** - * Return a Kairos.Gnomon instance. - * + * Gets current Kairos pattern. + * + * @memberof module:Kairos + * @method getPattern + * @returns {String} Current Kairos pattern + */ + Kairos.getPattern = function () { + return Kairos._pattern; + }; + + /** + * Sets Kairos configuration for auto parse feature. + * * @memberof module:Kairos - * @method with - * @param {String|Number} expression Time expression - * @returns {Kairos.Gnomon} + * @method setAutoParser + * @param {Boolean} yN True to use or false to not use auto parser + * @example Kairos.setAutoParser(true); */ - Kairos.with = function (expression) { - return new Kairos.Gnomon(expression); + Kairos.setAutoParser = function (yN) { + Kairos._autoParser = !!yN; }; /** - * Sums augend time with addend time + * Gets current Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method getAutoParser + * @returns {Boolean} True if auto parse is being used or false if not + */ + Kairos.getAutoParser = function () { + return Kairos._autoParser; + }; + + /** + * Validates the give expression with the current or given pattern. + * + * @memberof module:Kairos + * @method validate + * @param {String} expression Time expression to validate + * @param {String} pattern Pattern to test the expression + * @example Kairos.validate('10:30', 'hh:mm'); + * @returns {Boolean} True if valid, false if invalid + */ + Kairos.validate = function (expression, pattern) { + return Kairos.Lexicon.validate(expression, pattern); + }; + + /** + * Returns a new Kairos.Engine instance. + * + * @memberof module:Kairos + * @method new + * @param {String|Number|kairos.Engine} time Time expression to create an instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance from the given time + */ + Kairos.new = function (time, pattern) { + return new Kairos.Engine(time, pattern); + }; + + /** + * Returns an instance of Kairos.Engine with absolute time. + * + * @memberof module:Kairos + * @method absolute + * @param {String|Number|kairos.Engine} time Time expression to get its absolute value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with absolute value + */ + Kairos.absolute = function (time, pattern) { + return Kairos.new(time, pattern).toAbsolute(); + }; + + /** + * Sums augend time with addend time. * * @memberof module:Kairos * @method plus - * @param {String|Number} augend Augend time expression - * @param {String|Number} addend Addend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} augend Augend time expression + * @param {String|Number|kairos.Engine} addend Addend time expression + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the sum result */ - Kairos.plus = function (augend, addend) { - return Kairos.with(augend).plus(addend).toExpression(); + Kairos.plus = function (augend, addend, pattern) { + return Kairos.new(augend, pattern).plus(addend, pattern); }; /** - * Subtracts minuend time with subtrahend time + * Subtracts minuend time with subtrahend time. * * @memberof module:Kairos * @method minus - * @param {String|Number} minuend Minuend time expression - * @param {String|Number} subtrahend Subtrahend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} minuend Minuend time expression + * @param {String|Number|kairos.Engine} subtrahend Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with subtract result */ - Kairos.minus = function (minuend, subtrahend) { - return Kairos.with(minuend).minus(subtrahend).toExpression(); + Kairos.minus = function (minuend, subtrahend, pattern) { + return Kairos.new(minuend, pattern).minus(subtrahend, pattern); }; /** - * Multiplies multiplier by the multiplicand + * Multiplies multiplier by the multiplicand. * * @memberof module:Kairos * @method multiply - * @param {String|Number} multiplier Multiplier time expression - * @param {String|Number} multiplicand Multiplicand number - * @returns {String} + * @param {String|Number|kairos.Engine} multiplier Multiplier time expression + * @param {Number} multiplicand Multiplicand value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with multiplication result */ - Kairos.multiply = function (multiplier, multiplicand) { - return Kairos.with(multiplier).multiply(multiplicand).toExpression(); + Kairos.multiply = function (multiplier, multiplicand, pattern) { + return Kairos.new(multiplier, pattern).multiply(multiplicand); }; /** - * Divides dividend by the divisor + * Divides dividend by the divisor. * * @memberof module:Kairos * @method divide - * @param {String|Number} dividend Dividend time expression - * @param {Number} divisor Dividor number - * @returns {String} + * @param {String|Number|kairos.Engine} dividend Dividend time expression + * @param {Number} divisor Divisor value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with division result */ - Kairos.divide = function (dividend, divisor) { - return Kairos.with(dividend).divide(divisor).toExpression(); + Kairos.divide = function (dividend, divisor, pattern) { + return Kairos.new(dividend, pattern).divide(divisor); }; /** - * Returns a fraction of the current time + * Returns a fraction of the current time. * * @memberof module:Kairos * @method getFraction - * @param {String|Number} time - * @param {Number} numerator - * @param {Number} denominator - * @returns {String} + * @param {String|Number|Kairos.Engine} time Time expression to extract a fraction + * @param {Number} numerator Numerator value + * @param {Number} denominator Denominator value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the fraction extracted */ - Kairos.getFraction = function (time, numerator, denominator) { + Kairos.getFraction = function (time, numerator, denominator, pattern) { if (numerator > denominator) { throw new Error('Improper fraction'); } - return Kairos.with(time).multiply(numerator).divide(denominator).toExpression(); + return Kairos.new(time, pattern).multiply(numerator).divide(denominator); }; /** - * Returns a time expression representing the time between starting time and ending time + * Returns a time expression representing the time between starting time and ending time. * * @memberof module:Kairos * @method getInterval - * @param {String|Number} time1 time expression representing the starting time - * @param {String|Number} time2 time expression representing the ending time - * @returns {String} + * @param {String|Number|Kairos.Engine} time1 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String|Number|Kairos.Engine} time2 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the interval between time1 and time2 */ - Kairos.getInterval = function (starting, ending) { - var st = new Kairos.Gnomon(starting); - var en = new Kairos.Gnomon(ending); - if (st.compareTo(en) > 0) { - throw new Error('Starting time must be bigger than ending time'); - } - return en.minus(st).toExpression(); + Kairos.getInterval = function (time1, time2, pattern) { + return Kairos.new(time1, pattern).minus(time2, pattern).toAbsolute(); }; /** - * Converts the given time expression to milliseconds + * Converts the given time expression to milliseconds. * * @memberof module:Kairos * @method toMilliseconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total milliseconds in the time expression */ - Kairos.toMilliseconds = function (expression) { - return Kairos.with(expression).toMilliseconds(); + Kairos.toMilliseconds = function (time, pattern) { + return Kairos.new(time, pattern).toMilliseconds(); }; /** - * Converts the given time expression to seconds + * Converts the given time expression to seconds. * * @memberof module:Kairos * @method toSeconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total seconds in the time expression */ - Kairos.toSeconds = function (expression) { - return Kairos.with(expression).toSeconds(); + Kairos.toSeconds = function (time, pattern) { + return Kairos.new(time, pattern).toSeconds(); }; /** - * Converts the given time expression to minutes + * Converts the given time expression to minutes. * * @memberof module:Kairos * @method toMinutes - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total minutes in the time expression */ - Kairos.toMinutes = function (expression) { - return Kairos.with(expression).toMinutes(); + Kairos.toMinutes = function (time, pattern) { + return Kairos.new(time, pattern).toMinutes(); }; /** - * Converts the given time expression to hours + * Converts the given time expression to hours. * * @memberof module:Kairos * @method toHours - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total hours in the time expression */ - Kairos.toHours = function (expression) { - return Kairos.with(expression).toHours(); + Kairos.toHours = function (time, pattern) { + return Kairos.new(time, pattern).toHours(); }; /** * Compares first time with second time and returns -1, 0 or 1 if first value - * is smaller, equals or bigger than second value + * is smaller, equals or bigger than second value. * * @memberof module:Kairos * @method compare - * @param {String|Number} time1 Time expression - * @param {String|Number} time2 Time expression for comparation - * @returns {Number} + * @param {String|Number} comparand Time to compare with + * @param {String|Number} comparator Time to be compared with + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.compare = function (time1, time2) { - return Kairos.with(time1).compareTo(time2); + Kairos.compare = function (comparand, comparator, pattern) { + return Kairos.new(comparand, pattern).compareTo(comparator, pattern); }; /** - * Returns the minimum value from the given values + * Returns the minimum value from the given values. * * @memberof module:Kairos * @method min - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the lowest value found in the list */ - Kairos.min = function (values) { + Kairos.min = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var min = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() < current.toMilliseconds() ? previous : current ); + return Kairos.compare(previous, current, pattern) < 0 ? previous : current; }); - - return (min instanceof Kairos.Gnomon) ? min.toExpression() : new Kairos.Gnomon(min).toExpression(); + + return Kairos.new(min, pattern); }; /** - * Returns the maximum value from the given values + * Returns the maximum value from the given values. * * @memberof module:Kairos * @method max - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {String} Kairos.Engine instance with the greatest value found in the list */ - Kairos.max = function (values) { + Kairos.max = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var max = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() > current.toMilliseconds() ? previous : current ); + return Kairos.new(previous, pattern).compareTo(current, pattern) > 0 ? previous : current; }); - return (max instanceof Kairos.Gnomon) ? max.toExpression() : new Kairos.Gnomon(max).toExpression(); + return Kairos.new(max, pattern); }; // Node.js if (typeof module === 'object' && module.exports) { + /** + * @module Lexicon + */ (function () { + 'use strict'; /** - * - * @type {{SECOND: number, MINUTE: number, HOUR: number}} + * @type {{HOURS: string, MINUTES: string, SECONDS: string, MILLISECONDS: string}} */ - var MILLIS = { - SECOND: 1000, - MINUTE: 60 * 1000, - HOUR: 60 * 60 * 1000 + var TOKENS = { + SIGN: '#', HOURS: 'h', MINUTES: 'm', + SECONDS: 's', MILLISECONDS: 'S' }; + Kairos.Lexicon = {}; + /** - * Gnomon is the time engine for Kairos. It's name references the first solar clock ever made. - * - * @param {String|Number} expression Time expression - * @constructor + * Gets a regex from a pattern. + * + * @memberof module:Lexicon + * @method getValidator + * @param {String} [pattern] Pattern to convert + * @example Kairos.Lexicon.getValidator('#hh:mm:ss.SSS'); + * @returns {RegExp} */ - Kairos.Gnomon = function (expression) { - if (typeof expression === 'number') { + Kairos.Lexicon.getValidator = function (pattern) { + if (typeof pattern !== 'string') { + pattern = Kairos._pattern; + } + if (pattern === Kairos._pattern) { + return Kairos._validator; + } - this.milliseconds = expression; + var regex = ''; + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + regex += '^[+-]?'; + break; + case TOKENS.HOURS: + case TOKENS.MINUTES: + case TOKENS.SECONDS: + case TOKENS.MILLISECONDS: + regex += '\\d'; + break; + default: + regex += cur.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); + } + } + + return new RegExp(regex); + }; + + /** + * Validates if given expression matches the current pattern. + * + * @memberof module:Lexicon + * @method validate + * @param {String} expression Time expression to be validated + * @param {String} [pattern] Pattern to validate + * @example Kairos.Lexicon.validate('10:00:00.000', 'hh:mm:ss.SSS'); + * @returns {Boolean} True if expression is valid, false if expression is invalid + */ + Kairos.Lexicon.validate = function (expression, pattern) { + return Kairos.Lexicon.getValidator(pattern).test(expression); + }; + + /** + * Parses given time expression to a Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method parse + * @param {String} expression Time expression to be parsed + * @param {String} [pattern] Pattern to parse + * @example Kairos.Lexicon.parse('01:00:03', 'hh:mm:ss'); + * @returns {Kairos.Engine} Given expression parsed to Kairos.Engine + */ + Kairos.Lexicon.parse = function (expression, pattern) { + if (!pattern) { + pattern = Kairos._pattern; + } + if (!Kairos.Lexicon.validate(expression, pattern)) { + throw new Error('Cannot parse expression. Time format doesn\'t match the current time pattern.'); + } - } else if (typeof expression === 'string' && expression.length > 0) { - - if (!Kairos.validateExpression(expression)) { - throw new Error('Invalid time expression'); + var sign = true, hours = '', minutes = '', seconds = '', milliseconds = ''; + + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + var validSign = (['+', '-'].indexOf(expression[i]) !== -1); + if (!validSign) { + pattern = pattern.slice(0, i) + pattern.slice(i + 1); + len--; + i--; + } else { + sign = expression[i] === '+'; + } + break; + case TOKENS.HOURS: + hours += expression[i]; + break; + case TOKENS.MINUTES: + minutes += expression[i]; + break; + case TOKENS.SECONDS: + seconds += expression[i]; + break; + case TOKENS.MILLISECONDS: + milliseconds += expression[i]; + break; } + } - var timeSteps = expression.split(':'); - var positive = expression.slice(0, 1)[0] !== '-'; + var result = Kairos.new() + .addHours(hours ? +hours : 0) + .addMinutes(minutes ? +minutes : 0) + .addSeconds(seconds ? +seconds : 0) + .addMilliseconds(milliseconds ? +milliseconds : 0); - for (var i = 0, len = timeSteps.length; i < len; i++) { - var timeStep = timeSteps[i]; + if (!sign) { + result.milliseconds =- result.milliseconds; + } - timeStep = Math.abs(timeStep); - switch (i) { - case 0: - this.milliseconds = _parse(this, MILLIS.HOUR, timeStep); - break; - case 1: - this.milliseconds = _parse(this, MILLIS.MINUTE, timeStep); + return result; + }; + + /** + * Returns a formated string from an Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method format + * @param {Kairos.Engine} instance The instance to format + * @param {String} [pattern] Pattern to format + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example Kairos.Lexicon.format(Kairos.new('10:30'), 'mm:hh'); + * @returns {String} Formated time expression + */ + Kairos.Lexicon.format = function (instance, pattern, allowOverflow) { + if (!pattern) { + pattern = Kairos._pattern; + } + + var sign = instance.milliseconds >= 0, + hours = String(Math.abs(instance.getHours())), + minutes = String(Math.abs(instance.getMinutes())), + seconds = String(Math.abs(instance.getSeconds())), + milliseconds = String(Math.abs(instance.getMilliseconds())); + + var result = '', + hasOverflow = (hours.length > (pattern.match(/h/g) || []).length); + + for (var i = pattern.length - 1; i >= 0; i--) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + result = (sign ? '+' : '-') + result; + break; + case TOKENS.HOURS: + if (hasOverflow) { + if (allowOverflow) { + result = hours + result; + allowOverflow = false; + } + break; + } + result = (hours.slice(-1) || '0') + result; + if (hours.length > 0) { + hours = hours.slice(0, hours.length - 1); + } + break; + case TOKENS.MINUTES: + result = (minutes.slice(-1) || '0') + result; + if (minutes.length > 0) { + minutes = minutes.slice(0, minutes.length - 1); + } + break; + case TOKENS.SECONDS: + result = (seconds.slice(-1) || '0') + result; + if (seconds.length > 0) { + seconds = seconds.slice(0, seconds.length - 1); + } + break; + case TOKENS.MILLISECONDS: + result = (milliseconds.slice(-1) || '0') + result; + if (milliseconds.length > 0) { + milliseconds = milliseconds.slice(0, milliseconds.length - 1); + } + break; + default: + result = cur + result; + } + } + + return result; + }; + + /** + * Tries to extract a pattern from the given expression. + * + * @memberof module:Lexicon + * @method findPattern + * @param {String} expression Expression to be analysed + * @example Kairos.Lexicon.findPattern('01:05:30'); + * @returns {String} Extracted pattern + */ + Kairos.Lexicon.findPattern = function (expression) { + var pattern = '', + currentStep = TOKENS.HOURS; + for (var i = 0, len = expression.length; len > i; i++) { + var cur = expression[i]; + + if (['+', '-'].indexOf(cur) !== -1) { + pattern += TOKENS.SIGN; + continue; + } + + if (!isNaN(cur)) { + pattern += currentStep || cur; + continue; + } + + if (isNaN(cur)) { + pattern += cur; + switch (currentStep) { + case TOKENS.HOURS: + currentStep = TOKENS.MINUTES; break; - case 2: - this.milliseconds = _parse(this, MILLIS.SECOND, timeStep); + case TOKENS.MINUTES: + currentStep = TOKENS.SECONDS; break; - case 3: - this.milliseconds = _parse(this, 1, timeStep); + case TOKENS.SECONDS: + currentStep = TOKENS.MILLISECONDS; break; + default: + currentStep = false; } + continue; } - if (!positive) { - this.milliseconds = -Math.abs(this.milliseconds); + } + + return pattern; + }; + }()); + (function () { + + 'use strict'; + + /** + * @type {{SECOND: number, MINUTE: number, HOUR: number}} + */ + var MILLIS = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000 + }; + + /** + * Kairos time engine. + * + * @param {String|Number|Kairos.Engine} expression Literal time expression, milliseconds or a Kairos.Engine instance + * @pattern {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('10:30', 'hh:mm'); + * @constructor + */ + Kairos.Engine = function (expression, pattern) { + if (!expression) { + return; + } + + if (expression instanceof Kairos.Engine) { + return expression; + } + + if (typeof expression === 'number') { + this.milliseconds = expression; + return this; + } + + if (typeof expression === 'string' && expression.length > 0) { + if (Kairos.getAutoParser()) { + pattern = Kairos.Lexicon.findPattern(expression); } + return new Kairos.Lexicon.parse(expression, pattern); } + + throw new Error('Invalid arguments'); }; /** - * @param {Kairos.Gnomon} instance + * @param {Kairos.Engine} instance * @param {Number} millis * @param {Number} time * @returns {Number} * @private */ - var _parse = function (instance, millis, time) { + Kairos.Engine.prototype._resolveStep = function (millis, time) { switch (millis) { case 1: - instance.removeMilliseconds(instance.getMilliseconds()); + this.removeMilliseconds(this.getMilliseconds()); break; case MILLIS.SECOND: - instance.removeSeconds(instance.getSeconds()); + this.removeSeconds(this.getSeconds()); break; case MILLIS.MINUTE: - instance.removeMinutes(instance.getMinutes()); + this.removeMinutes(this.getMinutes()); break; case MILLIS.HOUR: - instance.removeHours(instance.getHours()); + this.removeHours(this.getHours()); break; } - return instance.milliseconds + (time * millis); + return this.milliseconds + (time * millis); }; /** @@ -355,271 +661,305 @@ * @default 0 * @protected */ - Kairos.Gnomon.prototype.milliseconds = 0; + Kairos.Engine.prototype.milliseconds = 0; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Sets hours fraction in the current instance. + * + * @param {Number} hours Hours to set + * @example new Kairos.Engine('01:00').setHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setHours = function (hours) { - this.milliseconds = _parse(this, MILLIS.HOUR, hours); + Kairos.Engine.prototype.setHours = function (hours) { + this.milliseconds = this._resolveStep(MILLIS.HOUR, hours); return this; }; /** - * - * @returns {*|Number} + * Gets hours fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getHours(); + * @returns {Number} Hours fraction from the instance */ - Kairos.Gnomon.prototype.getHours = function () { + Kairos.Engine.prototype.getHours = function () { return Math.trunc(this.milliseconds / MILLIS.HOUR); }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Sets minutes fraction in the current instance. + * + * @param {Number} minutes Minutes to set + * @example new Kairos.Engine('01:00').setMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMinutes = function (minutes) { - this.milliseconds = _parse(this, MILLIS.MINUTE, minutes); + Kairos.Engine.prototype.setMinutes = function (minutes) { + this.milliseconds = this._resolveStep(MILLIS.MINUTE, minutes); return this; }; /** - * - * @returns {*|Number} + * Gets minutes fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMinutes(); + * @returns {Number} Minutes fraction from the instance */ - Kairos.Gnomon.prototype.getMinutes = function () { + Kairos.Engine.prototype.getMinutes = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toHours()) * MILLIS.HOUR)) / MILLIS.MINUTE); }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Sets seconds fraction in the current instance. + * + * @param {Number} seconds Seconds to set + * @example new Kairos.Engine('01:00').setSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setSeconds = function (seconds) { - this.milliseconds = _parse(this, MILLIS.SECOND, seconds); + Kairos.Engine.prototype.setSeconds = function (seconds) { + this.milliseconds = this._resolveStep(MILLIS.SECOND, seconds); return this; }; /** - * - * @returns {*|Number} + * Gets seconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getSeconds(); + * @returns {Number} Seconds fraction from the instance */ - Kairos.Gnomon.prototype.getSeconds = function () { + Kairos.Engine.prototype.getSeconds = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toMinutes()) * MILLIS.MINUTE)) / MILLIS.SECOND); }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Sets milliseconds fraction in the current instance. + * + * @param {Number} milliseconds Milliseconds to set + * @example new Kairos.Engine('01:00').setMilliseconds(200); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMilliseconds = function (milliseconds) { - this.milliseconds = _parse(this, 1, milliseconds); + Kairos.Engine.prototype.setMilliseconds = function (milliseconds) { + this.milliseconds = this._resolveStep(1, milliseconds); return this; }; /** - * - * @returns {Number|*} + * Gets milliseconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMilliseconds(); + * @returns {Number} Milliseconds fraction from the instance */ - Kairos.Gnomon.prototype.getMilliseconds = function () { + Kairos.Engine.prototype.getMilliseconds = function () { return Math.trunc(this.milliseconds - (Math.trunc(this.toSeconds()) * MILLIS.SECOND)); }; /** + * Adds hours to the current instance. * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * @param {Number} hours Hours to add + * @example new Kairos.Engine('01:00').addHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addHours = function (hours) { + Kairos.Engine.prototype.addHours = function (hours) { this.milliseconds += (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Adds minutes to the current instance. + * + * @param {Number} minutes Minutes to add + * @example new Kairos.Engine('01:00').addMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMinutes = function (minutes) { + Kairos.Engine.prototype.addMinutes = function (minutes) { this.milliseconds += (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Adds seconds in the current instance. + * + * @param {Number} seconds Seconds to add + * @example new Kairos.Engine('01:00').addSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addSeconds = function (seconds) { + Kairos.Engine.prototype.addSeconds = function (seconds) { this.milliseconds += (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Adds milliseconds in the current instance. + * + * @param {Number} milliseconds Milliseconds to add + * @example new Kairos.Engine('01:00').addMilliseconds(500); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.addMilliseconds = function (milliseconds) { this.milliseconds += milliseconds; return this; }; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Removes hours from the current instance. + * + * @param {Number} hours Hours to remove + * @example new Kairos.Engine('01:00').removeHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeHours = function (hours) { + Kairos.Engine.prototype.removeHours = function (hours) { this.milliseconds -= (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Removes minutes from the current instance. + * + * @param {Number} minutes Minutes to remove + * @example new Kairos.Engine('01:00').removeMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMinutes = function (minutes) { + Kairos.Engine.prototype.removeMinutes = function (minutes) { this.milliseconds -= (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Removes seconds from the current instance. + * + * @param {Number} seconds Seconds to remove + * @example new Kairos.Engine('01:00').removeSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeSeconds = function (seconds) { + Kairos.Engine.prototype.removeSeconds = function (seconds) { this.milliseconds -= (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Removes milliseconds from the current instance. + * + * @example new Kairos.Engine('01:00').removeMilliseconds(50); + * @param {Number} milliseconds Milliseconds to remove + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.removeMilliseconds = function (milliseconds) { this.milliseconds -= milliseconds; return this; }; /** - * - * @returns {Number} hours within the time expression + * Returns total hours within the current instance. + * + * @example new Kairos.Engine('01:00').toHours(); + * @returns {Number} Hours within the current instance */ - Kairos.Gnomon.prototype.toHours = function () { + Kairos.Engine.prototype.toHours = function () { return (this.milliseconds / MILLIS.HOUR); }; /** - * - * @returns {Number} minutes within the time expression + * Returns total minutes within the current instance. + * + * @example new Kairos.Engine('01:00').toMinutes(); + * @returns {Number} Minutes within the current instance */ - Kairos.Gnomon.prototype.toMinutes = function () { + Kairos.Engine.prototype.toMinutes = function () { return (this.milliseconds / MILLIS.MINUTE); }; /** - * - * @returns {Number} seconds within the time expression + * Returns total seconds within the current instance. + * + * @example new Kairos.Engine('01:00').toSeconds(); + * @returns {Number} Seconds within the current instance */ - Kairos.Gnomon.prototype.toSeconds = function () { + Kairos.Engine.prototype.toSeconds = function () { return (this.milliseconds / MILLIS.SECOND); }; /** - * - * @returns {Number} milliseconds within the time expression + * Returns total milliseconds within the current instance. + * + * @example new Kairos.Engine('01:00').toMilliseconds(); + * @returns {Number} Milliseconds within the current instance */ - Kairos.Gnomon.prototype.toMilliseconds = function () { + Kairos.Engine.prototype.toMilliseconds = function () { return this.milliseconds; }; /** - * - * @returns {String} - */ - Kairos.Gnomon.prototype.toExpression = function () { - var expression = ''; - // Hours - var hours = Math.trunc(Math.abs(this.getHours())); - expression += ((String(hours).length > 1) ? '' : '0') + hours + ':'; - // Minutes - expression += ('00' + Math.trunc(Math.abs(this.getMinutes()))).slice(-2); - // Seconds - if (this.getSeconds() !== 0 || this.getMilliseconds() !== 0) { - expression += ':' + ('00' + Math.trunc(Math.abs(this.getSeconds()))).slice(-2); - } - // Millis - if (this.getMilliseconds() !== 0) { - expression += ':' + ('000' + Math.trunc(Math.abs(this.getMilliseconds()))).slice(-3); - } - - if (this.milliseconds < 0) { - expression = '-' + expression; - } - return expression; + * Makes the current instance's value absolute. + * + * @example new Kairos.Engine('01:00').toAbsolute(); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.toAbsolute = function () { + this.milliseconds = Math.abs(this.milliseconds); + return this; }; /** - * - * @param {Number|String|Kairos.Gnomon} addend - * @returns {Kairos.Gnomon} self + * Sums the given addend. + * + * @param {Number|String|Kairos.Engine} addend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.plus = function (addend) { - addend = (addend instanceof Kairos.Gnomon) ? addend : new Kairos.Gnomon(addend); + Kairos.Engine.prototype.plus = function (addend, pattern) { + addend = new Kairos.Engine(addend, pattern); this.milliseconds += addend.toMilliseconds(); return this; }; /** + * Subtracts the given subtrahend. * - * @param {Number|String|Kairos.Gnomon} subtrahend - * @returns {Kairos.Gnomon} self + * @param {Number|String|Kairos.Engine} subtrahend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.minus = function (subtrahend) { - subtrahend = (subtrahend instanceof Kairos.Gnomon) ? subtrahend : new Kairos.Gnomon(subtrahend); + Kairos.Engine.prototype.minus = function (subtrahend, pattern) { + subtrahend = new Kairos.Engine(subtrahend, pattern); this.milliseconds -= subtrahend.toMilliseconds(); return this; }; /** - * - * @param {Number} multiplicand - * @returns {Kairos.Gnomon} self + * Multiply by the given multiplicand. + * + * @param {Number} multiplicand Multiplicand value + * @example new Kairos.Engine('01:00').multiply(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.multiply = function (multiplicand) { + Kairos.Engine.prototype.multiply = function (multiplicand) { this.milliseconds *= multiplicand; return this; }; /** - * - * @param {Number} dividend - * @returns {Kairos.Gnomon} self + * Divies by the given dividend. + * + * @param {Number} divisor Divisor value + * @example new Kairos.Engine('01:00').divide(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.divide = function (dividend) { - this.milliseconds /= dividend; + Kairos.Engine.prototype.divide = function (divisor) { + this.milliseconds /= divisor; return this; }; /** * Compares with another instance. - * Smaller -1 - * Equals 0 - * Bigger 1 * - * @param {String|Number|Kairos.Gnomon} another Expression to compare with - * @returns {Number} + * @param {String|Number|Kairos.Engine} another Expression to compare with + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').compareTo('00:30'); + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.Gnomon.prototype.compareTo = function (another) { - another = (another instanceof Kairos.Gnomon) ? another : new Kairos.Gnomon(another); + Kairos.Engine.prototype.compareTo = function (another, pattern) { + another = new Kairos.Engine(another, pattern); if (this.milliseconds < another.toMilliseconds()) { return -1; @@ -631,6 +971,22 @@ return 1; } }; + + /** + * Returns a string representation of the object. + * + * @param {String} pattern Pattern to format the time expression + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example new Kairos.Engine('22:10').toString('hh:mm'); + * @returns {String} String representing the instance time + */ + Kairos.Engine.prototype.toString = function (pattern, allowOverflow) { + if (typeof pattern === 'boolean') { + allowOverflow = pattern; + pattern = null; + } + return Kairos.Lexicon.format(this, pattern, allowOverflow); + }; }()); module.exports = Kairos; } diff --git a/build/kairos.js b/build/kairos.js index 96c4a01..535393c 100644 --- a/build/kairos.js +++ b/build/kairos.js @@ -1,7 +1,7 @@ /** * Kairos.js - A non date-based time calculator * @author Rodrigo Gomes da Silva - * @version v1.1.0 + * @version v2.0.0 * @link https://github.com/kairos * @license BSD-2-Clause */ @@ -9,10 +9,16 @@ * @module Kairos */ (function () { + 'use strict'; var Kairos = {}; + // Set defaults + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + Kairos._autoParser = false; + // global on the server, window in the browser var previous_Kairos; @@ -28,11 +34,11 @@ } /** - * Avoid conflict in case of another instance of Kairos is already in the scope + * Avoid conflict in case of another instance of Kairos is already in the scope. * * @memberof module:Kairos * @method noConflict - * @returns {Object} + * @returns {Object} Previous Kairos object */ Kairos.noConflict = function () { root.Kairos = previous_Kairos; @@ -40,234 +46,301 @@ }; /** - * Validates if the given expression is valid. + * Sets Kairos time expression pattern. + * Pattern structure is the following: + * # -> sign + * h -> hours + * m -> minutes + * s -> seconds + * S -> milliseconds * * @memberof module:Kairos - * @method validateExpression - * @param {String|Number} expression Time expression - * @returns {Boolean} + * @method setPattern + * @param {String} pattern The pattern to parse and format time expressions + * @example Kairos.setPattern('#hh:mm:ss.SSS'); */ - Kairos.validateExpression = function (expression) { - var regex = /^[+-]?\d+(?::?\d{1,2}(?::\d{1,2}(?::\d{1,3})?)?)?$/; - return regex.test(expression); + Kairos.setPattern = function (pattern) { + Kairos._validator = Kairos.Lexicon.getValidator(pattern); + Kairos._pattern = pattern; }; /** - * Return a Kairos.Gnomon instance. - * + * Gets current Kairos pattern. + * + * @memberof module:Kairos + * @method getPattern + * @returns {String} Current Kairos pattern + */ + Kairos.getPattern = function () { + return Kairos._pattern; + }; + + /** + * Sets Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method setAutoParser + * @param {Boolean} yN True to use or false to not use auto parser + * @example Kairos.setAutoParser(true); + */ + Kairos.setAutoParser = function (yN) { + Kairos._autoParser = !!yN; + }; + + /** + * Gets current Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method getAutoParser + * @returns {Boolean} True if auto parse is being used or false if not + */ + Kairos.getAutoParser = function () { + return Kairos._autoParser; + }; + + /** + * Validates the give expression with the current or given pattern. + * + * @memberof module:Kairos + * @method validate + * @param {String} expression Time expression to validate + * @param {String} pattern Pattern to test the expression + * @example Kairos.validate('10:30', 'hh:mm'); + * @returns {Boolean} True if valid, false if invalid + */ + Kairos.validate = function (expression, pattern) { + return Kairos.Lexicon.validate(expression, pattern); + }; + + /** + * Returns a new Kairos.Engine instance. + * + * @memberof module:Kairos + * @method new + * @param {String|Number|kairos.Engine} time Time expression to create an instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance from the given time + */ + Kairos.new = function (time, pattern) { + return new Kairos.Engine(time, pattern); + }; + + /** + * Returns an instance of Kairos.Engine with absolute time. + * * @memberof module:Kairos - * @method with - * @param {String|Number} expression Time expression - * @returns {Kairos.Gnomon} + * @method absolute + * @param {String|Number|kairos.Engine} time Time expression to get its absolute value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with absolute value */ - Kairos.with = function (expression) { - return new Kairos.Gnomon(expression); + Kairos.absolute = function (time, pattern) { + return Kairos.new(time, pattern).toAbsolute(); }; /** - * Sums augend time with addend time + * Sums augend time with addend time. * * @memberof module:Kairos * @method plus - * @param {String|Number} augend Augend time expression - * @param {String|Number} addend Addend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} augend Augend time expression + * @param {String|Number|kairos.Engine} addend Addend time expression + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the sum result */ - Kairos.plus = function (augend, addend) { - return Kairos.with(augend).plus(addend).toExpression(); + Kairos.plus = function (augend, addend, pattern) { + return Kairos.new(augend, pattern).plus(addend, pattern); }; /** - * Subtracts minuend time with subtrahend time + * Subtracts minuend time with subtrahend time. * * @memberof module:Kairos * @method minus - * @param {String|Number} minuend Minuend time expression - * @param {String|Number} subtrahend Subtrahend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} minuend Minuend time expression + * @param {String|Number|kairos.Engine} subtrahend Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with subtract result */ - Kairos.minus = function (minuend, subtrahend) { - return Kairos.with(minuend).minus(subtrahend).toExpression(); + Kairos.minus = function (minuend, subtrahend, pattern) { + return Kairos.new(minuend, pattern).minus(subtrahend, pattern); }; /** - * Multiplies multiplier by the multiplicand + * Multiplies multiplier by the multiplicand. * * @memberof module:Kairos * @method multiply - * @param {String|Number} multiplier Multiplier time expression - * @param {String|Number} multiplicand Multiplicand number - * @returns {String} + * @param {String|Number|kairos.Engine} multiplier Multiplier time expression + * @param {Number} multiplicand Multiplicand value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with multiplication result */ - Kairos.multiply = function (multiplier, multiplicand) { - return Kairos.with(multiplier).multiply(multiplicand).toExpression(); + Kairos.multiply = function (multiplier, multiplicand, pattern) { + return Kairos.new(multiplier, pattern).multiply(multiplicand); }; /** - * Divides dividend by the divisor + * Divides dividend by the divisor. * * @memberof module:Kairos * @method divide - * @param {String|Number} dividend Dividend time expression - * @param {Number} divisor Dividor number - * @returns {String} + * @param {String|Number|kairos.Engine} dividend Dividend time expression + * @param {Number} divisor Divisor value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with division result */ - Kairos.divide = function (dividend, divisor) { - return Kairos.with(dividend).divide(divisor).toExpression(); + Kairos.divide = function (dividend, divisor, pattern) { + return Kairos.new(dividend, pattern).divide(divisor); }; /** - * Returns a fraction of the current time + * Returns a fraction of the current time. * * @memberof module:Kairos * @method getFraction - * @param {String|Number} time - * @param {Number} numerator - * @param {Number} denominator - * @returns {String} + * @param {String|Number|Kairos.Engine} time Time expression to extract a fraction + * @param {Number} numerator Numerator value + * @param {Number} denominator Denominator value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the fraction extracted */ - Kairos.getFraction = function (time, numerator, denominator) { + Kairos.getFraction = function (time, numerator, denominator, pattern) { if (numerator > denominator) { throw new Error('Improper fraction'); } - return Kairos.with(time).multiply(numerator).divide(denominator).toExpression(); + return Kairos.new(time, pattern).multiply(numerator).divide(denominator); }; /** - * Returns a time expression representing the time between starting time and ending time + * Returns a time expression representing the time between starting time and ending time. * * @memberof module:Kairos * @method getInterval - * @param {String|Number} time1 time expression representing the starting time - * @param {String|Number} time2 time expression representing the ending time - * @returns {String} - */ - Kairos.getInterval = function (starting, ending) { - var st = new Kairos.Gnomon(starting); - var en = new Kairos.Gnomon(ending); - if (st.compareTo(en) > 0) { - throw new Error('Starting time must be bigger than ending time'); - } - return en.minus(st).toExpression(); + * @param {String|Number|Kairos.Engine} time1 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String|Number|Kairos.Engine} time2 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the interval between time1 and time2 + */ + Kairos.getInterval = function (time1, time2, pattern) { + return Kairos.new(time1, pattern).minus(time2, pattern).toAbsolute(); }; /** - * Converts the given time expression to milliseconds + * Converts the given time expression to milliseconds. * * @memberof module:Kairos * @method toMilliseconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total milliseconds in the time expression */ - Kairos.toMilliseconds = function (expression) { - return Kairos.with(expression).toMilliseconds(); + Kairos.toMilliseconds = function (time, pattern) { + return Kairos.new(time, pattern).toMilliseconds(); }; /** - * Converts the given time expression to seconds + * Converts the given time expression to seconds. * * @memberof module:Kairos * @method toSeconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total seconds in the time expression */ - Kairos.toSeconds = function (expression) { - return Kairos.with(expression).toSeconds(); + Kairos.toSeconds = function (time, pattern) { + return Kairos.new(time, pattern).toSeconds(); }; /** - * Converts the given time expression to minutes + * Converts the given time expression to minutes. * * @memberof module:Kairos * @method toMinutes - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total minutes in the time expression */ - Kairos.toMinutes = function (expression) { - return Kairos.with(expression).toMinutes(); + Kairos.toMinutes = function (time, pattern) { + return Kairos.new(time, pattern).toMinutes(); }; /** - * Converts the given time expression to hours + * Converts the given time expression to hours. * * @memberof module:Kairos * @method toHours - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total hours in the time expression */ - Kairos.toHours = function (expression) { - return Kairos.with(expression).toHours(); + Kairos.toHours = function (time, pattern) { + return Kairos.new(time, pattern).toHours(); }; /** * Compares first time with second time and returns -1, 0 or 1 if first value - * is smaller, equals or bigger than second value + * is smaller, equals or bigger than second value. * * @memberof module:Kairos * @method compare - * @param {String|Number} time1 Time expression - * @param {String|Number} time2 Time expression for comparation - * @returns {Number} + * @param {String|Number} comparand Time to compare with + * @param {String|Number} comparator Time to be compared with + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.compare = function (time1, time2) { - return Kairos.with(time1).compareTo(time2); + Kairos.compare = function (comparand, comparator, pattern) { + return Kairos.new(comparand, pattern).compareTo(comparator, pattern); }; /** - * Returns the minimum value from the given values + * Returns the minimum value from the given values. * * @memberof module:Kairos * @method min - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the lowest value found in the list */ - Kairos.min = function (values) { + Kairos.min = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var min = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() < current.toMilliseconds() ? previous : current ); + return Kairos.compare(previous, current, pattern) < 0 ? previous : current; }); - - return (min instanceof Kairos.Gnomon) ? min.toExpression() : new Kairos.Gnomon(min).toExpression(); + + return Kairos.new(min, pattern); }; /** - * Returns the maximum value from the given values + * Returns the maximum value from the given values. * * @memberof module:Kairos * @method max - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {String} Kairos.Engine instance with the greatest value found in the list */ - Kairos.max = function (values) { + Kairos.max = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var max = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() > current.toMilliseconds() ? previous : current ); + return Kairos.new(previous, pattern).compareTo(current, pattern) > 0 ? previous : current; }); - return (max instanceof Kairos.Gnomon) ? max.toExpression() : new Kairos.Gnomon(max).toExpression(); + return Kairos.new(max, pattern); }; // Node.js if (typeof module === 'object' && module.exports) { - //=include /engine/Gnomon.js + //=include /Lexicon.js + //=include /Engine.js module.exports = Kairos; } // AMD / RequireJS @@ -286,87 +359,321 @@ return x < 0 ? Math.ceil(x) : Math.floor(x); }; }()); +/** + * @module Lexicon + */ (function () { + 'use strict'; /** - * - * @type {{SECOND: number, MINUTE: number, HOUR: number}} + * @type {{HOURS: string, MINUTES: string, SECONDS: string, MILLISECONDS: string}} */ - var MILLIS = { - SECOND: 1000, - MINUTE: 60 * 1000, - HOUR: 60 * 60 * 1000 + var TOKENS = { + SIGN: '#', HOURS: 'h', MINUTES: 'm', + SECONDS: 's', MILLISECONDS: 'S' }; + Kairos.Lexicon = {}; + /** - * Gnomon is the time engine for Kairos. It's name references the first solar clock ever made. - * - * @param {String|Number} expression Time expression - * @constructor + * Gets a regex from a pattern. + * + * @memberof module:Lexicon + * @method getValidator + * @param {String} [pattern] Pattern to convert + * @example Kairos.Lexicon.getValidator('#hh:mm:ss.SSS'); + * @returns {RegExp} + */ + Kairos.Lexicon.getValidator = function (pattern) { + if (typeof pattern !== 'string') { + pattern = Kairos._pattern; + } + if (pattern === Kairos._pattern) { + return Kairos._validator; + } + + var regex = ''; + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + regex += '^[+-]?'; + break; + case TOKENS.HOURS: + case TOKENS.MINUTES: + case TOKENS.SECONDS: + case TOKENS.MILLISECONDS: + regex += '\\d'; + break; + default: + regex += cur.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); + } + } + + return new RegExp(regex); + }; + + /** + * Validates if given expression matches the current pattern. + * + * @memberof module:Lexicon + * @method validate + * @param {String} expression Time expression to be validated + * @param {String} [pattern] Pattern to validate + * @example Kairos.Lexicon.validate('10:00:00.000', 'hh:mm:ss.SSS'); + * @returns {Boolean} True if expression is valid, false if expression is invalid */ - Kairos.Gnomon = function (expression) { - if (typeof expression === 'number') { + Kairos.Lexicon.validate = function (expression, pattern) { + return Kairos.Lexicon.getValidator(pattern).test(expression); + }; - this.milliseconds = expression; + /** + * Parses given time expression to a Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method parse + * @param {String} expression Time expression to be parsed + * @param {String} [pattern] Pattern to parse + * @example Kairos.Lexicon.parse('01:00:03', 'hh:mm:ss'); + * @returns {Kairos.Engine} Given expression parsed to Kairos.Engine + */ + Kairos.Lexicon.parse = function (expression, pattern) { + if (!pattern) { + pattern = Kairos._pattern; + } + if (!Kairos.Lexicon.validate(expression, pattern)) { + throw new Error('Cannot parse expression. Time format doesn\'t match the current time pattern.'); + } - } else if (typeof expression === 'string' && expression.length > 0) { - - if (!Kairos.validateExpression(expression)) { - throw new Error('Invalid time expression'); + var sign = true, hours = '', minutes = '', seconds = '', milliseconds = ''; + + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + var validSign = (['+', '-'].indexOf(expression[i]) !== -1); + if (!validSign) { + pattern = pattern.slice(0, i) + pattern.slice(i + 1); + len--; + i--; + } else { + sign = expression[i] === '+'; + } + break; + case TOKENS.HOURS: + hours += expression[i]; + break; + case TOKENS.MINUTES: + minutes += expression[i]; + break; + case TOKENS.SECONDS: + seconds += expression[i]; + break; + case TOKENS.MILLISECONDS: + milliseconds += expression[i]; + break; } + } + + var result = Kairos.new() + .addHours(hours ? +hours : 0) + .addMinutes(minutes ? +minutes : 0) + .addSeconds(seconds ? +seconds : 0) + .addMilliseconds(milliseconds ? +milliseconds : 0); - var timeSteps = expression.split(':'); - var positive = expression.slice(0, 1)[0] !== '-'; + if (!sign) { + result.milliseconds =- result.milliseconds; + } - for (var i = 0, len = timeSteps.length; i < len; i++) { - var timeStep = timeSteps[i]; + return result; + }; - timeStep = Math.abs(timeStep); - switch (i) { - case 0: - this.milliseconds = _parse(this, MILLIS.HOUR, timeStep); - break; - case 1: - this.milliseconds = _parse(this, MILLIS.MINUTE, timeStep); + /** + * Returns a formated string from an Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method format + * @param {Kairos.Engine} instance The instance to format + * @param {String} [pattern] Pattern to format + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example Kairos.Lexicon.format(Kairos.new('10:30'), 'mm:hh'); + * @returns {String} Formated time expression + */ + Kairos.Lexicon.format = function (instance, pattern, allowOverflow) { + if (!pattern) { + pattern = Kairos._pattern; + } + + var sign = instance.milliseconds >= 0, + hours = String(Math.abs(instance.getHours())), + minutes = String(Math.abs(instance.getMinutes())), + seconds = String(Math.abs(instance.getSeconds())), + milliseconds = String(Math.abs(instance.getMilliseconds())); + + var result = '', + hasOverflow = (hours.length > (pattern.match(/h/g) || []).length); + + for (var i = pattern.length - 1; i >= 0; i--) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + result = (sign ? '+' : '-') + result; + break; + case TOKENS.HOURS: + if (hasOverflow) { + if (allowOverflow) { + result = hours + result; + allowOverflow = false; + } + break; + } + result = (hours.slice(-1) || '0') + result; + if (hours.length > 0) { + hours = hours.slice(0, hours.length - 1); + } + break; + case TOKENS.MINUTES: + result = (minutes.slice(-1) || '0') + result; + if (minutes.length > 0) { + minutes = minutes.slice(0, minutes.length - 1); + } + break; + case TOKENS.SECONDS: + result = (seconds.slice(-1) || '0') + result; + if (seconds.length > 0) { + seconds = seconds.slice(0, seconds.length - 1); + } + break; + case TOKENS.MILLISECONDS: + result = (milliseconds.slice(-1) || '0') + result; + if (milliseconds.length > 0) { + milliseconds = milliseconds.slice(0, milliseconds.length - 1); + } + break; + default: + result = cur + result; + } + } + + return result; + }; + + /** + * Tries to extract a pattern from the given expression. + * + * @memberof module:Lexicon + * @method findPattern + * @param {String} expression Expression to be analysed + * @example Kairos.Lexicon.findPattern('01:05:30'); + * @returns {String} Extracted pattern + */ + Kairos.Lexicon.findPattern = function (expression) { + var pattern = '', + currentStep = TOKENS.HOURS; + for (var i = 0, len = expression.length; len > i; i++) { + var cur = expression[i]; + + if (['+', '-'].indexOf(cur) !== -1) { + pattern += TOKENS.SIGN; + continue; + } + + if (!isNaN(cur)) { + pattern += currentStep || cur; + continue; + } + + if (isNaN(cur)) { + pattern += cur; + switch (currentStep) { + case TOKENS.HOURS: + currentStep = TOKENS.MINUTES; break; - case 2: - this.milliseconds = _parse(this, MILLIS.SECOND, timeStep); + case TOKENS.MINUTES: + currentStep = TOKENS.SECONDS; break; - case 3: - this.milliseconds = _parse(this, 1, timeStep); + case TOKENS.SECONDS: + currentStep = TOKENS.MILLISECONDS; break; + default: + currentStep = false; } + continue; } - if (!positive) { - this.milliseconds = -Math.abs(this.milliseconds); + } + + return pattern; + }; +}()); +(function () { + + 'use strict'; + + /** + * @type {{SECOND: number, MINUTE: number, HOUR: number}} + */ + var MILLIS = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000 + }; + + /** + * Kairos time engine. + * + * @param {String|Number|Kairos.Engine} expression Literal time expression, milliseconds or a Kairos.Engine instance + * @pattern {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('10:30', 'hh:mm'); + * @constructor + */ + Kairos.Engine = function (expression, pattern) { + if (!expression) { + return; + } + + if (expression instanceof Kairos.Engine) { + return expression; + } + + if (typeof expression === 'number') { + this.milliseconds = expression; + return this; + } + + if (typeof expression === 'string' && expression.length > 0) { + if (Kairos.getAutoParser()) { + pattern = Kairos.Lexicon.findPattern(expression); } + return new Kairos.Lexicon.parse(expression, pattern); } + + throw new Error('Invalid arguments'); }; /** - * @param {Kairos.Gnomon} instance + * @param {Kairos.Engine} instance * @param {Number} millis * @param {Number} time * @returns {Number} * @private */ - var _parse = function (instance, millis, time) { + Kairos.Engine.prototype._resolveStep = function (millis, time) { switch (millis) { case 1: - instance.removeMilliseconds(instance.getMilliseconds()); + this.removeMilliseconds(this.getMilliseconds()); break; case MILLIS.SECOND: - instance.removeSeconds(instance.getSeconds()); + this.removeSeconds(this.getSeconds()); break; case MILLIS.MINUTE: - instance.removeMinutes(instance.getMinutes()); + this.removeMinutes(this.getMinutes()); break; case MILLIS.HOUR: - instance.removeHours(instance.getHours()); + this.removeHours(this.getHours()); break; } - return instance.milliseconds + (time * millis); + return this.milliseconds + (time * millis); }; /** @@ -374,271 +681,305 @@ * @default 0 * @protected */ - Kairos.Gnomon.prototype.milliseconds = 0; + Kairos.Engine.prototype.milliseconds = 0; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Sets hours fraction in the current instance. + * + * @param {Number} hours Hours to set + * @example new Kairos.Engine('01:00').setHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setHours = function (hours) { - this.milliseconds = _parse(this, MILLIS.HOUR, hours); + Kairos.Engine.prototype.setHours = function (hours) { + this.milliseconds = this._resolveStep(MILLIS.HOUR, hours); return this; }; /** - * - * @returns {*|Number} + * Gets hours fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getHours(); + * @returns {Number} Hours fraction from the instance */ - Kairos.Gnomon.prototype.getHours = function () { + Kairos.Engine.prototype.getHours = function () { return Math.trunc(this.milliseconds / MILLIS.HOUR); }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Sets minutes fraction in the current instance. + * + * @param {Number} minutes Minutes to set + * @example new Kairos.Engine('01:00').setMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMinutes = function (minutes) { - this.milliseconds = _parse(this, MILLIS.MINUTE, minutes); + Kairos.Engine.prototype.setMinutes = function (minutes) { + this.milliseconds = this._resolveStep(MILLIS.MINUTE, minutes); return this; }; /** - * - * @returns {*|Number} + * Gets minutes fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMinutes(); + * @returns {Number} Minutes fraction from the instance */ - Kairos.Gnomon.prototype.getMinutes = function () { + Kairos.Engine.prototype.getMinutes = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toHours()) * MILLIS.HOUR)) / MILLIS.MINUTE); }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Sets seconds fraction in the current instance. + * + * @param {Number} seconds Seconds to set + * @example new Kairos.Engine('01:00').setSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setSeconds = function (seconds) { - this.milliseconds = _parse(this, MILLIS.SECOND, seconds); + Kairos.Engine.prototype.setSeconds = function (seconds) { + this.milliseconds = this._resolveStep(MILLIS.SECOND, seconds); return this; }; /** - * - * @returns {*|Number} + * Gets seconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getSeconds(); + * @returns {Number} Seconds fraction from the instance */ - Kairos.Gnomon.prototype.getSeconds = function () { + Kairos.Engine.prototype.getSeconds = function () { return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toMinutes()) * MILLIS.MINUTE)) / MILLIS.SECOND); }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Sets milliseconds fraction in the current instance. + * + * @param {Number} milliseconds Milliseconds to set + * @example new Kairos.Engine('01:00').setMilliseconds(200); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.setMilliseconds = function (milliseconds) { - this.milliseconds = _parse(this, 1, milliseconds); + Kairos.Engine.prototype.setMilliseconds = function (milliseconds) { + this.milliseconds = this._resolveStep(1, milliseconds); return this; }; /** - * - * @returns {Number|*} + * Gets milliseconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMilliseconds(); + * @returns {Number} Milliseconds fraction from the instance */ - Kairos.Gnomon.prototype.getMilliseconds = function () { + Kairos.Engine.prototype.getMilliseconds = function () { return Math.trunc(this.milliseconds - (Math.trunc(this.toSeconds()) * MILLIS.SECOND)); }; /** + * Adds hours to the current instance. * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * @param {Number} hours Hours to add + * @example new Kairos.Engine('01:00').addHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addHours = function (hours) { + Kairos.Engine.prototype.addHours = function (hours) { this.milliseconds += (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Adds minutes to the current instance. + * + * @param {Number} minutes Minutes to add + * @example new Kairos.Engine('01:00').addMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMinutes = function (minutes) { + Kairos.Engine.prototype.addMinutes = function (minutes) { this.milliseconds += (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Adds seconds in the current instance. + * + * @param {Number} seconds Seconds to add + * @example new Kairos.Engine('01:00').addSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addSeconds = function (seconds) { + Kairos.Engine.prototype.addSeconds = function (seconds) { this.milliseconds += (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Adds milliseconds in the current instance. + * + * @param {Number} milliseconds Milliseconds to add + * @example new Kairos.Engine('01:00').addMilliseconds(500); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.addMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.addMilliseconds = function (milliseconds) { this.milliseconds += milliseconds; return this; }; /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self + * Removes hours from the current instance. + * + * @param {Number} hours Hours to remove + * @example new Kairos.Engine('01:00').removeHours(1); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeHours = function (hours) { + Kairos.Engine.prototype.removeHours = function (hours) { this.milliseconds -= (MILLIS.HOUR * hours); return this; }; /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self + * Removes minutes from the current instance. + * + * @param {Number} minutes Minutes to remove + * @example new Kairos.Engine('01:00').removeMinutes(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMinutes = function (minutes) { + Kairos.Engine.prototype.removeMinutes = function (minutes) { this.milliseconds -= (MILLIS.MINUTE * minutes); return this; }; /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self + * Removes seconds from the current instance. + * + * @param {Number} seconds Seconds to remove + * @example new Kairos.Engine('01:00').removeSeconds(30); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeSeconds = function (seconds) { + Kairos.Engine.prototype.removeSeconds = function (seconds) { this.milliseconds -= (MILLIS.SECOND * seconds); return this; }; /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self + * Removes milliseconds from the current instance. + * + * @example new Kairos.Engine('01:00').removeMilliseconds(50); + * @param {Number} milliseconds Milliseconds to remove + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.removeMilliseconds = function (milliseconds) { + Kairos.Engine.prototype.removeMilliseconds = function (milliseconds) { this.milliseconds -= milliseconds; return this; }; /** - * - * @returns {Number} hours within the time expression + * Returns total hours within the current instance. + * + * @example new Kairos.Engine('01:00').toHours(); + * @returns {Number} Hours within the current instance */ - Kairos.Gnomon.prototype.toHours = function () { + Kairos.Engine.prototype.toHours = function () { return (this.milliseconds / MILLIS.HOUR); }; /** - * - * @returns {Number} minutes within the time expression + * Returns total minutes within the current instance. + * + * @example new Kairos.Engine('01:00').toMinutes(); + * @returns {Number} Minutes within the current instance */ - Kairos.Gnomon.prototype.toMinutes = function () { + Kairos.Engine.prototype.toMinutes = function () { return (this.milliseconds / MILLIS.MINUTE); }; /** - * - * @returns {Number} seconds within the time expression + * Returns total seconds within the current instance. + * + * @example new Kairos.Engine('01:00').toSeconds(); + * @returns {Number} Seconds within the current instance */ - Kairos.Gnomon.prototype.toSeconds = function () { + Kairos.Engine.prototype.toSeconds = function () { return (this.milliseconds / MILLIS.SECOND); }; /** - * - * @returns {Number} milliseconds within the time expression + * Returns total milliseconds within the current instance. + * + * @example new Kairos.Engine('01:00').toMilliseconds(); + * @returns {Number} Milliseconds within the current instance */ - Kairos.Gnomon.prototype.toMilliseconds = function () { + Kairos.Engine.prototype.toMilliseconds = function () { return this.milliseconds; }; /** - * - * @returns {String} - */ - Kairos.Gnomon.prototype.toExpression = function () { - var expression = ''; - // Hours - var hours = Math.trunc(Math.abs(this.getHours())); - expression += ((String(hours).length > 1) ? '' : '0') + hours + ':'; - // Minutes - expression += ('00' + Math.trunc(Math.abs(this.getMinutes()))).slice(-2); - // Seconds - if (this.getSeconds() !== 0 || this.getMilliseconds() !== 0) { - expression += ':' + ('00' + Math.trunc(Math.abs(this.getSeconds()))).slice(-2); - } - // Millis - if (this.getMilliseconds() !== 0) { - expression += ':' + ('000' + Math.trunc(Math.abs(this.getMilliseconds()))).slice(-3); - } - - if (this.milliseconds < 0) { - expression = '-' + expression; - } - return expression; + * Makes the current instance's value absolute. + * + * @example new Kairos.Engine('01:00').toAbsolute(); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.toAbsolute = function () { + this.milliseconds = Math.abs(this.milliseconds); + return this; }; /** - * - * @param {Number|String|Kairos.Gnomon} addend - * @returns {Kairos.Gnomon} self + * Sums the given addend. + * + * @param {Number|String|Kairos.Engine} addend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.plus = function (addend) { - addend = (addend instanceof Kairos.Gnomon) ? addend : new Kairos.Gnomon(addend); + Kairos.Engine.prototype.plus = function (addend, pattern) { + addend = new Kairos.Engine(addend, pattern); this.milliseconds += addend.toMilliseconds(); return this; }; /** + * Subtracts the given subtrahend. * - * @param {Number|String|Kairos.Gnomon} subtrahend - * @returns {Kairos.Gnomon} self + * @param {Number|String|Kairos.Engine} subtrahend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.minus = function (subtrahend) { - subtrahend = (subtrahend instanceof Kairos.Gnomon) ? subtrahend : new Kairos.Gnomon(subtrahend); + Kairos.Engine.prototype.minus = function (subtrahend, pattern) { + subtrahend = new Kairos.Engine(subtrahend, pattern); this.milliseconds -= subtrahend.toMilliseconds(); return this; }; /** - * - * @param {Number} multiplicand - * @returns {Kairos.Gnomon} self + * Multiply by the given multiplicand. + * + * @param {Number} multiplicand Multiplicand value + * @example new Kairos.Engine('01:00').multiply(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.multiply = function (multiplicand) { + Kairos.Engine.prototype.multiply = function (multiplicand) { this.milliseconds *= multiplicand; return this; }; /** - * - * @param {Number} dividend - * @returns {Kairos.Gnomon} self + * Divies by the given dividend. + * + * @param {Number} divisor Divisor value + * @example new Kairos.Engine('01:00').divide(2); + * @returns {Kairos.Engine} Self */ - Kairos.Gnomon.prototype.divide = function (dividend) { - this.milliseconds /= dividend; + Kairos.Engine.prototype.divide = function (divisor) { + this.milliseconds /= divisor; return this; }; /** * Compares with another instance. - * Smaller -1 - * Equals 0 - * Bigger 1 * - * @param {String|Number|Kairos.Gnomon} another Expression to compare with - * @returns {Number} + * @param {String|Number|Kairos.Engine} another Expression to compare with + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').compareTo('00:30'); + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.Gnomon.prototype.compareTo = function (another) { - another = (another instanceof Kairos.Gnomon) ? another : new Kairos.Gnomon(another); + Kairos.Engine.prototype.compareTo = function (another, pattern) { + another = new Kairos.Engine(another, pattern); if (this.milliseconds < another.toMilliseconds()) { return -1; @@ -650,4 +991,20 @@ return 1; } }; + + /** + * Returns a string representation of the object. + * + * @param {String} pattern Pattern to format the time expression + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example new Kairos.Engine('22:10').toString('hh:mm'); + * @returns {String} String representing the instance time + */ + Kairos.Engine.prototype.toString = function (pattern, allowOverflow) { + if (typeof pattern === 'boolean') { + allowOverflow = pattern; + pattern = null; + } + return Kairos.Lexicon.format(this, pattern, allowOverflow); + }; }()); \ No newline at end of file diff --git a/examples/basic/index.html b/examples/basic/index.html index fd713a1..c46e03c 100644 --- a/examples/basic/index.html +++ b/examples/basic/index.html @@ -7,23 +7,23 @@ - + + - + =

- + - - + =

- + * = @@ -31,11 +31,11 @@

- + / = - + diff --git a/examples/basic/index.js b/examples/basic/index.js index e63845b..6302e18 100644 --- a/examples/basic/index.js +++ b/examples/basic/index.js @@ -14,6 +14,8 @@ var dividend = document.getElementById('dividend'); var divisor = document.getElementById('divisor'); var divideResult = document.getElementById('divideResult'); +Kairos.setPattern('hh:mm'); + function plus() { plusResult.value = Kairos.plus(augend.value, addend.value); } diff --git a/examples/calc/calc.js b/examples/calc/calc.js index bc01e59..b41858b 100644 --- a/examples/calc/calc.js +++ b/examples/calc/calc.js @@ -4,7 +4,7 @@ _operator, _doNotParse = false, _error; - + var _sendNum = function () { var val = this.textContent; if (!_operator) { @@ -88,8 +88,8 @@ var _equals = function () { try { - var val1 = new Kairos.Gnomon(String(_val1)); - var val2 = _doNotParse ? parseInt(_val2) : new Kairos.Gnomon(_val2); + var val1 = new Kairos.Engine(String(_val1)); + var val2 = _doNotParse ? parseInt(_val2) : new Kairos.Engine(_val2); switch (_operator) { case '/': @@ -105,8 +105,12 @@ val1.plus(val2); break; } - - _val1 = val1.toExpression(); + + if (val1.toMilliseconds() >= 0) { + _val1 = val1.toString('hh:mm:ss.SSS', true); + } else { + _val1 = val1.toString(true); + } _val2 = ''; _operator = null; } catch (err) { @@ -123,6 +127,8 @@ }; var _init = function () { + Kairos.setAutoParser(true); + var nums = document.getElementsByClassName('num'); for (var i = 0, len = nums.length; i < len; i++) { var num = nums[i]; diff --git a/examples/usecase/index.html b/examples/usecase/index.html index 42ee376..f8f6eb8 100644 --- a/examples/usecase/index.html +++ b/examples/usecase/index.html @@ -7,24 +7,23 @@ - + Kairos Usecase - + - + -

Kairo Usecase

- -
- -
+ +
+ +
@@ -32,8 +31,12 @@

Kairo Usecase

- -
+ +
+ +
+ +
@@ -52,15 +55,15 @@

Kairo Usecase

- +
- + - +
- + diff --git a/examples/usecase/index.js b/examples/usecase/index.js index 2b97425..9d92b6f 100644 --- a/examples/usecase/index.js +++ b/examples/usecase/index.js @@ -1,46 +1,46 @@ (function (window) { 'use strict'; - + var _tasks = []; - + var exports = {}; - + var _taskNameInput, _taskStartBtn, _tasksTableBody, _totalTime; - + var _initSelectors = function () { _taskNameInput = document.querySelector('input#task-name'); _taskStartBtn = document.querySelector('div#taks-start'); _tasksTableBody = document.querySelector('table#tasks-table tbody'); _totalTime = document.getElementById('total-time'); }; - + var _initEventHandlers = function () { _taskStartBtn.addEventListener('click', _addTask); }; - + var _addTask = function () { var task = new Task(_taskNameInput.value); _tasks.push(task); - + var row = document.createElement('tr'), taskCol = document.createElement('td'), executedForCol = document.createElement('td'), actionCol = document.createElement('td'), taskContent = document.createTextNode(task.name), stopTaskBtn = document.createElement('button'); - + taskCol.appendChild(taskContent); row.appendChild(taskCol); - + var updateInterval = setInterval(function () { - executedForCol.innerHTML = task.getTimeElapsed().toExpression(); + executedForCol.innerHTML = task.getTimeElapsed().toString(); _updateTotal(); }, 1000); row.appendChild(executedForCol); - + stopTaskBtn.setAttribute('class', 'btn btn-danger'); stopTaskBtn.innerHTML = 'Stop'; stopTaskBtn.addEventListener('click', function () { @@ -49,27 +49,28 @@ }); actionCol.appendChild(stopTaskBtn); row.appendChild(actionCol); - + _tasksTableBody.appendChild(row); _taskNameInput.value = ''; }; - + var _updateTotal = function () { - var g = new Kairos.Gnomon(); + var g = new Kairos.Engine(); for (var i = 0, len = _tasks.length; i < len; i++) { g.plus(_tasks[i].getTimeElapsed()); } - - _totalTime.innerHTML = g.toExpression(); + + _totalTime.innerHTML = g.toString(); }; - + var _init = function () { _initSelectors(); _initEventHandlers(); + Kairos.setPattern('hh:mm:ss'); }; - + exports.init = _init; - + window.TaskManager = exports; })(window); diff --git a/examples/usecase/jumbotron-narrow.css b/examples/usecase/jumbotron-narrow.css deleted file mode 100644 index 952adc5..0000000 --- a/examples/usecase/jumbotron-narrow.css +++ /dev/null @@ -1,79 +0,0 @@ -/* Space out content a bit */ -body { - padding-top: 20px; - padding-bottom: 20px; -} - -/* Everything but the jumbotron gets side spacing for mobile first views */ -.header, -.marketing, -.footer { - padding-right: 15px; - padding-left: 15px; -} - -/* Custom page header */ -.header { - padding-bottom: 20px; - border-bottom: 1px solid #e5e5e5; -} -/* Make the masthead heading the same height as the navigation */ -.header h3 { - margin-top: 0; - margin-bottom: 0; - line-height: 40px; -} - -/* Custom page footer */ -.footer { - padding-top: 19px; - color: #777; - border-top: 1px solid #e5e5e5; -} - -/* Customize container */ -@media (min-width: 768px) { - .container { - max-width: 730px; - } -} -.container-narrow > hr { - margin: 30px 0; -} - -/* Main marketing message and sign up button */ -.jumbotron { - text-align: center; - border-bottom: 1px solid #e5e5e5; -} -.jumbotron .btn { - padding: 14px 24px; - font-size: 21px; -} - -/* Supporting marketing content */ -.marketing { - margin: 40px 0; -} -.marketing p + h4 { - margin-top: 28px; -} - -/* Responsive: Portrait tablets and up */ -@media screen and (min-width: 768px) { - /* Remove the padding we set earlier */ - .header, - .marketing, - .footer { - padding-right: 0; - padding-left: 0; - } - /* Space out the masthead */ - .header { - margin-bottom: 30px; - } - /* Remove the bottom border on the jumbotron for visual effect */ - .jumbotron { - border-bottom: 0; - } -} diff --git a/examples/usecase/task.js b/examples/usecase/task.js index 97e9609..968878c 100644 --- a/examples/usecase/task.js +++ b/examples/usecase/task.js @@ -16,14 +16,14 @@ * @protected */ Task.prototype.name = ''; - + /** * @type {Date} * @default new Date * @protected */ Task.prototype.startedAt = null; - + /** * @type {Date} * @default null @@ -37,16 +37,16 @@ Task.prototype.finish = function () { this.finishedAt = new Date(); }; - + /** * @returns {Kairos.Gnomon} */ Task.prototype.getTimeElapsed = function () { var diff = ((this.finishedAt || new Date()).getTime() - this.startedAt.getTime()); - var gnomon = new Kairos.Gnomon(diff); - gnomon.removeMilliseconds(gnomon.getMilliseconds()); - return gnomon; + var engine = Kairos.new(diff); + engine.removeMilliseconds(engine.getMilliseconds()); + return engine; }; - + window.Task = Task; }()); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 0804825..b4d831a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -10,7 +10,8 @@ const stylish = require('jshint-stylish'); const mainFiles = [ 'src/kairos.js', - 'src/engine/Gnomon.js' + 'src/Lexicon.js', + 'src/Engine.js' ]; gulp.task('init', () => { diff --git a/karma.conf.js b/karma.conf.js index c55ad0e..1750301 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,11 +6,13 @@ module.exports = function (config) { files: [ 'bower_components/mocha/mocha.css', 'src/kairos.js', - 'src/engine/Gnomon.js', + 'src/Lexicon.js', + 'src/Engine.js', 'bower_components/assert/assert.js', 'bower_components/mocha/mocha.js', 'test/browser/kairos.js', - 'test/browser/gnomon.js', + 'test/browser/lexicon.js', + 'test/browser/engine.js', { pattern: 'test/browser/fixture/*', included: false, diff --git a/package.json b/package.json index 327aada..932ae32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kairos", - "version": "1.1.0", + "version": "2.0.0", "description": "A non date-based time calculator", "license": "BSD-2-Clause", "repository": "kairos", @@ -11,7 +11,8 @@ }, "main": "./build/kairos-node.js", "scripts": { - "test": "node test/node/test.js" + "test": "node test/node/test.js", + "coverage": "istanbul cover gulp test -- -R spec" }, "keywords": [ "time", @@ -23,34 +24,35 @@ ], "devDependencies": { "assert": "^1.3.0", - "codeclimate-test-reporter": "^0.3.0", + "codeclimate-test-reporter": "^0.3.1", "del": "^2.2.0", - "gulp": "^3.9.0", + "gulp": "^3.9.1", "gulp-autoprefixer": "^3.1.0", - "gulp-bower": "0.0.11", + "gulp-bower": "0.0.13", "gulp-concat": "^2.6.0", - "gulp-esformatter": "^5.0.0", + "gulp-esformatter": "^6.0.0", "gulp-header": "^1.7.1", "gulp-include": "^2.1.0", "gulp-jsdoc": "^0.1.5", "gulp-jshint": "^2.0.0", - "gulp-load-plugins": "^1.1.0", + "gulp-load-plugins": "^1.2.0", "gulp-strip-debug": "^1.1.0", - "gulp-uglify": "^1.5.1", + "gulp-uglify": "^1.5.3", "gulp-webserver": "^0.9.1", + "istanbul": "^0.4.2", "jasmine-core": "^2.4.1", - "jshint": "^2.9.1-rc2", + "jshint": "^2.9.1", "jshint-stylish": "^2.1.0", - "karma": "^0.13.15", + "karma": "^0.13.22", "karma-chrome-launcher": "^0.2.2", - "karma-coverage": "^0.5.3", + "karma-coverage": "^0.5.5", "karma-firefox-launcher": "^0.1.7", - "karma-jasmine": "^0.3.6", - "karma-mocha": "^0.2.1", - "karma-phantomjs-launcher": "^0.2.1", - "mocha": "^2.3.4", - "phantom": "^0.8.4", - "phantomjs": "^1.9.19", + "karma-jasmine": "^0.3.8", + "karma-mocha": "^0.2.2", + "karma-phantomjs-launcher": "^1.0.0", + "mocha": "^2.4.5", + "phantom": "^2.0.6", + "phantomjs-prebuilt": "^2.1.5", "run-sequence": "^1.1.5" } } diff --git a/src/Engine.js b/src/Engine.js new file mode 100644 index 0000000..222877d --- /dev/null +++ b/src/Engine.js @@ -0,0 +1,402 @@ +(function () { + + 'use strict'; + + /** + * @type {{SECOND: number, MINUTE: number, HOUR: number}} + */ + var MILLIS = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000 + }; + + /** + * Kairos time engine. + * + * @param {String|Number|Kairos.Engine} expression Literal time expression, milliseconds or a Kairos.Engine instance + * @pattern {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('10:30', 'hh:mm'); + * @constructor + */ + Kairos.Engine = function (expression, pattern) { + if (!expression) { + return; + } + + if (expression instanceof Kairos.Engine) { + return expression; + } + + if (typeof expression === 'number') { + this.milliseconds = expression; + return this; + } + + if (typeof expression === 'string' && expression.length > 0) { + if (Kairos.getAutoParser()) { + pattern = Kairos.Lexicon.findPattern(expression); + } + return new Kairos.Lexicon.parse(expression, pattern); + } + + throw new Error('Invalid arguments'); + }; + + /** + * @param {Kairos.Engine} instance + * @param {Number} millis + * @param {Number} time + * @returns {Number} + * @private + */ + Kairos.Engine.prototype._resolveStep = function (millis, time) { + switch (millis) { + case 1: + this.removeMilliseconds(this.getMilliseconds()); + break; + case MILLIS.SECOND: + this.removeSeconds(this.getSeconds()); + break; + case MILLIS.MINUTE: + this.removeMinutes(this.getMinutes()); + break; + case MILLIS.HOUR: + this.removeHours(this.getHours()); + break; + } + return this.milliseconds + (time * millis); + }; + + /** + * @type {Number} + * @default 0 + * @protected + */ + Kairos.Engine.prototype.milliseconds = 0; + + /** + * Sets hours fraction in the current instance. + * + * @param {Number} hours Hours to set + * @example new Kairos.Engine('01:00').setHours(1); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.setHours = function (hours) { + this.milliseconds = this._resolveStep(MILLIS.HOUR, hours); + return this; + }; + + /** + * Gets hours fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getHours(); + * @returns {Number} Hours fraction from the instance + */ + Kairos.Engine.prototype.getHours = function () { + return Math.trunc(this.milliseconds / MILLIS.HOUR); + }; + + /** + * Sets minutes fraction in the current instance. + * + * @param {Number} minutes Minutes to set + * @example new Kairos.Engine('01:00').setMinutes(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.setMinutes = function (minutes) { + this.milliseconds = this._resolveStep(MILLIS.MINUTE, minutes); + return this; + }; + + /** + * Gets minutes fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMinutes(); + * @returns {Number} Minutes fraction from the instance + */ + Kairos.Engine.prototype.getMinutes = function () { + return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toHours()) * MILLIS.HOUR)) / MILLIS.MINUTE); + }; + + /** + * Sets seconds fraction in the current instance. + * + * @param {Number} seconds Seconds to set + * @example new Kairos.Engine('01:00').setSeconds(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.setSeconds = function (seconds) { + this.milliseconds = this._resolveStep(MILLIS.SECOND, seconds); + return this; + }; + + /** + * Gets seconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getSeconds(); + * @returns {Number} Seconds fraction from the instance + */ + Kairos.Engine.prototype.getSeconds = function () { + return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toMinutes()) * MILLIS.MINUTE)) / MILLIS.SECOND); + }; + + /** + * Sets milliseconds fraction in the current instance. + * + * @param {Number} milliseconds Milliseconds to set + * @example new Kairos.Engine('01:00').setMilliseconds(200); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.setMilliseconds = function (milliseconds) { + this.milliseconds = this._resolveStep(1, milliseconds); + return this; + }; + + /** + * Gets milliseconds fraction in the current instance. + * + * @example new Kairos.Engine('01:00').getMilliseconds(); + * @returns {Number} Milliseconds fraction from the instance + */ + Kairos.Engine.prototype.getMilliseconds = function () { + return Math.trunc(this.milliseconds - (Math.trunc(this.toSeconds()) * MILLIS.SECOND)); + }; + + /** + * Adds hours to the current instance. + * + * @param {Number} hours Hours to add + * @example new Kairos.Engine('01:00').addHours(1); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.addHours = function (hours) { + this.milliseconds += (MILLIS.HOUR * hours); + return this; + }; + + /** + * Adds minutes to the current instance. + * + * @param {Number} minutes Minutes to add + * @example new Kairos.Engine('01:00').addMinutes(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.addMinutes = function (minutes) { + this.milliseconds += (MILLIS.MINUTE * minutes); + return this; + }; + + /** + * Adds seconds in the current instance. + * + * @param {Number} seconds Seconds to add + * @example new Kairos.Engine('01:00').addSeconds(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.addSeconds = function (seconds) { + this.milliseconds += (MILLIS.SECOND * seconds); + return this; + }; + + /** + * Adds milliseconds in the current instance. + * + * @param {Number} milliseconds Milliseconds to add + * @example new Kairos.Engine('01:00').addMilliseconds(500); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.addMilliseconds = function (milliseconds) { + this.milliseconds += milliseconds; + return this; + }; + + /** + * Removes hours from the current instance. + * + * @param {Number} hours Hours to remove + * @example new Kairos.Engine('01:00').removeHours(1); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.removeHours = function (hours) { + this.milliseconds -= (MILLIS.HOUR * hours); + return this; + }; + + /** + * Removes minutes from the current instance. + * + * @param {Number} minutes Minutes to remove + * @example new Kairos.Engine('01:00').removeMinutes(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.removeMinutes = function (minutes) { + this.milliseconds -= (MILLIS.MINUTE * minutes); + return this; + }; + + /** + * Removes seconds from the current instance. + * + * @param {Number} seconds Seconds to remove + * @example new Kairos.Engine('01:00').removeSeconds(30); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.removeSeconds = function (seconds) { + this.milliseconds -= (MILLIS.SECOND * seconds); + return this; + }; + + /** + * Removes milliseconds from the current instance. + * + * @example new Kairos.Engine('01:00').removeMilliseconds(50); + * @param {Number} milliseconds Milliseconds to remove + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.removeMilliseconds = function (milliseconds) { + this.milliseconds -= milliseconds; + return this; + }; + + /** + * Returns total hours within the current instance. + * + * @example new Kairos.Engine('01:00').toHours(); + * @returns {Number} Hours within the current instance + */ + Kairos.Engine.prototype.toHours = function () { + return (this.milliseconds / MILLIS.HOUR); + }; + + /** + * Returns total minutes within the current instance. + * + * @example new Kairos.Engine('01:00').toMinutes(); + * @returns {Number} Minutes within the current instance + */ + Kairos.Engine.prototype.toMinutes = function () { + return (this.milliseconds / MILLIS.MINUTE); + }; + + /** + * Returns total seconds within the current instance. + * + * @example new Kairos.Engine('01:00').toSeconds(); + * @returns {Number} Seconds within the current instance + */ + Kairos.Engine.prototype.toSeconds = function () { + return (this.milliseconds / MILLIS.SECOND); + }; + + /** + * Returns total milliseconds within the current instance. + * + * @example new Kairos.Engine('01:00').toMilliseconds(); + * @returns {Number} Milliseconds within the current instance + */ + Kairos.Engine.prototype.toMilliseconds = function () { + return this.milliseconds; + }; + + /** + * Makes the current instance's value absolute. + * + * @example new Kairos.Engine('01:00').toAbsolute(); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.toAbsolute = function () { + this.milliseconds = Math.abs(this.milliseconds); + return this; + }; + + /** + * Sums the given addend. + * + * @param {Number|String|Kairos.Engine} addend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.plus = function (addend, pattern) { + addend = new Kairos.Engine(addend, pattern); + this.milliseconds += addend.toMilliseconds(); + return this; + }; + + /** + * Subtracts the given subtrahend. + * + * @param {Number|String|Kairos.Engine} subtrahend + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').minus('00:30'); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.minus = function (subtrahend, pattern) { + subtrahend = new Kairos.Engine(subtrahend, pattern); + this.milliseconds -= subtrahend.toMilliseconds(); + return this; + }; + + /** + * Multiply by the given multiplicand. + * + * @param {Number} multiplicand Multiplicand value + * @example new Kairos.Engine('01:00').multiply(2); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.multiply = function (multiplicand) { + this.milliseconds *= multiplicand; + return this; + }; + + /** + * Divies by the given dividend. + * + * @param {Number} divisor Divisor value + * @example new Kairos.Engine('01:00').divide(2); + * @returns {Kairos.Engine} Self + */ + Kairos.Engine.prototype.divide = function (divisor) { + this.milliseconds /= divisor; + return this; + }; + + /** + * Compares with another instance. + * + * @param {String|Number|Kairos.Engine} another Expression to compare with + * @param {String} [pattern] Overrides Kairos pattern + * @example new Kairos.Engine('01:00').compareTo('00:30'); + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 + */ + Kairos.Engine.prototype.compareTo = function (another, pattern) { + another = new Kairos.Engine(another, pattern); + + if (this.milliseconds < another.toMilliseconds()) { + return -1; + } + if (this.milliseconds === another.toMilliseconds()) { + return 0; + } + if (this.milliseconds > another.toMilliseconds()) { + return 1; + } + }; + + /** + * Returns a string representation of the object. + * + * @param {String} pattern Pattern to format the time expression + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example new Kairos.Engine('22:10').toString('hh:mm'); + * @returns {String} String representing the instance time + */ + Kairos.Engine.prototype.toString = function (pattern, allowOverflow) { + if (typeof pattern === 'boolean') { + allowOverflow = pattern; + pattern = null; + } + return Kairos.Lexicon.format(this, pattern, allowOverflow); + }; +}()); \ No newline at end of file diff --git a/src/Lexicon.js b/src/Lexicon.js new file mode 100644 index 0000000..744552a --- /dev/null +++ b/src/Lexicon.js @@ -0,0 +1,247 @@ +/** + * @module Lexicon + */ +(function () { + + 'use strict'; + + /** + * @type {{HOURS: string, MINUTES: string, SECONDS: string, MILLISECONDS: string}} + */ + var TOKENS = { + SIGN: '#', HOURS: 'h', MINUTES: 'm', + SECONDS: 's', MILLISECONDS: 'S' + }; + + Kairos.Lexicon = {}; + + /** + * Gets a regex from a pattern. + * + * @memberof module:Lexicon + * @method getValidator + * @param {String} [pattern] Pattern to convert + * @example Kairos.Lexicon.getValidator('#hh:mm:ss.SSS'); + * @returns {RegExp} + */ + Kairos.Lexicon.getValidator = function (pattern) { + if (typeof pattern !== 'string') { + pattern = Kairos._pattern; + } + if (pattern === Kairos._pattern) { + return Kairos._validator; + } + + var regex = ''; + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + regex += '^[+-]?'; + break; + case TOKENS.HOURS: + case TOKENS.MINUTES: + case TOKENS.SECONDS: + case TOKENS.MILLISECONDS: + regex += '\\d'; + break; + default: + regex += cur.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); + } + } + + return new RegExp(regex); + }; + + /** + * Validates if given expression matches the current pattern. + * + * @memberof module:Lexicon + * @method validate + * @param {String} expression Time expression to be validated + * @param {String} [pattern] Pattern to validate + * @example Kairos.Lexicon.validate('10:00:00.000', 'hh:mm:ss.SSS'); + * @returns {Boolean} True if expression is valid, false if expression is invalid + */ + Kairos.Lexicon.validate = function (expression, pattern) { + return Kairos.Lexicon.getValidator(pattern).test(expression); + }; + + /** + * Parses given time expression to a Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method parse + * @param {String} expression Time expression to be parsed + * @param {String} [pattern] Pattern to parse + * @example Kairos.Lexicon.parse('01:00:03', 'hh:mm:ss'); + * @returns {Kairos.Engine} Given expression parsed to Kairos.Engine + */ + Kairos.Lexicon.parse = function (expression, pattern) { + if (!pattern) { + pattern = Kairos._pattern; + } + if (!Kairos.Lexicon.validate(expression, pattern)) { + throw new Error('Cannot parse expression. Time format doesn\'t match the current time pattern.'); + } + + var sign = true, hours = '', minutes = '', seconds = '', milliseconds = ''; + + for (var i = 0, len = pattern.length; len > i; i++) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + var validSign = (['+', '-'].indexOf(expression[i]) !== -1); + if (!validSign) { + pattern = pattern.slice(0, i) + pattern.slice(i + 1); + len--; + i--; + } else { + sign = expression[i] === '+'; + } + break; + case TOKENS.HOURS: + hours += expression[i]; + break; + case TOKENS.MINUTES: + minutes += expression[i]; + break; + case TOKENS.SECONDS: + seconds += expression[i]; + break; + case TOKENS.MILLISECONDS: + milliseconds += expression[i]; + break; + } + } + + var result = Kairos.new() + .addHours(hours ? +hours : 0) + .addMinutes(minutes ? +minutes : 0) + .addSeconds(seconds ? +seconds : 0) + .addMilliseconds(milliseconds ? +milliseconds : 0); + + if (!sign) { + result.milliseconds =- result.milliseconds; + } + + return result; + }; + + /** + * Returns a formated string from an Kairos.Engine instance. + * + * @memberof module:Lexicon + * @method format + * @param {Kairos.Engine} instance The instance to format + * @param {String} [pattern] Pattern to format + * @param {Boolean} allowOverflow If true, when hour field is bigger than the pattern definition, it will be printed anyway + * @example Kairos.Lexicon.format(Kairos.new('10:30'), 'mm:hh'); + * @returns {String} Formated time expression + */ + Kairos.Lexicon.format = function (instance, pattern, allowOverflow) { + if (!pattern) { + pattern = Kairos._pattern; + } + + var sign = instance.milliseconds >= 0, + hours = String(Math.abs(instance.getHours())), + minutes = String(Math.abs(instance.getMinutes())), + seconds = String(Math.abs(instance.getSeconds())), + milliseconds = String(Math.abs(instance.getMilliseconds())); + + var result = '', + hasOverflow = (hours.length > (pattern.match(/h/g) || []).length); + + for (var i = pattern.length - 1; i >= 0; i--) { + var cur = pattern[i]; + switch (cur) { + case TOKENS.SIGN: + result = (sign ? '+' : '-') + result; + break; + case TOKENS.HOURS: + if (hasOverflow) { + if (allowOverflow) { + result = hours + result; + allowOverflow = false; + } + break; + } + result = (hours.slice(-1) || '0') + result; + if (hours.length > 0) { + hours = hours.slice(0, hours.length - 1); + } + break; + case TOKENS.MINUTES: + result = (minutes.slice(-1) || '0') + result; + if (minutes.length > 0) { + minutes = minutes.slice(0, minutes.length - 1); + } + break; + case TOKENS.SECONDS: + result = (seconds.slice(-1) || '0') + result; + if (seconds.length > 0) { + seconds = seconds.slice(0, seconds.length - 1); + } + break; + case TOKENS.MILLISECONDS: + result = (milliseconds.slice(-1) || '0') + result; + if (milliseconds.length > 0) { + milliseconds = milliseconds.slice(0, milliseconds.length - 1); + } + break; + default: + result = cur + result; + } + } + + return result; + }; + + /** + * Tries to extract a pattern from the given expression. + * + * @memberof module:Lexicon + * @method findPattern + * @param {String} expression Expression to be analysed + * @example Kairos.Lexicon.findPattern('01:05:30'); + * @returns {String} Extracted pattern + */ + Kairos.Lexicon.findPattern = function (expression) { + var pattern = '', + currentStep = TOKENS.HOURS; + for (var i = 0, len = expression.length; len > i; i++) { + var cur = expression[i]; + + if (['+', '-'].indexOf(cur) !== -1) { + pattern += TOKENS.SIGN; + continue; + } + + if (!isNaN(cur)) { + pattern += currentStep || cur; + continue; + } + + if (isNaN(cur)) { + pattern += cur; + switch (currentStep) { + case TOKENS.HOURS: + currentStep = TOKENS.MINUTES; + break; + case TOKENS.MINUTES: + currentStep = TOKENS.SECONDS; + break; + case TOKENS.SECONDS: + currentStep = TOKENS.MILLISECONDS; + break; + default: + currentStep = false; + } + continue; + } + } + + return pattern; + }; +}()); \ No newline at end of file diff --git a/src/engine/Gnomon.js b/src/engine/Gnomon.js deleted file mode 100644 index 0d1fab8..0000000 --- a/src/engine/Gnomon.js +++ /dev/null @@ -1,365 +0,0 @@ -(function () { - 'use strict'; - - /** - * - * @type {{SECOND: number, MINUTE: number, HOUR: number}} - */ - var MILLIS = { - SECOND: 1000, - MINUTE: 60 * 1000, - HOUR: 60 * 60 * 1000 - }; - - /** - * Gnomon is the time engine for Kairos. It's name references the first solar clock ever made. - * - * @param {String|Number} expression Time expression - * @constructor - */ - Kairos.Gnomon = function (expression) { - if (typeof expression === 'number') { - - this.milliseconds = expression; - - } else if (typeof expression === 'string' && expression.length > 0) { - - if (!Kairos.validateExpression(expression)) { - throw new Error('Invalid time expression'); - } - - var timeSteps = expression.split(':'); - var positive = expression.slice(0, 1)[0] !== '-'; - - for (var i = 0, len = timeSteps.length; i < len; i++) { - var timeStep = timeSteps[i]; - - timeStep = Math.abs(timeStep); - switch (i) { - case 0: - this.milliseconds = _parse(this, MILLIS.HOUR, timeStep); - break; - case 1: - this.milliseconds = _parse(this, MILLIS.MINUTE, timeStep); - break; - case 2: - this.milliseconds = _parse(this, MILLIS.SECOND, timeStep); - break; - case 3: - this.milliseconds = _parse(this, 1, timeStep); - break; - } - } - if (!positive) { - this.milliseconds = -Math.abs(this.milliseconds); - } - } - }; - - /** - * @param {Kairos.Gnomon} instance - * @param {Number} millis - * @param {Number} time - * @returns {Number} - * @private - */ - var _parse = function (instance, millis, time) { - switch (millis) { - case 1: - instance.removeMilliseconds(instance.getMilliseconds()); - break; - case MILLIS.SECOND: - instance.removeSeconds(instance.getSeconds()); - break; - case MILLIS.MINUTE: - instance.removeMinutes(instance.getMinutes()); - break; - case MILLIS.HOUR: - instance.removeHours(instance.getHours()); - break; - } - return instance.milliseconds + (time * millis); - }; - - /** - * @type {Number} - * @default 0 - * @protected - */ - Kairos.Gnomon.prototype.milliseconds = 0; - - /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.setHours = function (hours) { - this.milliseconds = _parse(this, MILLIS.HOUR, hours); - return this; - }; - - /** - * - * @returns {*|Number} - */ - Kairos.Gnomon.prototype.getHours = function () { - return Math.trunc(this.milliseconds / MILLIS.HOUR); - }; - - /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.setMinutes = function (minutes) { - this.milliseconds = _parse(this, MILLIS.MINUTE, minutes); - return this; - }; - - /** - * - * @returns {*|Number} - */ - Kairos.Gnomon.prototype.getMinutes = function () { - return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toHours()) * MILLIS.HOUR)) / MILLIS.MINUTE); - }; - - /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.setSeconds = function (seconds) { - this.milliseconds = _parse(this, MILLIS.SECOND, seconds); - return this; - }; - - /** - * - * @returns {*|Number} - */ - Kairos.Gnomon.prototype.getSeconds = function () { - return Math.trunc(Math.trunc(this.milliseconds - (Math.trunc(this.toMinutes()) * MILLIS.MINUTE)) / MILLIS.SECOND); - }; - - /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.setMilliseconds = function (milliseconds) { - this.milliseconds = _parse(this, 1, milliseconds); - return this; - }; - - /** - * - * @returns {Number|*} - */ - Kairos.Gnomon.prototype.getMilliseconds = function () { - return Math.trunc(this.milliseconds - (Math.trunc(this.toSeconds()) * MILLIS.SECOND)); - }; - - /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.addHours = function (hours) { - this.milliseconds += (MILLIS.HOUR * hours); - return this; - }; - - /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.addMinutes = function (minutes) { - this.milliseconds += (MILLIS.MINUTE * minutes); - return this; - }; - - /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.addSeconds = function (seconds) { - this.milliseconds += (MILLIS.SECOND * seconds); - return this; - }; - - /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.addMilliseconds = function (milliseconds) { - this.milliseconds += milliseconds; - return this; - }; - - /** - * - * @param {Number} hours - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.removeHours = function (hours) { - this.milliseconds -= (MILLIS.HOUR * hours); - return this; - }; - - /** - * - * @param {Number} minutes - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.removeMinutes = function (minutes) { - this.milliseconds -= (MILLIS.MINUTE * minutes); - return this; - }; - - /** - * - * @param {Number} seconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.removeSeconds = function (seconds) { - this.milliseconds -= (MILLIS.SECOND * seconds); - return this; - }; - - /** - * - * @param {Number} milliseconds - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.removeMilliseconds = function (milliseconds) { - this.milliseconds -= milliseconds; - return this; - }; - - /** - * - * @returns {Number} hours within the time expression - */ - Kairos.Gnomon.prototype.toHours = function () { - return (this.milliseconds / MILLIS.HOUR); - }; - - /** - * - * @returns {Number} minutes within the time expression - */ - Kairos.Gnomon.prototype.toMinutes = function () { - return (this.milliseconds / MILLIS.MINUTE); - }; - - /** - * - * @returns {Number} seconds within the time expression - */ - Kairos.Gnomon.prototype.toSeconds = function () { - return (this.milliseconds / MILLIS.SECOND); - }; - - /** - * - * @returns {Number} milliseconds within the time expression - */ - Kairos.Gnomon.prototype.toMilliseconds = function () { - return this.milliseconds; - }; - - /** - * - * @returns {String} - */ - Kairos.Gnomon.prototype.toExpression = function () { - var expression = ''; - // Hours - var hours = Math.trunc(Math.abs(this.getHours())); - expression += ((String(hours).length > 1) ? '' : '0') + hours + ':'; - // Minutes - expression += ('00' + Math.trunc(Math.abs(this.getMinutes()))).slice(-2); - // Seconds - if (this.getSeconds() !== 0 || this.getMilliseconds() !== 0) { - expression += ':' + ('00' + Math.trunc(Math.abs(this.getSeconds()))).slice(-2); - } - // Millis - if (this.getMilliseconds() !== 0) { - expression += ':' + ('000' + Math.trunc(Math.abs(this.getMilliseconds()))).slice(-3); - } - - if (this.milliseconds < 0) { - expression = '-' + expression; - } - return expression; - }; - - /** - * - * @param {Number|String|Kairos.Gnomon} addend - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.plus = function (addend) { - addend = (addend instanceof Kairos.Gnomon) ? addend : new Kairos.Gnomon(addend); - this.milliseconds += addend.toMilliseconds(); - return this; - }; - - /** - * - * @param {Number|String|Kairos.Gnomon} subtrahend - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.minus = function (subtrahend) { - subtrahend = (subtrahend instanceof Kairos.Gnomon) ? subtrahend : new Kairos.Gnomon(subtrahend); - this.milliseconds -= subtrahend.toMilliseconds(); - return this; - }; - - /** - * - * @param {Number} multiplicand - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.multiply = function (multiplicand) { - this.milliseconds *= multiplicand; - return this; - }; - - /** - * - * @param {Number} dividend - * @returns {Kairos.Gnomon} self - */ - Kairos.Gnomon.prototype.divide = function (dividend) { - this.milliseconds /= dividend; - return this; - }; - - /** - * Compares with another instance. - * Smaller -1 - * Equals 0 - * Bigger 1 - * - * @param {String|Number|Kairos.Gnomon} another Expression to compare with - * @returns {Number} - */ - Kairos.Gnomon.prototype.compareTo = function (another) { - another = (another instanceof Kairos.Gnomon) ? another : new Kairos.Gnomon(another); - - if (this.milliseconds < another.toMilliseconds()) { - return -1; - } - if (this.milliseconds === another.toMilliseconds()) { - return 0; - } - if (this.milliseconds > another.toMilliseconds()) { - return 1; - } - }; -}()); \ No newline at end of file diff --git a/src/kairos.js b/src/kairos.js index 15598ae..806bf59 100644 --- a/src/kairos.js +++ b/src/kairos.js @@ -2,10 +2,16 @@ * @module Kairos */ (function () { + 'use strict'; var Kairos = {}; + // Set defaults + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + Kairos._autoParser = false; + // global on the server, window in the browser var previous_Kairos; @@ -21,11 +27,11 @@ } /** - * Avoid conflict in case of another instance of Kairos is already in the scope + * Avoid conflict in case of another instance of Kairos is already in the scope. * * @memberof module:Kairos * @method noConflict - * @returns {Object} + * @returns {Object} Previous Kairos object */ Kairos.noConflict = function () { root.Kairos = previous_Kairos; @@ -33,234 +39,301 @@ }; /** - * Validates if the given expression is valid. + * Sets Kairos time expression pattern. + * Pattern structure is the following: + * # -> sign + * h -> hours + * m -> minutes + * s -> seconds + * S -> milliseconds * * @memberof module:Kairos - * @method validateExpression - * @param {String|Number} expression Time expression - * @returns {Boolean} + * @method setPattern + * @param {String} pattern The pattern to parse and format time expressions + * @example Kairos.setPattern('#hh:mm:ss.SSS'); */ - Kairos.validateExpression = function (expression) { - var regex = /^[+-]?\d+(?::?\d{1,2}(?::\d{1,2}(?::\d{1,3})?)?)?$/; - return regex.test(expression); + Kairos.setPattern = function (pattern) { + Kairos._validator = Kairos.Lexicon.getValidator(pattern); + Kairos._pattern = pattern; }; /** - * Return a Kairos.Gnomon instance. - * + * Gets current Kairos pattern. + * + * @memberof module:Kairos + * @method getPattern + * @returns {String} Current Kairos pattern + */ + Kairos.getPattern = function () { + return Kairos._pattern; + }; + + /** + * Sets Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method setAutoParser + * @param {Boolean} yN True to use or false to not use auto parser + * @example Kairos.setAutoParser(true); + */ + Kairos.setAutoParser = function (yN) { + Kairos._autoParser = !!yN; + }; + + /** + * Gets current Kairos configuration for auto parse feature. + * + * @memberof module:Kairos + * @method getAutoParser + * @returns {Boolean} True if auto parse is being used or false if not + */ + Kairos.getAutoParser = function () { + return Kairos._autoParser; + }; + + /** + * Validates the give expression with the current or given pattern. + * + * @memberof module:Kairos + * @method validate + * @param {String} expression Time expression to validate + * @param {String} pattern Pattern to test the expression + * @example Kairos.validate('10:30', 'hh:mm'); + * @returns {Boolean} True if valid, false if invalid + */ + Kairos.validate = function (expression, pattern) { + return Kairos.Lexicon.validate(expression, pattern); + }; + + /** + * Returns a new Kairos.Engine instance. + * * @memberof module:Kairos - * @method with - * @param {String|Number} expression Time expression - * @returns {Kairos.Gnomon} + * @method new + * @param {String|Number|kairos.Engine} time Time expression to create an instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance from the given time */ - Kairos.with = function (expression) { - return new Kairos.Gnomon(expression); + Kairos.new = function (time, pattern) { + return new Kairos.Engine(time, pattern); }; /** - * Sums augend time with addend time + * Returns an instance of Kairos.Engine with absolute time. + * + * @memberof module:Kairos + * @method absolute + * @param {String|Number|kairos.Engine} time Time expression to get its absolute value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with absolute value + */ + Kairos.absolute = function (time, pattern) { + return Kairos.new(time, pattern).toAbsolute(); + }; + + /** + * Sums augend time with addend time. * * @memberof module:Kairos * @method plus - * @param {String|Number} augend Augend time expression - * @param {String|Number} addend Addend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} augend Augend time expression + * @param {String|Number|kairos.Engine} addend Addend time expression + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the sum result */ - Kairos.plus = function (augend, addend) { - return Kairos.with(augend).plus(addend).toExpression(); + Kairos.plus = function (augend, addend, pattern) { + return Kairos.new(augend, pattern).plus(addend, pattern); }; /** - * Subtracts minuend time with subtrahend time + * Subtracts minuend time with subtrahend time. * * @memberof module:Kairos * @method minus - * @param {String|Number} minuend Minuend time expression - * @param {String|Number} subtrahend Subtrahend time expression - * @returns {String} + * @param {String|Number|kairos.Engine} minuend Minuend time expression + * @param {String|Number|kairos.Engine} subtrahend Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with subtract result */ - Kairos.minus = function (minuend, subtrahend) { - return Kairos.with(minuend).minus(subtrahend).toExpression(); + Kairos.minus = function (minuend, subtrahend, pattern) { + return Kairos.new(minuend, pattern).minus(subtrahend, pattern); }; /** - * Multiplies multiplier by the multiplicand + * Multiplies multiplier by the multiplicand. * * @memberof module:Kairos * @method multiply - * @param {String|Number} multiplier Multiplier time expression - * @param {String|Number} multiplicand Multiplicand number - * @returns {String} + * @param {String|Number|kairos.Engine} multiplier Multiplier time expression + * @param {Number} multiplicand Multiplicand value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with multiplication result */ - Kairos.multiply = function (multiplier, multiplicand) { - return Kairos.with(multiplier).multiply(multiplicand).toExpression(); + Kairos.multiply = function (multiplier, multiplicand, pattern) { + return Kairos.new(multiplier, pattern).multiply(multiplicand); }; /** - * Divides dividend by the divisor + * Divides dividend by the divisor. * * @memberof module:Kairos * @method divide - * @param {String|Number} dividend Dividend time expression - * @param {Number} divisor Dividor number - * @returns {String} + * @param {String|Number|kairos.Engine} dividend Dividend time expression + * @param {Number} divisor Divisor value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with division result */ - Kairos.divide = function (dividend, divisor) { - return Kairos.with(dividend).divide(divisor).toExpression(); + Kairos.divide = function (dividend, divisor, pattern) { + return Kairos.new(dividend, pattern).divide(divisor); }; /** - * Returns a fraction of the current time + * Returns a fraction of the current time. * * @memberof module:Kairos * @method getFraction - * @param {String|Number} time - * @param {Number} numerator - * @param {Number} denominator - * @returns {String} + * @param {String|Number|Kairos.Engine} time Time expression to extract a fraction + * @param {Number} numerator Numerator value + * @param {Number} denominator Denominator value + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the fraction extracted */ - Kairos.getFraction = function (time, numerator, denominator) { + Kairos.getFraction = function (time, numerator, denominator, pattern) { if (numerator > denominator) { throw new Error('Improper fraction'); } - return Kairos.with(time).multiply(numerator).divide(denominator).toExpression(); + return Kairos.new(time, pattern).multiply(numerator).divide(denominator); }; /** - * Returns a time expression representing the time between starting time and ending time + * Returns a time expression representing the time between starting time and ending time. * * @memberof module:Kairos * @method getInterval - * @param {String|Number} time1 time expression representing the starting time - * @param {String|Number} time2 time expression representing the ending time - * @returns {String} + * @param {String|Number|Kairos.Engine} time1 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String|Number|Kairos.Engine} time2 Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the interval between time1 and time2 */ - Kairos.getInterval = function (starting, ending) { - var st = new Kairos.Gnomon(starting); - var en = new Kairos.Gnomon(ending); - if (st.compareTo(en) > 0) { - throw new Error('Starting time must be bigger than ending time'); - } - return en.minus(st).toExpression(); + Kairos.getInterval = function (time1, time2, pattern) { + return Kairos.new(time1, pattern).minus(time2, pattern).toAbsolute(); }; /** - * Converts the given time expression to milliseconds + * Converts the given time expression to milliseconds. * * @memberof module:Kairos * @method toMilliseconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total milliseconds in the time expression */ - Kairos.toMilliseconds = function (expression) { - return Kairos.with(expression).toMilliseconds(); + Kairos.toMilliseconds = function (time, pattern) { + return Kairos.new(time, pattern).toMilliseconds(); }; /** - * Converts the given time expression to seconds + * Converts the given time expression to seconds. * * @memberof module:Kairos * @method toSeconds - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total seconds in the time expression */ - Kairos.toSeconds = function (expression) { - return Kairos.with(expression).toSeconds(); + Kairos.toSeconds = function (time, pattern) { + return Kairos.new(time, pattern).toSeconds(); }; /** - * Converts the given time expression to minutes + * Converts the given time expression to minutes. * * @memberof module:Kairos * @method toMinutes - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total minutes in the time expression */ - Kairos.toMinutes = function (expression) { - return Kairos.with(expression).toMinutes(); + Kairos.toMinutes = function (time, pattern) { + return Kairos.new(time, pattern).toMinutes(); }; /** - * Converts the given time expression to hours + * Converts the given time expression to hours. * * @memberof module:Kairos * @method toHours - * @param {String|Number} expression Time expression - * @returns {Number} + * @param {String|Number} time Literal time expression, milliseconds or a Kairos.Engine instance + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Total hours in the time expression */ - Kairos.toHours = function (expression) { - return Kairos.with(expression).toHours(); + Kairos.toHours = function (time, pattern) { + return Kairos.new(time, pattern).toHours(); }; /** * Compares first time with second time and returns -1, 0 or 1 if first value - * is smaller, equals or bigger than second value + * is smaller, equals or bigger than second value. * * @memberof module:Kairos * @method compare - * @param {String|Number} time1 Time expression - * @param {String|Number} time2 Time expression for comparation - * @returns {Number} + * @param {String|Number} comparand Time to compare with + * @param {String|Number} comparator Time to be compared with + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Number} Smaller -1 | Equals 0 | Bigger 1 */ - Kairos.compare = function (time1, time2) { - return Kairos.with(time1).compareTo(time2); + Kairos.compare = function (comparand, comparator, pattern) { + return Kairos.new(comparand, pattern).compareTo(comparator, pattern); }; /** - * Returns the minimum value from the given values + * Returns the minimum value from the given values. * * @memberof module:Kairos * @method min - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {Kairos.Engine} Kairos.Engine instance with the lowest value found in the list */ - Kairos.min = function (values) { + Kairos.min = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var min = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() < current.toMilliseconds() ? previous : current ); + return Kairos.compare(previous, current, pattern) < 0 ? previous : current; }); - - return (min instanceof Kairos.Gnomon) ? min.toExpression() : new Kairos.Gnomon(min).toExpression(); + + return Kairos.new(min, pattern); }; /** - * Returns the maximum value from the given values + * Returns the maximum value from the given values. * * @memberof module:Kairos * @method max - * @param {String[]|Number[]|Kairos.Gnomon[]} values Array with time expressions - * @returns {String} + * @param {String[]|Number[]|Kairos.Engine[]} values Array with time expressions + * @param {String} [pattern] Overrides Kairos pattern + * @returns {String} Kairos.Engine instance with the greatest value found in the list */ - Kairos.max = function (values) { + Kairos.max = function (values, pattern) { if (!(values instanceof Array)) { + pattern = null; values = Array.prototype.slice.call(arguments); } var max = values.reduce(function (previous, current) { - if (!(previous instanceof Kairos.Gnomon)) { - previous = new Kairos.Gnomon(previous ? previous : 0); - } - if (!(current instanceof Kairos.Gnomon)) { - current = new Kairos.Gnomon(current ? current : 0); - } - return ( previous.toMilliseconds() > current.toMilliseconds() ? previous : current ); + return Kairos.new(previous, pattern).compareTo(current, pattern) > 0 ? previous : current; }); - return (max instanceof Kairos.Gnomon) ? max.toExpression() : new Kairos.Gnomon(max).toExpression(); + return Kairos.new(max, pattern); }; // Node.js if (typeof module === 'object' && module.exports) { - //=include /engine/Gnomon.js + //=include /Lexicon.js + //=include /Engine.js module.exports = Kairos; } // AMD / RequireJS diff --git a/test/browser/engine.js b/test/browser/engine.js new file mode 100644 index 0000000..44c1a41 --- /dev/null +++ b/test/browser/engine.js @@ -0,0 +1,332 @@ +'use strict'; + +// Pre assign variables +var assert = assert; +var Kairos = Kairos; + +// Require modules when running with Node.js +if (typeof require !== 'undefined') { + assert = require('assert'); + Kairos = require('../../build/kairos-node'); +} + +describe('Kairos.Engine', function () { + + // Setup ===================================================================== + + var loadDefaults = function () { + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + }; + + var engine; + + before(function (done) { + done(); + }); + + // Tests ===================================================================== + + beforeEach(function (done) { + loadDefaults(); + engine = new Kairos.Engine('01:30:30.123'); + + done(); + }); + + afterEach(function () { + }); + + it('should return an instance of Kairos.Engine', function (done) { + assert.doesNotThrow(function () { + var t1 = new Kairos.Engine('10:20:30.123'); + var t2 = new Kairos.Engine(1); + + assert.equal(t1.getMilliseconds(), 123); + assert.equal(t1.getSeconds(), 30); + assert.equal(t1.getMinutes(), 20); + assert.equal(t1.getHours(), 10); + assert.equal(t1.toMilliseconds(), 37230123); + assert.equal(t1.toSeconds(), 37230.123); + assert.equal(t1.toMinutes(), 620.50205); + assert.equal(t1.toHours(), 10.341700833333332); + + assert.equal(t2.getMilliseconds(), 1); + assert.equal(t2.getSeconds(), 0); + assert.equal(t2.getMinutes(), 0); + assert.equal(t2.getHours(), 0); + assert.equal(t2.toMilliseconds(), 1); + assert.equal(t2.toSeconds(), 0.001); + assert.equal(t2.toMinutes(), 0.000016666666666666667); + assert.equal(t2.toHours(), 2.7777777777777776e-7); + + var time = new Kairos.Engine(new Kairos.Engine()); + assert.equal(time.getMilliseconds(), 0); + + time = new Kairos.Engine('10:00', 'hh:mm'); + assert.equal(time.toString('hh:mm'), '10:00'); + + Kairos.setPattern('hhh:mm:ss'); + + time = new Kairos.Engine('100:00:00'); + assert.equal(time.toString(), '100:00:00'); + }); + + done(); + }); + + it('should return an instance of Kairos.Engine with zero value', function (done) { + assert.equal(new Kairos.Engine().toMilliseconds(), 0); + + done(); + }); + + it('should throw error when expression is invalid', function (done) { + assert.throws(function () { + new Kairos.Engine('00:00:00:00:00'); + }, Error); + + done(); + }); + + it('should return the milliseconds in the expression', function (done) { + assert.equal(engine.getMilliseconds(), 123); + done(); + }); + + it('should return the seconds in the expression', function (done) { + assert.equal(engine.getSeconds(), 30); + done(); + }); + + it('should return the minutes in the expression', function (done) { + assert.equal(engine.getMinutes(), 30); + done(); + }); + + it('should return the hours in the expression', function (done) { + assert.equal(engine.getHours(), 1); + done(); + }); + + it('should convert the expression to milliseconds', function (done) { + assert.equal(engine.toMilliseconds(), 5430123); + done(); + }); + + it('should convert the expression to seconds', function (done) { + assert.equal(engine.toSeconds(), 5430.123); + done(); + }); + + it('should convert the expression to minutes', function (done) { + assert.equal(engine.toMinutes(), 90.50205); + done(); + }); + + it('should convert the expression to hours', function (done) { + assert.equal(engine.toHours(), 1.5083675); + done(); + }); + + it('should return the given expression', function (done) { + assert.equal(engine.toString(), '+01:30:30.123'); + done(); + }); + + it('should return the given negative expression', function (done) { + engine = new Kairos.Engine('-01:30:30.123'); + assert.equal(engine.toString(), '-01:30:30.123'); + done(); + }); + + it('should add 900 milliseconds to the expression', function (done) { + var t = engine.addMilliseconds(900); + assert.equal(engine.getMilliseconds(), 23); + assert.equal(engine.getSeconds(), 31); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMilliseconds(), 23); + done(); + }); + + it('should add 31 seconds to the expression', function (done) { + var t = engine.addSeconds(31); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 1); + assert.equal(engine.getMinutes(), 31); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getSeconds(), 1); + done(); + }); + + it('should add 31 minutes to the expression', function (done) { + var t = engine.addMinutes(31); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 30); + assert.equal(engine.getMinutes(), 1); + assert.equal(engine.getHours(), 2); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMinutes(), 1); + done(); + }); + + it('should add 1.5 hours to the expression', function (done) { + var t = engine.addHours(1.5); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 30); + assert.equal(engine.getMinutes(), 0); + assert.equal(engine.getHours(), 3); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getHours(), 3); + done(); + }); + + it('should remove 900 milliseconds to the expression', function (done) { + var t = engine.removeMilliseconds(900); + assert.equal(engine.getMilliseconds(), 223); + assert.equal(engine.getSeconds(), 29); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMilliseconds(), 223); + done(); + }); + + it('should remove 31 seconds to the expression', function (done) { + var t = engine.removeSeconds(31); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 59); + assert.equal(engine.getMinutes(), 29); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getSeconds(), 59); + done(); + }); + + it('should remove 31 minutes to the expression', function (done) { + var t = engine.removeMinutes(31); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 30); + assert.equal(engine.getMinutes(), 59); + assert.equal(engine.getHours(), 0); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMinutes(), 59); + done(); + }); + + it('should remove 1.5 hours to the expression', function (done) { + var t = engine.removeHours(1.5); + assert.equal(engine.getMilliseconds(), 123); + assert.equal(engine.getSeconds(), 30); + assert.equal(engine.getMinutes(), 0); + assert.equal(engine.getHours(), 0); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getHours(), 0); + done(); + }); + + it('should set expression millisecons to 321', function (done) { + var t = engine.setMilliseconds(321); + assert.equal(engine.getMilliseconds(), 321); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMilliseconds(), 321); + done(); + }); + + it('should set expression seconds to 45', function (done) { + var t = engine.setSeconds(45); + assert.equal(engine.getSeconds(), 45); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getSeconds(), 45); + done(); + }); + + it('should set expression minutes to 45', function (done) { + var t = engine.setMinutes(45); + assert.equal(engine.getMinutes(), 45); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getMinutes(), 45); + done(); + }); + + it('should set expression hours to 5', function (done) { + var t = engine.setHours(5); + assert.equal(engine.getHours(), 5); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.getHours(), 5); + done(); + }); + + it('should sum two time expressions', function (done) { + var addend = new Kairos.Engine('01:30:30.123'); + var t = engine.plus(addend); + assert.equal(engine.toString(), '+03:01:00.246'); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.toString(), '+03:01:00.246'); + done(); + }); + + it('should subtract two time expressions', function (done) { + var substrahend = new Kairos.Engine('01:30:30.123'); + var t = engine.minus(substrahend); + assert.equal(engine.toString('hh:mm'), '00:00'); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.toString('hh:mm'), '00:00'); + done(); + }); + + it('should multiply the time expression by 2', function (done) { + var t = engine.multiply(2); + assert.equal(engine.toString(), '+03:01:00.246'); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.toString(), '+03:01:00.246'); + done(); + }); + + it('should divide the time expression by 2', function (done) { + var t = engine.divide(2); + assert.equal(engine.toString(), '+00:45:15.061'); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.toString(), '+00:45:15.061'); + done(); + }); + + it('should compare first time with second time and return -1 for smaller, 0 for equals and 1 for bigger', function (done) { + Kairos.setPattern('hh:mm'); + engine = new Kairos.Engine('01:00'); + assert.equal(engine.compareTo(new Kairos.Engine('02:00')), -1); + assert.equal(engine.compareTo(new Kairos.Engine('01:00')), 0); + assert.equal(engine.compareTo(new Kairos.Engine('00:30')), 1); + done(); + }); + + it('should parse correctly expressions whith hours < 10 and > 99', function (done) { + Kairos.setPattern('hh:mm'); + var a = new Kairos.Engine('60:00'); + var b = new Kairos.Engine('80:00'); + a.plus(b); + assert.equal(a.toString('hhh:mm'), '140:00'); + + a.minus(new Kairos.Engine('139:00', 'hhh:mm')); + assert.equal(a.toString(), '01:00'); + + done(); + }); + + it('should execute commands in sequence and output the correct result', function (done) { + Kairos.setPattern('hh:mm'); + var t = new Kairos.Engine('01:00').plus('02:00').minus('01:00').divide(2).multiply(10); + assert.ok(t instanceof Kairos.Engine); + assert.equal(t.toString(), '10:00'); + done(); + }); + + it('should parse instance to string', function (done) { + var time = Kairos.new('10:00:00.000'); + assert.equal(time.toString(), '+10:00:00.000'); + assert.equal(time.toString('hh:mm'), '10:00'); + + time = Kairos.new('100:00', 'hhh:mm'); + assert.equal(time.toString(true), '+100:00:00.000'); + assert.equal(time.toString('hh:mm', true), '100:00'); + + done(); + }); +}); diff --git a/test/browser/gnomon.js b/test/browser/gnomon.js deleted file mode 100644 index d256a46..0000000 --- a/test/browser/gnomon.js +++ /dev/null @@ -1,302 +0,0 @@ -'use strict'; - -// Pre assign variables -var assert = assert; -var Kairos = Kairos; - -// Require modules when running with Node.js -if (typeof require !== 'undefined') { - assert = require('assert'); - Kairos = require('../../build/kairos-node'); -} - -describe('Kairos.Gnomon', function () { - - // Setup ===================================================================== - - var gnomon; - - before(function (done) { - done(); - }); - - // Tests ===================================================================== - - beforeEach(function () { - gnomon = new Kairos.Gnomon('01:30:30:123'); - }); - - afterEach(function () { - }); - - it('should return an instance of Kairos.Gnomon', function (done) { - assert.doesNotThrow(function () { - var t1 = new Kairos.Gnomon('10:20:30:123'); - var t2 = new Kairos.Gnomon(1); - - assert.equal(t1.getMilliseconds(), 123); - assert.equal(t1.getSeconds(), 30); - assert.equal(t1.getMinutes(), 20); - assert.equal(t1.getHours(), 10); - assert.equal(t1.toMilliseconds(), 37230123); - assert.equal(t1.toSeconds(), 37230.123); - assert.equal(t1.toMinutes(), 620.50205); - assert.equal(t1.toHours(), 10.341700833333332); - - assert.equal(t2.getMilliseconds(), 1); - assert.equal(t2.getSeconds(), 0); - assert.equal(t2.getMinutes(), 0); - assert.equal(t2.getHours(), 0); - assert.equal(t2.toMilliseconds(), 1); - assert.equal(t2.toSeconds(), 0.001); - assert.equal(t2.toMinutes(), 0.000016666666666666667); - assert.equal(t2.toHours(), 2.7777777777777776e-7); - }); - done(); - }); - - it('should return an instance of Kairos.Gnomon with zero value', function (done) { - assert.equal(new Kairos.Gnomon().toMilliseconds(), 0); - done(); - }); - - it('should throw error when expression is invalid', function (done) { - assert.throws(function () { - new Kairos.Gnomon('00:00:00:00:00'); - }, Error); - done(); - }); - - it('should throw error when a expression time step is not a number', function (done) { - assert.throws(function () { - new Kairos.Gnomon('00:00:00:a0'); - }, Error); - done(); - }); - - it('should return the milliseconds in the expression', function (done) { - assert.equal(gnomon.getMilliseconds(), 123); - done(); - }); - - it('should return the seconds in the expression', function (done) { - assert.equal(gnomon.getSeconds(), 30); - done(); - }); - - it('should return the minutes in the expression', function (done) { - assert.equal(gnomon.getMinutes(), 30); - done(); - }); - - it('should return the hours in the expression', function (done) { - assert.equal(gnomon.getHours(), 1); - done(); - }); - - it('should convert the expression to milliseconds', function (done) { - assert.equal(gnomon.toMilliseconds(), 5430123); - done(); - }); - - it('should convert the expression to seconds', function (done) { - assert.equal(gnomon.toSeconds(), 5430.123); - done(); - }); - - it('should convert the expression to minutes', function (done) { - assert.equal(gnomon.toMinutes(), 90.50205); - done(); - }); - - it('should convert the expression to hours', function (done) { - assert.equal(gnomon.toHours(), 1.5083675); - done(); - }); - - it('should return the given expression', function (done) { - assert.equal(gnomon.toExpression(), '01:30:30:123'); - done(); - }); - - it('should return the given negative expression', function (done) { - gnomon = new Kairos.Gnomon('-01:30:30:123'); - assert.equal(gnomon.toExpression(), '-01:30:30:123'); - done(); - }); - - it('should add 900 milliseconds to the expression', function (done) { - var t = gnomon.addMilliseconds(900); - assert.equal(gnomon.getMilliseconds(), 23); - assert.equal(gnomon.getSeconds(), 31); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMilliseconds(), 23); - done(); - }); - - it('should add 31 seconds to the expression', function (done) { - var t = gnomon.addSeconds(31); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 1); - assert.equal(gnomon.getMinutes(), 31); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getSeconds(), 1); - done(); - }); - - it('should add 31 minutes to the expression', function (done) { - var t = gnomon.addMinutes(31); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 30); - assert.equal(gnomon.getMinutes(), 1); - assert.equal(gnomon.getHours(), 2); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMinutes(), 1); - done(); - }); - - it('should add 1.5 hours to the expression', function (done) { - var t = gnomon.addHours(1.5); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 30); - assert.equal(gnomon.getMinutes(), 0); - assert.equal(gnomon.getHours(), 3); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getHours(), 3); - done(); - }); - - it('should remove 900 milliseconds to the expression', function (done) { - var t = gnomon.removeMilliseconds(900); - assert.equal(gnomon.getMilliseconds(), 223); - assert.equal(gnomon.getSeconds(), 29); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMilliseconds(), 223); - done(); - }); - - it('should remove 31 seconds to the expression', function (done) { - var t = gnomon.removeSeconds(31); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 59); - assert.equal(gnomon.getMinutes(), 29); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getSeconds(), 59); - done(); - }); - - it('should remove 31 minutes to the expression', function (done) { - var t = gnomon.removeMinutes(31); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 30); - assert.equal(gnomon.getMinutes(), 59); - assert.equal(gnomon.getHours(), 0); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMinutes(), 59); - done(); - }); - - it('should remove 1.5 hours to the expression', function (done) { - var t = gnomon.removeHours(1.5); - assert.equal(gnomon.getMilliseconds(), 123); - assert.equal(gnomon.getSeconds(), 30); - assert.equal(gnomon.getMinutes(), 0); - assert.equal(gnomon.getHours(), 0); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getHours(), 0); - done(); - }); - - it('should set expression millisecons to 321', function (done) { - var t = gnomon.setMilliseconds(321); - assert.equal(gnomon.getMilliseconds(), 321); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMilliseconds(), 321); - done(); - }); - - it('should set expression seconds to 45', function (done) { - var t = gnomon.setSeconds(45); - assert.equal(gnomon.getSeconds(), 45); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getSeconds(), 45); - done(); - }); - - it('should set expression minutes to 45', function (done) { - var t = gnomon.setMinutes(45); - assert.equal(gnomon.getMinutes(), 45); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getMinutes(), 45); - done(); - }); - - it('should set expression hours to 5', function (done) { - var t = gnomon.setHours(5); - assert.equal(gnomon.getHours(), 5); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.getHours(), 5); - done(); - }); - - it('should sum two time expressions', function (done) { - var addend = new Kairos.Gnomon('01:30:30:123'); - var t = gnomon.plus(addend); - assert.equal(gnomon.toExpression(), '03:01:00:246'); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.toExpression(), '03:01:00:246'); - done(); - }); - - it('should subtract two time expressions', function (done) { - var substrahend = new Kairos.Gnomon('01:30:30:123'); - var t = gnomon.minus(substrahend); - assert.equal(gnomon.toExpression(), '00:00'); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.toExpression(), '00:00'); - done(); - }); - - it('should multiply the time expression by 2', function (done) { - var t = gnomon.multiply(2); - assert.equal(gnomon.toExpression(), '03:01:00:246'); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.toExpression(), '03:01:00:246'); - done(); - }); - - it('should divide the time expression by 2', function (done) { - var t = gnomon.divide(2); - assert.equal(gnomon.toExpression(), '00:45:15:061'); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.toExpression(), '00:45:15:061'); - done(); - }); - - it('should compare first time with second time and return -1 for smaller, 0 for equals and 1 for bigger', function (done) { - gnomon = new Kairos.Gnomon('01:00'); - assert.equal(gnomon.compareTo(new Kairos.Gnomon('02:00')), -1); - assert.equal(gnomon.compareTo(new Kairos.Gnomon('01:00')), 0); - assert.equal(gnomon.compareTo(new Kairos.Gnomon('00:30')), 1); - done(); - }); - - it('should parse correctly expressions whith hours < 10 and > 99', function (done) { - var a = new Kairos.Gnomon('60:00'); - var b = new Kairos.Gnomon('80:00'); - a.plus(b); - assert.equal(a.toExpression(), '140:00'); - - a.minus(new Kairos.Gnomon('139:00')); - assert.equal(a.toExpression(), '01:00'); - - done(); - }); - - it('should execute commands in sequence and output the correct result', function (done) { - var t = new Kairos.Gnomon('01:00').plus('02:00').minus('01:00').divide(2).multiply(10); - assert.ok(t instanceof Kairos.Gnomon); - assert.equal(t.toExpression(), '10:00'); - done(); - }); -}); diff --git a/test/browser/kairos.js b/test/browser/kairos.js index adc12fa..7987b9a 100644 --- a/test/browser/kairos.js +++ b/test/browser/kairos.js @@ -14,19 +14,16 @@ describe('Kairos', function () { // Setup ===================================================================== - var gnomon; - - before(function (done) { - done(); - }); + var loadDefaults = function () { + Kairos._pattern = '#hh:mm:ss.SSS'; + Kairos._validator = new RegExp(/^[+-]?\d\d:\d\d:\d\d\.\d\d\d/); + }; // Tests ===================================================================== - beforeEach(function () { - gnomon = new Kairos.Gnomon('01:30:30:123'); - }); - - afterEach(function () { + afterEach(function (done) { + loadDefaults(); + done(); }); it('should return previous instance of Kairos if it already exists', function (done) { @@ -36,139 +33,187 @@ describe('Kairos', function () { done(); }); + it('should set a new pattern to Kairos', function (done) { + Kairos.setPattern('hh:mm'); + assert.equal(Kairos.getPattern() === 'hh:mm', true); + done(); + }); + + it('should set auto parser to true or false', function (done) { + Kairos.setAutoParser(true); + assert.equal(Kairos.getAutoParser(), true); + + var time = Kairos.new('10:00'); + assert.equal(time.toString(), '+10:00:00.000'); + + Kairos.setAutoParser(false); + assert.equal(Kairos.getAutoParser(), false); + + assert.throws(function () { + Kairos.new('10:00'); + }, Error); + + done(); + }); + + it('should validate the expression with the given pattern or the current Kairos pattern', function (done) { + assert.equal(Kairos.validate('22:30', 'hh:mm'), true); + assert.equal(Kairos.validate('22:30', 'hh'), true); + assert.equal(Kairos.validate('-22:30:30.500'), true); + assert.equal(Kairos.validate('-22:30:30'), false); + assert.equal(Kairos.validate('-300:30:30'), false); + done(); + }); + it('should sum first time expression with second time expression', function (done) { - var time = Kairos.plus('01:00', '01:30:35:100'); - assert.equal(time, '02:30:35:100'); + var time = Kairos.plus('01:00:00.000', '01:30:35.100'); + assert.equal(time.toString(), '+02:30:35.100'); + time = Kairos.plus('01:00:00', '01:30:35', 'hh:mm:ss'); + assert.equal(time.toString('hh:mm:ss'), '02:30:35'); done(); }); it('should subtract first time expression with second time expression', function (done) { - var time = Kairos.minus('01:30:35:100', '01:15'); - assert.equal(time, '00:15:35:100'); + var time = Kairos.minus('01:30:35.100', '01:15:00.000'); + assert.equal(time.toString(), '+00:15:35.100'); + time = Kairos.minus('01:30:35', '01:15:00', 'hh:mm:ss'); + assert.equal(time.toString('hh:mm:ss'), '00:15:35'); done(); }); it('should multiply the time expression by 2', function (done) { - assert.equal(Kairos.multiply('01:30:35:100', 2), '03:01:10:200'); + assert.equal(Kairos.multiply('01:30:35.100', 2).toString(), '+03:01:10.200'); + assert.equal(Kairos.multiply('01:30:35', 2, 'hh:mm:ss').toString('hh:mm:ss'), '03:01:10'); done(); }); it('should divide the time expression by 2', function (done) { - assert.equal(Kairos.divide('01:30:35:100', 2), '00:45:17:550'); + assert.equal(Kairos.divide('01:30:35.100', 2).toString(), '+00:45:17.550'); + assert.equal(Kairos.divide('01:30:35', 2, 'hh:mm:ss').toString('hh:mm:ss'), '00:45:17'); done(); }); it('should return a time fraction', function (done) { - assert.equal(Kairos.getFraction('01:00', 2, 3), '00:40'); + assert.equal(Kairos.getFraction('01:00:00.000', 2, 3).toString(), '+00:40:00.000'); + assert.equal(Kairos.getFraction('01:00:00', 2, 3, 'hh:mm:ss').toString('hh:mm:ss'), '00:40:00'); done(); }); it('should throw error when a improper fraction is given', function (done) { assert.throws(function () { - Kairos.getFraction('01:00', 3, 2); + Kairos.getFraction('01:00:00.000', 3, 2); }); done(); }); - + it('should return a time expression representing the interval between starting time and ending time', function (done) { - assert.equal(Kairos.getInterval('01:00', '02:00'), '01:00'); + assert.equal(Kairos.getInterval('01:00:00.000', '02:00:00.000').toString(), '+01:00:00.000'); + assert.equal(Kairos.getInterval('01:00:00', '02:00:00', 'hh:mm:ss').toString('hh:mm:ss'), '01:00:00'); done(); }); - it('should throw error when starting time is bigger than ending time', function (done) { - assert.throws(function () { - Kairos.getInterval('02:00', '01:00'); - }); - done(); - }); - it('should return total milliseconds in the given time expression', function (done) { - assert.equal(Kairos.toMilliseconds('01:30:35:100'), 5435100); + assert.equal(Kairos.toMilliseconds('01:30:35.100'), 5435100); + assert.equal(Kairos.toMilliseconds('01:30:35', 'hh:mm:ss'), 5435000); done(); }); it('should return total seconds in the given time expression', function (done) { - assert.equal(Kairos.toSeconds('01:30:35:100'), 5435.1); + assert.equal(Kairos.toSeconds('01:30:35.100'), 5435.1); + assert.equal(Kairos.toSeconds('01:30:35', 'hh:mm:ss'), 5435); done(); }); it('should return total minutes in the given time expression', function (done) { - assert.equal(Kairos.toMinutes('01:30:35:100'), 90.585); + assert.equal(Kairos.toMinutes('01:30:35.100'), 90.585); + assert.equal(Kairos.toMinutes('01:30:35', 'hh:mm:ss'), 90.58333333333333); done(); }); it('should return total hours in the given time expression', function (done) { - assert.equal(Kairos.toHours('01:30:35:100'), 1.50975); + assert.equal(Kairos.toHours('01:30:35.100'), 1.50975); + assert.equal(Kairos.toHours('01:30:35', 'hh:mm:ss'), 1.5097222222222222); done(); }); it('should compare first time with second time and return -1 for smaller, 0 for equals and 1 for bigger', function (done) { - assert.equal(Kairos.compare('01:00', '02:00'), -1); - assert.equal(Kairos.compare('01:00', '01:00'), 0); - assert.equal(Kairos.compare('02:00', '01:00'), 1); + assert.equal(Kairos.compare('01:00:00.000', '02:00:00.000'), -1); + assert.equal(Kairos.compare('01:00:00.000', '01:00:00.000'), 0); + assert.equal(Kairos.compare('02:00:00.000', '01:00:00.000'), 1); + assert.equal(Kairos.compare('01:00:00', '01:00:00.000', 'hh:mm:ss'), 0); done(); }); - + it('should return the minimun value from the given values', function (done) { - assert.equal(Kairos.min(['01:00', '05:00', '00:30', '00:40']), '00:30'); - + assert.equal(Kairos.min(['01:00', '05:00', '00:30', '00:40'], 'hh:mm').toString('hh:mm'), '00:30'); + assert.equal(Kairos.min([ - new Kairos.Gnomon('01:00'), - new Kairos.Gnomon('05:00'), - new Kairos.Gnomon('00:30'), - new Kairos.Gnomon('00:40')]), '00:30'); - - assert.equal(Kairos.min('01:00', '05:00', '00:30', '00:40'), '00:30'); - - assert.equal(Kairos.min(new Kairos.Gnomon('01:00'), - new Kairos.Gnomon('05:00'), - new Kairos.Gnomon('00:30'), - new Kairos.Gnomon('00:40')), '00:30'); - - assert.equal(Kairos.min('01:00'), '01:00'); + new Kairos.Engine('01:00:00.000'), + new Kairos.Engine('05:00:00.000'), + new Kairos.Engine('00:30:00.000'), + new Kairos.Engine('00:40', 'hh:mm')]).toString(), '+00:30:00.000'); + + assert.equal(Kairos.min('01:00:00.000', '05:00:00.000', '00:30:00.000', '00:40:00.000').toString('hh:mm'), '00:30'); + assert.equal(Kairos.min(100, 200, 300).toString('SSS'), '100'); + + assert.equal(Kairos.min(new Kairos.Engine('01:00:00.000'), + new Kairos.Engine('05:00:00.000'), + new Kairos.Engine('00:30:00.000'), + new Kairos.Engine('00:40', 'hh:mm')).toString('mm'), '30'); + + assert.equal(Kairos.min('01:00:00.000').toString('hh:mm'), '01:00'); + done(); }); - + it('should return the maximum value from the given values', function (done) { - assert.equal(Kairos.max(['01:00', '05:00', '00:30', '00:40']), '05:00'); - + assert.equal(Kairos.max(['01:00', '05:00', '00:30', '00:40'], 'hh:mm').toString('hh:mm'), '05:00'); + assert.equal(Kairos.max([ - new Kairos.Gnomon('01:00'), - new Kairos.Gnomon('05:00'), - new Kairos.Gnomon('00:30'), - new Kairos.Gnomon('00:40')]), '05:00'); - - assert.equal(Kairos.max('01:00', '05:00', '00:30', '00:40'), '05:00'); - - assert.equal(Kairos.max(new Kairos.Gnomon('01:00'), - new Kairos.Gnomon('05:00'), - new Kairos.Gnomon('00:30'), - new Kairos.Gnomon('00:40')), '05:00'); - - assert.equal(Kairos.max('01:00'), '01:00'); + new Kairos.Engine('01:00:00.000'), + new Kairos.Engine('05:00:00.000'), + new Kairos.Engine('00:30:00.000'), + new Kairos.Engine('00:40', 'hh:mm')]).toString(), '+05:00:00.000'); + + assert.equal(Kairos.max('01:00:00.000', '05:00:00.000', '00:30:00.000', '00:40:00.000').toString('hh:mm'), '05:00'); + assert.equal(Kairos.max(100, 200, 300).toString('SSS'), '300'); + + assert.equal(Kairos.max(new Kairos.Engine('01:00:00.000'), + new Kairos.Engine('05:00:00.000'), + new Kairos.Engine('00:30:00.000'), + new Kairos.Engine('00:40', 'hh:mm')).toString('hh'), '05'); + + assert.equal(Kairos.max('01:00:00.000').toString('hh:mm'), '01:00'); + done(); }); - it('should invalidate the given expression', function (done) { - assert.equal(Kairos.validateExpression('10:000'), false); - done(); - }); - - it('should validate the given expression', function (done) { - assert.equal(Kairos.validateExpression('10:01:00:000'), true); + it('should create an instance of Kairos.Engine', function (done) { + var a = Kairos.new(); + var b = Kairos.new('+01:00:00.000'); + var c = Kairos.new(123); + var d = Kairos.new('01:00', 'hh:mm'); + + assert.ok(a instanceof Kairos.Engine); + assert.ok(b instanceof Kairos.Engine); + assert.ok(c instanceof Kairos.Engine); + assert.ok(d instanceof Kairos.Engine); + + assert.throws(function () { + assert.Kairos.new('+01:00:00:000'); + }, Error); + done(); }); - - it('should create an instance of Kairos.Gnomon', function (done) { - var a = Kairos.with(); - var b = Kairos.with('01:00'); - var c = Kairos.with(123); - - assert.ok(a instanceof Kairos.Gnomon); - assert.ok(b instanceof Kairos.Gnomon); - assert.ok(c instanceof Kairos.Gnomon); + + it('should return an instance with absolute value', function (done) { + assert.equal(Kairos.absolute('-10:30:00.000').toString(), '+10:30:00.000'); + assert.equal(Kairos.absolute('-10:30', '#hh:mm').toString(), '+10:30:00.000'); + assert.equal(Kairos.absolute(new Kairos.Engine('-10:30:00.000')), '+10:30:00.000'); + assert.equal(Kairos.absolute(-500).toString(), '+00:00:00.500'); + done(); }); }); diff --git a/test/browser/lexicon.js b/test/browser/lexicon.js new file mode 100644 index 0000000..31519bd --- /dev/null +++ b/test/browser/lexicon.js @@ -0,0 +1,88 @@ +'use strict'; + +// Pre assign variables +var assert = assert; +var Kairos = Kairos; + +// Require modules when running with Node.js +if (typeof require !== 'undefined') { + assert = require('assert'); + Kairos = require('../../build/kairos-node'); +} + +describe('Kairos.Lexicon', function () { + + // Setup ===================================================================== + + var loadDefaults = function () { + Kairos._autoParser = false; + }; + + // Tests ===================================================================== + + afterEach(function (done) { + loadDefaults(); + done(); + }); + + it('should generate a validator from the given pattern', function (done) { + var validator = Kairos.Lexicon.getValidator('hh:mm'); + assert.ok(validator.test('10:30')); + assert.equal(validator.test('10'), false); + + validator = Kairos.Lexicon.getValidator(); + assert.ok(validator.test('10:30:00.000')); + assert.equal(validator.test('10:30'), false); + + validator = Kairos.Lexicon.getValidator(123456); + assert.ok(validator.test('10:30:00.000')); + assert.equal(validator.test('10:30'), false); + + done(); + }); + + it('should validate an expression using a pattern', function (done) { + assert.ok(Kairos.Lexicon.validate('10:00:30.000')); + assert.equal(Kairos.Lexicon.validate('10:00:30'), false); + assert.equal(Kairos.Lexicon.validate('10:00:30', 'hh:mm:ss'), true); + + done(); + }); + + it('should parse the given expression to a Kairos.Engine instance', function (done) { + var time = Kairos.Lexicon.parse('10:30:00.000'); + assert.ok(time instanceof Kairos.Engine); + assert.equal(time.toString(), '+10:30:00.000'); + + time = Kairos.Lexicon.parse('10:30', 'hh:mm'); + assert.ok(time instanceof Kairos.Engine); + assert.equal(time.toString(), '+10:30:00.000'); + + assert.throws(function () { + Kairos.Lexicon.parse('10:30'); + }, Error); + + done(); + }); + + it('should return a formated string from a Kairos.Engine ', function (done) { + var time = Kairos.Lexicon.format(Kairos.new('10:00:00.000'), 'hh:mm'); + assert.equal(time, '10:00'); + + time = Kairos.Lexicon.format(Kairos.new('10:00:00.000')); + assert.equal(time, '+10:00:00.000'); + + Kairos.setAutoParser(true); + time = Kairos.Lexicon.format(Kairos.new('100:00:00.000'), null, true); + assert.equal(time, '+100:00:00.000'); + + done(); + }); + + it('should find the pattern for the given expression', function (done) { + var time = Kairos.Lexicon.findPattern('+10:00:00.000'); + assert.equal(time, '#hh:mm:ss.SSS'); + + done(); + }); +}); \ No newline at end of file diff --git a/test/browser/test.html b/test/browser/test.html index b223867..719df53 100644 --- a/test/browser/test.html +++ b/test/browser/test.html @@ -12,7 +12,8 @@ - + +