JavaScript Data Structures - A TimeInterval Object
Written by Ian Elliot   
Thursday, 16 April 2020
Article Index
JavaScript Data Structures - A TimeInterval Object
Methods and overriding
Extending Date

Some methods

Now we have a correctly initialized TimeInterval object, aka an augmented Date object, it is time to actually augment it with some new methods.

The first thing we probably want to do is add and subtract TimeIntervals. This is easy, because all we have to do is add or subtract the number of milliseconds stored in a pair of Date objects. For example:

obj.add=function(t){
this.setTime(this.getTime()+t.getTime());
}

You can see that this simply gets the milliseconds from each object and adds - but how can you be sure that t is another TimeInterval object?

At this point you are probably thinking that we need to specify the object's type or something similar. This is again a left over from the way you think about a typed class based language. In the case of JavaScript you don't need to worry about type. If an object has the method you are trying to use then use it - if not don't use it. So a method that checks for the reasonableness of the t parameter is:

obj.add=function(t){
if (t.getTime) {
this.setTime(this.getTime()+t.getTime())
};
}

and a subtract function is simply:

obj.subtract=function(t){
if (t.getTime) {
this.setTime(this.getTime()-t.getTime())
};
}

Notice that this allows you to use a Date object in place of a TimeInterval object and this is just the consequence of TimeInterval being an augmented Date object.

Of course at this point you could argue that this is a dangerous way to work because if an arbitrary object has a getTime method then who is to say it makes any sense in this context? This is of course the responsibility  of the programmer.

Now that we have the basic outline of the way these additional methods work let's add one more - a test for equality:

obj.equals=function(t)
{
if (t.getTime) {
return this.getTime()===t.getTime();
};
return false;
}

This is a true test of value equality. It only returns true if the two TimeInterval objects have the same time to the millisecond.

You can add similar methods to do things like compare to two intervals and so on.

Overriding methods

If you use the getDay Date function it returns the day of the week and this isn't really appropriate for a TimeInterval object. In this case it should really just return the total number of days in the interval. The solution is to replace the existing getDay function with a new one - this is JavaScript's equivalent of overriding methods. In this case the getDay method is just:

obj.getDay=function(){                
return Math.floor(this.getTime()/24/60/60/1000);
}

Now when you call getDay it is the redefined method belonging to TimeInterval you use.

You could also define a getTotalDay method which returned a day and fractional day number.

There is one other method that is good to replace. The toString method is called when ever a String representation of an object is required. Even though it is a built in function you can still replace it. See Objects with values for the details of toString and valueOf. In this case we need a reasonably formatted string showing the time interval in the form

d Day(s) h:m:s:mill

This is just a matter of string manipulation:

obj.toString=function(){
var days=this.getDay();
var temp="";
if(days!==0)temp=days+" Day(s) ";
temp=temp+this.getUTCHours()+
":"+this.getUTCMinutes()+
":"+this.getUTCSeconds()+
":"+this.getUTCMilliseconds();     
return temp;
}

Notice that the toString method is perfectly OK using the getDay method of the TimeInerval object.

The complete object factory is:

var TimeInterval = function(){
var d = 0, h = 0, m = 0, s = 0, mill = 0;

if (arguments.length === 1) {
mill = arguments[0].valueOf();
};
if (arguments.length === 3) {
h = arguments[0].valueOf();
m = arguments[1].valueOf();
s = arguments[2].valueOf();
}
if (arguments.length >= 4) {
d = arguments[0].valueOf();
h = arguments[1].valueOf();
m = arguments[2].valueOf();
s = arguments[3].valueOf();
}
if (arguments.length === 5) {
mill = arguments[4].valueOf();
}

var t = (((d*24+h)*60+m)*60+s)*1000+mill;
var obj = new Date(t);
obj.TimeInterval = true;

obj.add = function(t){
if (t.getTime) {
this.setTime(this.getTime()+t.getTime())
};
}

obj.subtract = function(t){
if (t.getTime) {
this.setTime(this.getTime() - t.getTime())
};
}

obj.equals = function(t){
if (t.getTime) {
return this.getTime() === t.getTime();
};
return false;
}

obj.getDay = function(){
return Math.floor(this.getTime()/24/60/60/1000);
}

obj.toString = function(){
var days = this.getDay();
var temp = "";
if (days !== 0)
temp = days + " Day(s) ";
temp = temp + this.getUTCHours() +
":" + this.getUTCMinutes() +
":" + this.getUTCSeconds() +
":" + this.getUTCMilliseconds();
return temp;
}
return obj;
}

<ASIN:1871962579>

<ASIN:1871962560>



Last Updated ( Saturday, 25 April 2020 )