Date.prototype.getTimestamp = function(){
    return Math.floor(this.getTime() / 1000);
};

Date.prototype.fromString = function (str, now) {
    var i, match, s, strTmp = '',
    parse = '';

    strTmp = str;
    strTmp = strTmp.replace(/\s{2,}|^\s|\s$/g, ' '); // unecessary spaces
    strTmp = strTmp.replace(/[\t\r\n]/g, ''); // unecessary chars
    if (strTmp == 'now') {
        return (new Date()).getTime() / 1000; // Return seconds, not milli-seconds
    } else if (!isNaN(parse = Date.parse(strTmp))) {
        return (parse / 1000);
    } else if (now) {
        now = new Date(now * 1000); // Accept PHP-style seconds
    } else {
        now = new Date();
    }

    strTmp = strTmp.toLowerCase();

    var __is = {
        day: {
            'sun': 0,
            'mon': 1,
            'tue': 2,
            'wed': 3,
            'thu': 4,
            'fri': 5,
            'sat': 6
        },
        mon: {
            'jan': 0,
            'feb': 1,
            'mar': 2,
            'apr': 3,
            'may': 4,
            'jun': 5,
            'jul': 6,
            'aug': 7,
            'sep': 8,
            'oct': 9,
            'nov': 10,
            'dec': 11
        }
    };

    var process = function (m) {
        var ago = (m[2] && m[2] == 'ago');
        var num = (num = m[0] == 'last' ? -1 : 1) * (ago ? -1 : 1);

        switch (m[0]) {
            case 'last':
            case 'next':
                switch (m[1].substring(0, 3)) {
                    case 'yea':
                        now.setFullYear(now.getFullYear() + num);
                        break;
                    case 'mon':
                        now.setMonth(now.getMonth() + num);
                        break;
                    case 'wee':
                        now.setDate(now.getDate() + (num * 7));
                        break;
                    case 'day':
                        now.setDate(now.getDate() + num);
                        break;
                    case 'hou':
                        now.setHours(now.getHours() + num);
                        break;
                    case 'min':
                        now.setMinutes(now.getMinutes() + num);
                        break;
                    case 'sec':
                        now.setSeconds(now.getSeconds() + num);
                        break;
                    default:
                        var day;
                        if (typeof(day = __is.day[m[1].substring(0, 3)]) != 'undefined') {
                            var diff = day - now.getDay();
                            if (diff == 0) {
                                diff = 7 * num;
                            } else if (diff > 0) {
                                if (m[0] == 'last') {
                                    diff -= 7;
                                }
                            } else {
                                if (m[0] == 'next') {
                                    diff += 7;
                                }
                            }
                            now.setDate(now.getDate() + diff);
                        }
                }
                break;

            default:
                if (/\d+/.test(m[0])) {
                    num *= parseInt(m[0], 10);

                    switch (m[1].substring(0, 3)) {
                        case 'yea':
                            now.setFullYear(now.getFullYear() + num);
                            break;
                        case 'mon':
                            now.setMonth(now.getMonth() + num);
                            break;
                        case 'wee':
                            now.setDate(now.getDate() + (num * 7));
                            break;
                        case 'day':
                            now.setDate(now.getDate() + num);
                            break;
                        case 'hou':
                            now.setHours(now.getHours() + num);
                            break;
                        case 'min':
                            now.setMinutes(now.getMinutes() + num);
                            break;
                        case 'sec':
                            now.setSeconds(now.getSeconds() + num);
                            break;
                    }
                } else {
                    return false;
                }
                break;
        }
        return true;
    };

    match = strTmp.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/);
    if (match != null) {
        if (!match[2]) {
            match[2] = '00:00:00';
        } else if (!match[3]) {
            match[2] += ':00';
        }

        s = match[1].split(/-/g);

        for (i in __is.mon) {
            if (__is.mon[i] == s[1] - 1) {
                s[1] = i;
            }
        }
        s[0] = parseInt(s[0], 10);

        s[0] = (s[0] >= 0 && s[0] <= 69) ? '20' + (s[0] < 10 ? '0' + s[0] : s[0] + '') : (s[0] >= 70 && s[0] <= 99) ? '19' + s[0] : s[0] + '';
        return parseInt(this.strtotime(s[2] + ' ' + s[1] + ' ' + s[0] + ' ' + match[2]) + (match[4] ? match[4] / 1000 : ''), 10);
    }

    var regex = '([+-]?\\d+\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)' + '|(last|next)\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))' + '(\\sago)?';

    match = strTmp.match(new RegExp(regex, 'gi')); // Brett: seems should be case insensitive per docs, so added 'i'
    if (match == null) {
        return false;
    }

    for (i = 0; i < match.length; i++) {
        if (!process(match[i].split(' '))) {
            return false;
        }
    }

    return now.getTime() / 1000;
};

Date.prototype.getFriendly = function(){
    textDate = '';

    date = new Date();
    large = date.getTimestamp();

    diff = large - this.getTimestamp();

    if(diff <= 1) return 'less than 1 second ago';
    if(diff < (60)) return diff + ' seconds ago';
    if(diff < (60*60)) {
        minutes = Math.round(diff / 60);
        return 'about ' + minutes + ' minute' + (minutes > 1 ? 's' : '') + ' ago';
    }
    if(diff < (60*60*16)) {
        hours = Math.round( diff / (60*60));
        return 'about ' + hours + ' hour' + (hours > 1 ? 's' : '') + ' ago';
    }

    // if(diff < (large - this.fromString('yesterday'))) return 'yesterday';
    if(diff < (60*60*24)) {
        hours = Math.round(diff/(60*60));
        return 'about ' + hours + ' hour' + (hours > 1 ? 's' : '') + ' ago';
    }
    if(diff < (60*60*24*6.5)) textDate = Math.round(diff/(60*60*24)) + ' days ago';

    if(diff < (large - this.fromString('last week'))) return 'last week';
    if(Math.round(diff/(60*60*24*7))  == 1) return 'about a week ago';
    if(diff < (60*60*24*7*3.5)) textDate = Math.round(diff/(60*60*24*7)) + ' weeks ago';
    if(diff < (large - this.fromString('last month'))) return 'last month';
    if(Math.round(diff/(60*60*24*7*4))  == 1) return 'about a month ago';
    if(diff < (60*60*24*7*4*11.5)) return Math.round( diff / (60*60*24*7*4)) + ' months ago';
    if(diff < (large - this.fromString('last year'))) return 'last year';
    if(Math.round(diff / (60*60*24*7*52)) == 1) return 'about a year ago';
    if(diff >= (60*60*24*7*4*12)) return Math.round( diff / (60*60*24*7*52) ) + ' years ago';

    return textDate;
};

jQuery.fn.friendlyDate = function() {
$this = $(this);
    $this.each(function(){
        date = new Date($(this).html());
        dateValue = $(this).find('.fd-value').html();
        if(dateValue != null) date = new Date(dateValue);
        realDate = '<time style="display:none;" class="fd-value">'+date+'</time>';
        $(this).attr('title', date);
        $(this).html(date.getFriendly() + realDate);
    });
return $this;
}

// HACK : START : Add number formatting
$.fn.digits = function(){ 
    return this.each(function(){ 
        $(this).text( $(this).text().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") ); 
    })
}
