diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..c6c8b36
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.gitignore b/.gitignore
index 9daeafb..3c3629e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-test
+node_modules
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,2 @@
+{
+}
diff --git a/.npmignore b/.npmignore
index 9daeafb..44aaf22 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1 +1,5 @@
test
+.editorconfig
+.jshintrc
+Gruntfile.js
+.DS_Store
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f94f4ed
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - "0.10"
+ - "0.11"
+before_script:
+ - npm install -g grunt-cli
+script: grunt test
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..82ae255
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+#Changelog
+
+##1.1.0
+
+- Added MIT license
+- Added Changelog
+- Added Grunt config
+- Added editorconfig
+- Added Tests
+- Fixed JSHint errors
+- Formatted code as per editorconfig
+- Fixed bug with conversion from year(s) to another unit
+- Make sure `Error` (type) is thrown when invalid unit is encountered
+- Added minified distributable version
+- Updated package.json
+- Added bower config
+- Added travis config
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..30835ef
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,43 @@
+module.exports = function(grunt) {
+ // measure the time each task takes
+ require('time-grunt')(grunt);
+
+ // autoload Grunt tasks
+ require('load-grunt-tasks')(grunt);
+
+ // main project config
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ uglify: {
+ dist: {
+ files: {
+ 'dist/<%= pkg.name %>.min.js': '<%= pkg.name %>.js'
+ }
+ }
+ },
+ jshint: {
+ options: {
+ jshintrc: true
+ },
+ files: [
+ 'Gruntfile.js',
+ '<%= pkg.name %>.js',
+ 'test/**/*.js'
+ ]
+ },
+ mochaTest: {
+ test: {
+ options: {
+ reporter: 'spec'
+ },
+ src: ['test/**/*.js']
+ }
+ }
+ });
+
+ // user defined tasks
+ grunt.registerTask('test', ['mochaTest']);
+ grunt.registerTask('lint', ['jshint']);
+ grunt.registerTask('build', ['uglify']);
+ grunt.registerTask('default', ['jshint', 'mochaTest', 'uglify']);
+};
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..669e532
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) Michael David Barrett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
index 7e5d2e6..042da42 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
#Timestring
+[![Build Status](https://travis-ci.org/mike182uk/timestring.svg?branch=master)](https://travis-ci.org/mike182uk/timestring)
+
+[![NPM](https://nodei.co/npm/timestring.png?downloads=true&stars=true)](https://nodei.co/npm/timestring/)
+
Attempts to parse a human readable time string into a time based value.
##Overview
@@ -158,14 +162,21 @@ console.log(daysThisWeek); // will log 5
###Browser
-All you need to do to get timestring working in the browser is download / clone this repo and make sure you include the `timestring.js` script on your page:
+All you need to do to get timestring working in the browser is download / clone this repo and make sure you include the `dist/timestring.min.js` script on your page:
```html
-
+
```
-### Node
-To install for a node project, navigate to the projects root folder and in your terminal type the following:
+Alternatively you can you use bower to manage this dependency for you:
+
+```
+bower install timestring --save
+```
+
+###Node
+
+To install for a node application, navigate to the projects root folder and in your terminal type the following:
```
npm install timestring
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..9cf4dee
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,16 @@
+{
+ "name": "timestring",
+ "main": "timestring.js",
+ "version": "1.1.0",
+ "description": "Parse a human readable time string into a time based value",
+ "homepage": "https://github.com/mike182uk/timestring",
+ "authors": [
+ "Michael David Barrett "
+ ],
+ "license": "MIT",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "test"
+ ]
+}
diff --git a/dist/timestring.min.js b/dist/timestring.min.js
new file mode 100644
index 0000000..470b3d1
--- /dev/null
+++ b/dist/timestring.min.js
@@ -0,0 +1 @@
+(function(){"use strict";var a=function(a){var b={hoursPerDay:24,daysPerWeek:7,weeksPerMonth:4,monthsPerYear:12};a=a||{},this.settings=b;for(var c in a)this.settings[c]=a[c];this.units={s:["s","sec","secs","second","seconds"],m:["m","min","mins","minute","minutes"],h:["h","hr","hrs","hour","hours"],d:["d","day","days"],w:["w","week","weeks"],mth:["mth","mths","month","months"],y:["y","yr","yrs","year","years"]},this.unitValues={s:1,m:60,h:3600},this.unitValues.d=this.settings.hoursPerDay*this.unitValues.h,this.unitValues.w=this.settings.daysPerWeek*this.unitValues.d,this.unitValues.mth=this.settings.weeksPerMonth*this.unitValues.w,this.unitValues.y=this.settings.monthsPerYear*this.unitValues.mth};a.prototype.parse=function(a,b){function c(a){for(var b in f.units)for(var c in f.units[b])if(a===f.units[b][c])return b;throw new Error("The unit ["+a+"] is not supported by timestring")}function d(a,b){var d=f.unitValues[c(b)];return a/d}function e(a,b){var d=f.unitValues[c(b)];return a*d}var f=this,g=0,h=a.toLowerCase().replace(/[^\.\w+-]+/g,"").match(/[-+]?[0-9]+[a-z]+/g);if(null!==h)for(var i=0;i",
- "repository" : {
- "type": "git",
- "url": "git://github.com/mike182uk/timestring.git"
- },
- "main" : "timestring.js",
- "version" : "1.0.2"
+ "name": "timestring",
+ "description": "Parse a human readable time string into a time based value",
+ "homepage": "https://github.com/mike182uk/timestring",
+ "author": "Michael David Barrett ",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mike182uk/timestring.git"
+ },
+ "main": "timestring.js",
+ "version": "1.1.0",
+ "devDependencies": {
+ "chai": "^1.9.1",
+ "grunt": "^0.4.5",
+ "grunt-contrib-jshint": "^0.10.0",
+ "grunt-contrib-uglify": "^0.5.0",
+ "grunt-mocha-test": "^0.11.0",
+ "load-grunt-tasks": "^0.6.0",
+ "mocha": "^1.20.1",
+ "time-grunt": "^0.4.0"
+ }
}
diff --git a/test/timestring.js b/test/timestring.js
new file mode 100644
index 0000000..d27ec9d
--- /dev/null
+++ b/test/timestring.js
@@ -0,0 +1,75 @@
+var chai = require('chai');
+var expect = chai.expect;
+var timestring = require('../timestring');
+
+describe('timestring', function() {
+ it('can parse a timestring', function(done) {
+ var ts = new timestring();
+
+ expect(ts.parse('1s')).to.equal(1);
+ expect(ts.parse('1m')).to.equal(60);
+ expect(ts.parse('1h')).to.equal(3600);
+ expect(ts.parse('1d')).to.equal(86400);
+ expect(ts.parse('1w')).to.equal(604800);
+ expect(ts.parse('1mth')).to.equal(2419200);
+ expect(ts.parse('1y')).to.equal(29030400);
+
+ done();
+ });
+
+ it('can return a value in a specified unit', function(done) {
+ expect((new timestring()).parse('5m', 's')).to.equal(300);
+ expect((new timestring()).parse('5m', 'm')).to.equal(5);
+
+ done();
+ });
+
+ it('uses the passed settings instead of the defaults', function(done) {
+ var settings = {
+ hoursPerDay: 1,
+ daysPerWeek: 2,
+ weeksPerMonth: 3,
+ monthsPerYear: 4
+ };
+
+ var ts = new timestring(settings);
+
+ expect(ts.parse('1d', 'h')).to.equal(1);
+ expect(ts.parse('1w', 'd')).to.equal(2);
+ expect(ts.parse('1mth', 'w')).to.equal(3);
+ expect(ts.parse('1y', 'mth')).to.equal(4);
+
+
+ done();
+ });
+
+ it('throws an error when an invalid unit is used in the timestring', function(done) {
+ var ts = new timestring();
+
+ expect(ts.parse.bind(ts, '1g')).to.throw(Error);
+
+ done();
+ });
+
+ it('can parse a messy time string', function(done) {
+ expect((new timestring()).parse('5 D a YS 4 h 2 0 mI nS')).to.equal(447600);
+
+ done();
+ });
+
+ it('should expose a method on String.prototype that will parse the string as a timestring', function(done){
+ var str = '1min';
+
+ // no arguments passed
+ expect(str.parseTime()).to.equal(60);
+
+ // units argument passed
+ expect(str.parseTime('m')).to.equal(1);
+
+ // units + settings argument passed
+ str = '5h';
+ expect(str.parseTime('d', { hoursPerDay: 5 })).to.equal(1);
+
+ done();
+ });
+});
diff --git a/timestring.js b/timestring.js
index fe53b7b..b0249b2 100644
--- a/timestring.js
+++ b/timestring.js
@@ -1,111 +1,112 @@
(function(){
- "use strict";
+ "use strict";
- var Timestring = function(settings) {
- // default settings
- var defaults = {
- hoursPerDay: 24,
- daysPerWeek: 7,
- weeksPerMonth: 4,
- monthsPerYear: 12
- };
-
- // merge default settings with user settings
- var settings = settings || {};
- this.settings = {};
- for (var property in defaults) { this.settings[property] = defaults[property]; }
- for (var property in settings) { this.settings[property] = settings[property]; }
-
- // time units
- this.units = {
- s: ['s', 'sec', 'secs', 'second', 'seconds'],
- m: ['m', 'min', 'mins', 'minute', 'minutes'],
- h: ['h', 'hr', 'hrs', 'hour', 'hours'],
- d: ['d', 'day', 'days'],
- w: ['w', 'week', 'weeks'],
- mth: ['mth', 'mths','month', 'months'],
- y: ['y', 'yr', 'yrs', 'year', 'years']
- };
-
- // time unit seconds mappings
- this.unitValues = {
- s: 1,
- m: 60,
- h: 3600
- };
-
- // dynamic time unit seconds mappings
- // these are dynamic based on the settings
- this.unitValues.d = this.settings.hoursPerDay * this.unitValues.h;
- this.unitValues.w = this.settings.daysPerWeek * this.unitValues.d;
- this.unitValues.mth = this.settings.weeksPerMonth * this.unitValues.w;
- this.unitValues.y = this.settings.monthsPerYear * this.unitValues.w;
+ var Timestring = function(settings) {
+ // default settings
+ var defaults = {
+ hoursPerDay: 24,
+ daysPerWeek: 7,
+ weeksPerMonth: 4,
+ monthsPerYear: 12
};
- Timestring.prototype.parse = function(string, returnUnit) {
- // reference to this
- var self = this;
+ // merge default settings with user settings
+ settings = settings || {};
+ this.settings = defaults;
+ for (var s in settings) { this.settings[s] = settings[s]; }
- // get unit key helper
- function getUnitKey(unit) {
- for (var key in self.units) {
- for (var u in self.units[key]) {
- if (unit === self.units[key][u]) {
- return key;
- }
- }
- }
+ // time units
+ this.units = {
+ s: ['s', 'sec', 'secs', 'second', 'seconds'],
+ m: ['m', 'min', 'mins', 'minute', 'minutes'],
+ h: ['h', 'hr', 'hrs', 'hour', 'hours'],
+ d: ['d', 'day', 'days'],
+ w: ['w', 'week', 'weeks'],
+ mth: ['mth', 'mths','month', 'months'],
+ y: ['y', 'yr', 'yrs', 'year', 'years']
+ };
- // throw exception if invalid unit is passed
- throw 'The unit [' + unit + '] is not supported by timestring';
+ // time unit seconds mappings
+ this.unitValues = {
+ s: 1,
+ m: 60,
+ h: 3600
+ };
+
+ // dynamic time unit seconds mappings
+ // these are dynamic based on the settings
+ this.unitValues.d = this.settings.hoursPerDay * this.unitValues.h;
+ this.unitValues.w = this.settings.daysPerWeek * this.unitValues.d;
+ this.unitValues.mth = this.settings.weeksPerMonth * this.unitValues.w;
+ this.unitValues.y = this.settings.monthsPerYear * this.unitValues.mth;
+ };
+
+ Timestring.prototype.parse = function(string, returnUnit) {
+ // reference to this
+ var that = this;
+
+ // get unit key helper
+ function getUnitKey(unit) {
+ for (var k in that.units) {
+ for (var u in that.units[k]) {
+ if (unit === that.units[k][u]) {
+ return k;
+ }
}
+ }
- // convert a value to a specific unit
- function convert(value, unit) {
- var baseValue = self.unitValues[getUnitKey(unit)];
- return value / baseValue;
- }
-
- // get a value in seconds based on a specific unit
- function getSeconds(value, unit) {
- var baseValue = self.unitValues[getUnitKey(unit)];
- return value * baseValue;
- }
-
- // seconds counter
- var totalSeconds = 0;
-
- // split string into groups and get total seconds for each group
- var groups = string
- .toLowerCase() // convert words to lower case
- .replace(/[^\.\w+-]+/g, '') // remove white space
- .match(/[-+]?[0-9]+[a-z]+/g); // match time groups (digit followed by time unit - i.e 5d 15m = 2 time groups)
-
- if (groups !== null) {
- for(var i = 0; i < groups.length; i++) {
- var g = groups[i];
- var value = g.match(/[0-9]+/g)[0];
- var unit = g.match(/[a-z]+/g)[0];
-
- totalSeconds += getSeconds(value, unit);
- }
- }
-
- // return total, convert if needed
- return (returnUnit) ? convert(totalSeconds, returnUnit) : totalSeconds;
+ // throw error if invalid unit was passed
+ throw new Error('The unit [' + unit + '] is not supported by timestring');
}
- // add convenience method to string prototype
- String.prototype.parseTime = function (unit, settings) {
- return (new Timestring(settings)).parse(this, unit);
+ // convert a value to a specific unit
+ function convert(value, unit) {
+ var baseValue = that.unitValues[getUnitKey(unit)];
+
+ return value / baseValue;
}
- // export Timestring object for either the browser or node
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = Timestring;
+ // get a value in seconds based on a specific unit
+ function getSeconds(value, unit) {
+ var baseValue = that.unitValues[getUnitKey(unit)];
+
+ return value * baseValue;
}
- else {
- this.Timestring = Timestring;
+
+ // seconds counter
+ var totalSeconds = 0;
+
+ // split string into groups and get total seconds for each group
+ var groups = string
+ .toLowerCase() // convert words to lower case
+ .replace(/[^\.\w+-]+/g, '') // remove white space
+ .match(/[-+]?[0-9]+[a-z]+/g); // match time groups (digit followed by time unit - i.e 5d 15m = 2 time groups)
+
+ if (groups !== null) {
+ for(var i = 0; i < groups.length; i++) {
+ var g = groups[i];
+ var value = g.match(/[0-9]+/g)[0];
+ var unit = g.match(/[a-z]+/g)[0];
+
+ totalSeconds += getSeconds(value, unit);
+ }
}
+ // return total, convert if needed
+ return (returnUnit) ? convert(totalSeconds, returnUnit) : totalSeconds;
+ };
+
+ // add convenience method to string prototype
+ String.prototype.parseTime = function (unit, settings) {
+ return (new Timestring(settings)).parse(this, unit);
+ };
+
+ // export Timestring object
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Timestring;
+ }
+ else {
+ this.Timestring = Timestring;
+ }
+
}).call(this);