﻿        //needed for dy & wk
        Array.prototype.sum = function () { var c = 0; for(var i=0;i<this.length;i++) c+=parseFloat(this[i]); return c; }
        Date.prototype.daysinmonth = $w("31 28 31 30 31 30 31 31 30 31 30 31");      

        //if you need other languages then update the prototype dynamically
        Date.prototype.suffixes = $w("th st nd rd");
        Date.prototype.months = $w("January Feburary March April May June July August September October November December");
        Date.prototype.days = $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday");
     
        //Core formatting functions
        Date.prototype.intervals = {
            'yy': function () { return this.getFullYear().toString().substring(2,4) },
            'yyyy': function () { return this.getFullYear(); },
            'qq': function () { return Math.floor(this.getMonth() / 3) + 1},
            'm': function () { return this.getMonth() },
            'mm': function () { return this.getMonth().toPaddedString(2) },
            'M': function () { return this.months[this.getMonth()]; },
            'MMM': function () { return this.months[this.getMonth()].substring(0,3); },
            'dy': function () { return this.daysinmonth.slice(0,this.getMonth()+1).sum(); },
            'y': function () { return this.intervals['dy'].bind(this)();},
            'dd': function () { return this.getDate().toPaddedString(2) },
            'd': function () { return this.getDate(); },
            'D': function () { return this.days[this.getDay()]; },
            'DDD': function () { return this.days[this.getDay()].substring(0,3); },
            'wk': function () { return parseInt(Math.ceil(this.intervals['dy'].bind(this)() / 7)); },
            'wd': function () { return this.getDay() },
            'ww': function () { return this.intervals['wk'].bind(this)(); },
            'h': function () { return this.getHours(); },
            'hh': function () { return this.getHours().toPaddedString(2); },
            'mi': function () { return this.getMinutes().toPaddedString(2); },
            'n': function () { return this.intervals['mi'].bind(this)(); },
            'ss': function () { return this.getSeconds().toPaddedString(2); },
            's': function () { return this.getSeconds(); },
            'ms': function () { return this.getMilliseconds(); },
            'S': function () {  var s = this.getDay().toString(); var n = parseInt(s.substring(s.length-1,s.length)); return ($R(1,3).include(n)?this.suffixes[n]:this.suffixes[0]); }
        }   
        //Actually actions a format
        Date.prototype.toFormattedString = function (fmt) { return fmt.gsub(/([y]{4}|[y]{2}|dy|mi|[mdhsqn]{1,2}|[D]{3}|D|[M]{3}|M|ms|S|[w]{2}|wk)/, function(match) { return this.intervals[match[0]].bind(this)(); }.bind(this)); }    
        //a wrapper for most commonly used format
        Date.prototype.toISO8601 = function () { return this.toFormattedString("yyyy-mm-ddThh:n:ss"); }
        //convert a ISO8601 string to a date
        String.prototype.dateFromDMY = function() { var ts = this.strip().match("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})").slice(1); return new Date(ts[2], parseFloat(ts[1]) - 1, ts[0], 0, 0, 0); }
        String.prototype.dateFromISO8601 = function () { var ts = this.strip().match("([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})").slice(1); return new Date(ts[0],ts[1],ts[2],ts[3],ts[4],ts[5]); }
        //convert a dd/mm/yyyy, mm/dd/yyyy, yy/dd/mm etc string to a date
        String.prototype.dateFromFormat = function (fmt,sep) { var fa = fmt.split(sep); var da = this.split(sep); return new Date(da[fa.indexOf("yyyy")], da[fa.indexOf("mm")]-1, da[fa.indexOf("dd")]); }


        Date.prototype.dateDiff = function(datepart, v_date) {
            var orgDate = this;
            var newDate = v_date;
            var millisecondsBtwDates = Math.abs(newDate - orgDate);
            var secondsBtwDates = Math.floor(millisecondsBtwDates / 1000);
            var minutesBtwDates = Math.floor(secondsBtwDates / 60);
            var hoursBtwDates = Math.floor(minutesBtwDates / 60);
            var daysBtwDates = Math.floor(hoursBtwDates / 24);
            var yearsBtwDates = Math.floor(daysBtwDates / 365);
            var monthsBtwDates = Math.floor(daysBtwDates / 365 * 12);
            var returnVar = (datepart == "y") ? yearsBtwDates : (datepart == "m") ? monthsBtwDates : (datepart == "d") ? daysBtwDates : (datepart == "h") ? hoursBtwDates : (datepart == "n") ? minutesBtwDates : (datepart == "s") ? secondsBtwDates : millisecondsBtwDates;
            return returnVar;
        };
Date.prototype.dateAdd = function(datepart, v_number) {
	switch (datepart) {
	case "y" :
		this.setFullYear(this.getFullYear()+v_number);
		break;
	case "m" :
		this.setMonth(this.getMonth()+v_number);
		break;
	case "d" :
		this.setDate(this.getDate()+v_number);
		break;
	case "h" :
		this.setHours(this.getHours()+v_number);
		break;
	case "n" :
		this.setMinutes(this.getMinutes()+v_number);
		break;
	case "s" :
		this.setSeconds(this.getSeconds()+v_number);
		break;
	default :
		this.setMilliseconds(this.getMilliseconds()+v_number);
		break;
	}
	return this;
};
Date.prototype.dateDiffString = function(v_date, includeYears, includeSeconds) {
    var startDate = this.clone();
    var endDate = v_date;
    if (includeYears) {
        var DiffYear = startDate.dateDiff("y", endDate);
        startDate = startDate.dateAdd("y", DiffYear);
    }
    var DiffMonth = startDate.dateDiff("m", endDate);
    startDate = startDate.dateAdd("m", DiffMonth);
    var DiffDay = startDate.dateDiff("d", endDate);
    startDate = startDate.dateAdd("d", DiffDay);
    var DiffHour = startDate.dateDiff("h", endDate);
    startDate = startDate.dateAdd("h", DiffHour);
    var DiffMinute = startDate.dateDiff("n", endDate);
    startDate = startDate.dateAdd("n", DiffMinute);
    if (includeSeconds) {
        var DiffSecond = startDate.dateDiff("s", endDate);
        startDate = startDate.dateAdd("n", DiffSecond);
    }
    var diffString = (includeYears ? (DiffYear + " year" + (DiffYear != 1 ? "s" : "") + ", ") : "") + DiffMonth + " month" + (DiffMonth != 1 ? "s" : "") + ", " + DiffDay + " day" + (DiffDay != 1 ? "s" : "") + ", " + DiffHour + " hour" + (DiffHour != 1 ? "s" : "") + ", " + DiffMinute + " minute" + (DiffMinute != 1 ? "s" : "") + (includeSeconds ? (", " + DiffSecond + " second" + (DiffSecond != 1 ? "s" : "")) : "");
    return diffString;
};