text: var datetime = require('../');
  var assert = require('assert');
  var time = '2015-01-01 00:00:00.000';
  var past = '2014-11-02 00:00:00.000';
  var future = '2015-03-02 00:00:00.000';
  var dayOffset = 60;
  var hourOffset = 25;
  var hourPast = '2014-12-30 23:00:00.000';
  var hourFuture = '2015-01-02 01:00:00.000';
  
  describe('Tests node-datetime', function () {
  	
  	it('Can create datetime object with no argument passed', function () {
  		var d = datetime.create();
  		assert(d);
  	});
  
  	it('Can return timestamp in milliseconds', function () {
  		var then = new Date(time).getTime();
  		var d = datetime.create(time);
  		assert.equal(then, d.getTime());
  	});
  
  	it('Can return timestamp in seconds', function () {
  		var then = Math.floor(new Date(time).getTime() / 1000);
  		var d = datetime.create(time);
  		assert.equal(then, d.epoch());
  	});
  
  	it('Can return now in milliseconds', function (done) {
  		var then = new Date(time).getTime();
  		var d = datetime.create(time);
  		setTimeout(function () {
  			var now = d.now();
  			assert.notEqual(then, now);
  			done();
  		}, 1000);
  	});
  
      it('Can format D 1st', function () {
          var d = datetime.create('2018-01-01 00:00:00');
          var f = d.format('D');
          assert.equal(f, '1st');
      });
  
      it('Can format D 2nd', function () {
          var d = datetime.create('2018-01-02 00:00:00');
          var f = d.format('D');
          assert.equal(f, '2nd');
      });
  
      it('Can format D 3rd', function () {
          var d = datetime.create('2018-01-03 00:00:00');
          var f = d.format('D');
          assert.equal(f, '3rd');
      });
  
      it('Can format D 4th', function () {
          var d = datetime.create('2018-01-04 00:00:00');
          var f = d.format('D');
          assert.equal(f, '4th');
      });
  
      it('Can format D 10th', function () {
          var d = datetime.create('2018-01-10 00:00:00');
          var f = d.format('D');
          assert.equal(f, '10th');
      });
  
      it('Can format D 11th', function () {
          var d = datetime.create('2018-01-11 00:00:00');
          var f = d.format('D');
          assert.equal(f, '11th');
      });
  
      it('Can format D 12th', function () {
          var d = datetime.create('2018-01-12 00:00:00');
          var f = d.format('D');
          assert.equal(f, '12th');
      });
  
      it('Can format D 13th', function () {
          var d = datetime.create('2018-01-13 00:00:00');
          var f = d.format('D');
          assert.equal(f, '13th');
      });
  
      it('Can format D 14th', function () {
          var d = datetime.create('2018-01-14 00:00:00');
          var f = d.format('D');
          assert.equal(f, '14th');
      });
  
  	it('Can format Y-m-d H:M:S.N', function () {
  		var d = datetime.create(time);
  		var f = d.format('Y-m-d H:M:S.N');
  		assert.equal(f, time);
  	});
  
  	it('Can format Y-m-d I:M:S.N', function () {
  		var str = '2015-05-01 04:30:00.666';
  		var d = datetime.create(str);
  		var f = d.format('Y-m-d I:M:S.N');
  		assert.equal(str, f);
  	});
  
  	it('Can return w/ I:M:S p', function () {
  		datetime.setPeriod([ '午前', '午後' ]);		
  		var str = '2017-09-05 14:21:00';
  		var d = datetime.create(str);
  		var f = d.format('I:M:S p');
  		assert.equal('02:21:00 午後', f);
  	});
  
  	it('Can return y/m/d', function () {
  		var d = datetime.create(time);
  		var f = d.format('y/m/d');
  		assert.equal(f, '15/01/01');
  	});
  	
  	it('Can return name of week', function () {
  		var d = datetime.create(time);
  		var f = d.format('w W');
  		assert.equal('Thu Thursday', f);
  	});
  
  	it('Can return a short name of a month', function () {
  		var d = datetime.create(time);
  		var m = d.format('n');
  		assert.equal('Jan', m);	
  	});
  
  	it('Can return a full name of a month', function () {
  		var d = datetime.create(time);
  		var m = d.format('f');
  		assert.equal('January', m);	
  	});
  
  	it('Can offset ' + dayOffset + ' days in the past', function () {
  		var d = datetime.create(time);
  		d.offsetInDays(-1 * dayOffset);
  		assert.equal(past, d.format('Y-m-d H:M:S.N'));
  	});
  
  	it('Can offset ' + dayOffset + ' days in the future', function () {
  		var d = datetime.create(time);
  		d.offsetInDays(dayOffset);
  		assert.equal(future, d.format('Y-m-d H:M:S.N'));
  	});
  
  	it('Can offset ' + hourOffset + ' hours in the past', function () {
  		var d = datetime.create(time);
  		d.offsetInHours(-1 * hourOffset);
  		assert.equal(d.format('Y-m-d H:M:S.N'), hourPast);
  	});
  
  	it('Can offset ' + hourOffset + ' hours in the future', function () {
  		var d = datetime.create(time);
  		d.offsetInHours(hourOffset);
  		assert.equal(d.format('Y-m-d H:M:S.N'), hourFuture);
  	});
  
  	it('Can get instances of DateTime object between 2015-04-12 and 2015-05-12', function () {
  		var format = 'Y-m-d H:M:S.N';
  		var start = datetime.create('2015-04-12', format);
  		var end = datetime.create('2015-05-12', format);
  		var list = start.getDatesInRange(end);
          for (var i = 0, len = list.length; i < len; i++) {
  			var day = list[i];
  			var check = datetime.create(start.getTime(), format);
  			check.offsetInDays(i);
              assert.equal(end._defaultFormat, format);
              assert.equal(end._defaultFormat, check._defaultFormat);
              assert.equal(check._defaultFormat, day._defaultFormat);
  			assert.equal(day.format(), check.format());
  		}
  	});
  
  	it('Can get instances of DateTime object between 2015-05-12 and 2015-04-12', function () {
  		var format = 'Y-m-d H:M:S.N';
  		var start = datetime.create('2015-05-12', format);
  		var end = datetime.create('2015-04-12', format);
  		var list = start.getDatesInRange(end).reverse();
          for (var i = 0, len = list.length; i < len; i++) {
  			var day = list[i];
  			var check = datetime.create(end.getTime(), format);
  			check.offsetInDays(i);
              assert.equal(end._defaultFormat, format);
              assert.equal(end._defaultFormat, check._defaultFormat);
              assert.equal(check._defaultFormat, day._defaultFormat);
              assert.equal(day.format(), check.format());
  		}
  	});
  
  	it('can return a list of date time per hour between 2015-04-30 20:40:32.332 and 2015-05-01 17:05:10.223', function () {
  		var format = 'Y/m/d H:M:S.N';
  		var start = datetime.create('2015-04-30 20:40:32.332', format);
  		var end = datetime.create('2015-05-01 17:05:10.223', format);
  		var list = start.getHoursInRange(end);
  		for (var i = 0, len = list.length; i < len; i++) {
  			var hour = list[i];
  			var check = datetime.create(start.getTime(), format);
  			check.offsetInHours(i);
  			assert.equal(hour.format(), check.format());
  		}
  	});
  
  	it('can return a list of date time per hour between 2015-05-01 17:05:10.223 and 2015-04-30 20:40:32.332', function () {
  		var format = 'Y/m/d H:M:S.N';
  		var start = datetime.create('2015-05-01 17:05:10.223', format);
  		var end = datetime.create('2015-04-30 20:40:32.332', format);
  		var list = start.getHoursInRange(end).reverse();
          var offset = (list.length - 1) * -1;
          for (var i = 0, len = list.length; i < len; i++) {
  			var hour = list[i];
  			var check = datetime.create(start.getTime(), format);
  			check.offsetInHours(offset);
              offset += 1;
  			assert.equal(hour.format(), check.format());
  		}
  	});
  
  	it('Can use default format', function () {
  		var dateStr = '2015-04-30 11:59:59.999';
  		var dt = datetime.create(dateStr, 'Y-m-d H:M:S.N');
  		assert.equal(dateStr, dt.format());
  	});
  
  	 it('Can create an increment type timed data', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
          });
  
          it('Can not create an increment type timed data w/ invalid init', function () {
                  var conf = {
                          init: '10',
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an increment type timed data w/ invalid max', function () {
                  var conf = {
                          init: 10,
                          max: 0,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
  	 it('Can not create an increment type timed data w/ invalid min', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: -1,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an increment type timed data w/ invalid interval', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: [1, 2, 3],
                          step: 1,
                          type: 'inc'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an increment type timed data w/ invalid step', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 100,
                          type: 'inc'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an increment type timed data w/ invalid type', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'foo'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
  	 it('Can create an increment type timed data and decrement', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
          });
  
          it('Can create an increment type timed data and cannot decrement beyond min', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(100);
  
                  assert.equal(success, false);
                  assert.equal(timedData.getValue(), 10);
          });
  
          it('Can create an increment type timed data and decrement and recover by 1 after 10 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 6);
                          done();
                  }, 10);
          });
  
  	 it('Can create an increment type timed data and decrement and recover by 5 after 50 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 10);
                          done();
                  }, 50);
          });
  
          it('Can create an increment type timed data and decrement and cannot recover beyond max after 60 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'inc'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 10);
                          done();
                  }, 60);
          });
  
          it('Can create an decrement type timed data', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
          });
  
  	 it('Can not create an decrement type timed data w/ invalid init', function () {
                  var conf = {
                          init: '10',
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an deccrement type timed data w/ invalid max', function () {
                  var conf = {
                          init: 10,
                          max: 0,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an increment type timed data w/ invalid min', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: -1,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an decrement type timed data w/ invalid interval', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: [1, 2, 3],
                          step: 1,
                          type: 'dec'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
  	 it('Can not create an decrement type timed data w/ invalid step', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 100,
                          type: 'dec'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can not create an decrement type timed data w/ invalid type', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'foo'
                  };
                  try {
                          datetime.createTimedNumber(conf);
                  } catch (e) {
                          assert(e);
                  }
          });
  
          it('Can create an decrement type timed data and increment', function () {
                  var conf = {
                          init: 9,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 9);
  
                  var success = timedData.inc(1);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 10);
          });
  
          it('Can create an decrement type timed data and cannot increment beyond max', function () {
                  var conf = {
                          init: 9,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 9);
  
                  var success = timedData.inc(100);
  
                  assert.equal(success, false);
                  assert.equal(timedData.getValue(), 9);
          });
  
  	it('Can create an decrement type timed data by 1 after 10 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 9);
                          done();
                  }, 10);
          });
  
          it('Can create an decrement type timed data and decrement and derecements by 5 after 50 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 0);
                          done();
                  }, 50);
          });
  
          it('Can create an decrement type timed data and decrement and cannot decrement beyond min after 60 milliseconds', function (done) {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 10,
                          step: 1,
                          type: 'dec'
                  };
                  var timedData = datetime.createTimedNumber(conf);
                  var value = timedData.getValue();
  
                  assert.equal(value, 10);
  
                  var success = timedData.dec(5);
  
                  assert.equal(success, true);
                  assert.equal(timedData.getValue(), 5);
  
                  setTimeout(function () {
                          assert.equal(timedData.getValue(), 0);
                          done();
                  }, 60);
          });
  
  	it('Can reconstruct timed number with exactly the same sate', function () {
                  var conf = {
                          init: 10,
                          max: 10,
                          min: 0,
                          interval: 1000,
                          step: 1,
                          type: 'inc'
                  };
  		var tn1 = datetime.createTimedNumber(conf);
  		tn1.dec(1);
  		var tn1Source = tn1.toObject();
  		var tn2 = datetime.createTimedNumber(tn1Source);
  		var tn2Source = tn2.toObject();
  		for (var i in tn2Source) {
  			assert.equal(tn1Source[i], tn2Source[i]);
  		}
  	});
  
  	it('Can use "global" offset in days and "global format"', function () {
  		datetime.setOffsetInDays(dayOffset);
  		datetime.setDefaultFormat('Y-m-d H:M:S.N');
  		var dt1 = datetime.create(time);
  		var dt2 = datetime.create(time);
  		assert.equal(dt1.format(), dt2.format());
  		assert.equal(dt1.format(), future);
  		assert.equal(dt2.format(), future);
  	});
  
  	it('Can create a new instance of TimedState object', function () {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 100,
  			loop: false
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  	});
  
  	it('Moves forward by 2 states after 200 milliseconds w/ itnerval 100 miliseconds configuration', function (done) {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 100,
  			loop: false
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		setTimeout(function () {
  			var state = ts.getState();
  			assert.equal('c', state);
  			done();
  		}, 200);
  	});
  
  	it('Stays at the last state after 500 milliseconds w/ itnerval 100 miliseconds configuration', function (done) {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 100,
  			loop: false
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		setTimeout(function () {
  			var state = ts.getState();
  			assert.equal('d', state);
  			done();
  		}, 500);
  	});
  
  	it('Loops back to 1st state after 400 milliseconds w/ itnerval 100 miliseconds configuration', function (done) {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 100,
  			loop: true
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		setTimeout(function () {
  			var state = ts.getState();
  			assert.equal('a', state);
  			done();
  		}, 400);
  	});
  
  	it('Loops to 2nd state after 500 milliseconds w/ itnerval 100 miliseconds configuration', function (done) {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 100,
  			loop: true
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		setTimeout(function () {
  			var state = ts.getState();
  			assert.equal('b', state);
  			done();
  		}, 500);
  	});
  
  	it('Can move the state forward with .forward()', function () {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 10000,
  			loop: false
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		ts.forward();
  		assert.equal('b', ts.getState());
  	});
  
  	it('Can move the state backward with .backward()', function () {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 1,
  			interval: 10000,
  			loop: false
  		};
  		var ts = datetime.createTimedState(conf);
  		assert(ts);
  		ts.backward();
  		assert.equal('a', ts.getState());
  	});
  
  	it('Can reconstruct the same state w/ .toObject()', function () {
  		var conf = {
  			states: [
  				'a',
  				'b',
  				'c',
  				'd'
  			],
  			init: 0,
  			interval: 10000,
  			loop: false
  		};
  		var ts1 = datetime.createTimedState(conf);
  		ts1.forward();
  		var obj1 = ts1.toObject();
  		var ts2 = datetime.createTimedState(obj1);
  		var obj2 = ts2.toObject();
  		assert.equal(JSON.stringify(obj1), JSON.stringify(obj2));
  	});
  });
  