I’ll leave the code for now in a snippet. I’ll post updates and examples, and add new features soon.
"use strict";
/*jslint white: true, browser: true, onevar: true, undef: true, eqeqeq: true,
plusplus: true, bitwise: true, strict: true, newcap: true, immed: true,
maxlen: 200 */
/*global window: true */
/**
* Timer.js
* http://rolandog.com
*
* License: Creative Commons Attribution-Share Alike 3.0 Unported.
* http://creativecommons.org/licenses/by-sa/3.0/
*
* @projectDescription Performs calculations on how much time has passed.
* @author Rolando Garza rolandog@gmail.com
*/
/**
* A constructor that takes a date and returns a Timer object
* with several calculations. You can enter a string, or number by number or
* even use it as a counter by calling it as new Timer().
* @param(String) YYYY A String formatted like YYYY/MM/DD HH:MM:SS.ms
*/
var Timer = function Timer(YYYY, MM, DD, hh, mm, ss, ms) {
//rounds a date: from 2009/08/21 14:42.123 you'll get 2009/08/21
function round(d) {
return new Date("" + d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate());
}
function properties(d) {
return {
Y: d.getFullYear(),
M: d.getMonth(),
D: d.getDate(),
h: d.getHours(),
m: d.getMinutes(),
s: d.getSeconds(),
ms: d.getMilliseconds(),
t: d.getTime(),
d: d
};
}
this.exactly = {};
this.rounded = {};
//variable declarations
var start, date, Counter, ww;
//start is the moment the event started (from the date string)
if (typeof(YYYY) === "string") {
//in case there was a decimal place
start = YYYY.split(".");
ms = start[1] ? +("0." + start[1]) * 1000 : undefined;
YYYY = start[0];
start = new Date(YYYY);
if (ms) {
start.setMilliseconds(ms);
}
} else {
//in case a variable is undefined
MM = MM ? MM : "01";
DD = DD ? DD : "01";
hh = hh ? hh : "00";
mm = mm ? mm : "00";
ss = ss ? ss : "00";
//firefox doesn't recognize 2009-6-6 but does recognize 2009/6/6. Weird.
date = [YYYY, MM, DD].join("/") + " " + [hh, mm, ss].join(":");
start = YYYY ? new Date(date) : new Date(); //starts a counter if YYYY is undefined
if (ms) {
start.setMilliseconds(ms);
}
}
this.p = properties(start);
//the infamous Counter class.
Counter = function Counter(rounded, conversions) {
function update() {
var now, today, a, b, dt, pl = 100;
now = new Date();
today = round(now);
a = now > start ? start : now;
b = now > start ? now : start;
a = properties(rounded ? round(a) : a);
b = properties(rounded ? round(b) : b);
dt = b.d - a.d;
if (conversions) {
if (rounded) {
pl = 1;
}
ms = parseInt(pl * dt, 10) / pl;
ss = parseInt(pl * (dt /= 1000), 10) / pl;
mm = parseInt(pl * (dt /= 60), 10) / pl;
hh = parseInt(pl * (dt /= 60), 10) / pl;
DD = parseInt(pl * (dt /= 24), 10) / pl;
ww = parseInt(pl * DD / 7, 10) / pl;
MM = parseInt(pl * (dt /= (365.25 / 12)), 10) / pl;
YYYY = parseInt(pl * (dt /= 12), 10) / pl;
} else {
YYYY = b.Y - a.Y;
MM = b.M - a.M;
DD = b.D - a.D;
hh = b.h - a.h;
mm = b.m - a.m;
ss = b.s - a.s;
ms = b.ms - a.ms;
if (ms < 0) {
ss -= 1;
ms += 1000;
}
if (ss < 0) {
mm -= 1;
ss += 60;
}
if (mm < 0) {
hh -= 1;
mm += 60;
}
if (hh < 0) {
DD -= 1;
hh += 24;
}
if (DD < 0) {
MM -= 1;
DD += 30;
}
if (MM < 0) {
YYYY -= 1;
MM += 12;
}
ww = (YYYY * 365.25 / 7) + (MM * 365.25 / 7 / 12) + (DD / 7);
ww = parseInt(ww, 10);
}
return {
years : YYYY,
months : MM,
days : DD,
hours : hh,
minutes : mm,
seconds : ss,
milliseconds : ms,
weeks : ww
};
}
this.__defineGetter__("years", function years() {
return update().years;
});
this.__defineGetter__("months", function months() {
return update().months;
});
this.__defineGetter__("days", function days() {
return update().days;
});
this.__defineGetter__("hours", function hours() {
return update().hours;
});
this.__defineGetter__("minutes", function minutes() {
return update().minutes;
});
this.__defineGetter__("seconds", function seconds() {
return update().seconds;
});
this.__defineGetter__("milliseconds", function milliseconds() {
return update().milliseconds;
});
this.__defineGetter__("weeks", function weeks() {
return update().weeks;
});
this.__defineGetter__("status", function status() {
var i, r = [], u;
u = "years months days weeks hours minutes seconds milliseconds".split(" ");
for (i in u) {
if (this.hasOwnProperty(u[i]) && this[u[i]]) {
if (u[i] === "weeks") {
r.push("(" + this[u[i]] + " " + u[i] + ")");
} else {
r.push(this[u[i]] + " " + u[i]);
}
}
}
return r.join(",\n");
});
this.fireworks = function fireworks() {
var s = this.status;
s = s.replace(/\n/g, " ");
s = s.replace(/ /g, "%20");
s = s.replace(/,%20\(.+/g, "");
//Thanks Kenneth Kufluk
//return "http://js-fireworks.appspot.com/?msg=" + s; //for debugging
window.location.href = "http://js-fireworks.appspot.com/?msg=" + s;
};
};
this.exactly.howMany = new Counter(0);
this.exactly.conversions = new Counter(0, 1);
this.rounded.howMany = new Counter(1);
this.rounded.conversions = new Counter(1, 1);
};
/* Usage:
* Every Timer has three sub-objects: 'p', 'exactly' and 'rounded'
* the 'p' object has the following properties:
* Y, M, D, h, m, s, ms, d, t
* The last two are for the original date object and it's time-equivalent.
* Y is short-hand for yourTimer.d.getFullYear(); the rest is self-explanatory.
*
* 'exactly' and 'rounded' are objects with the following properties:
* years, months, days, weeks, hours, minutes, seconds, milliseconds, status
* 'status' displays a pre-formatted status message.
*/
/* Example with comments:
var asd, jkl, qwe, uio;
asd = new Timer(); //starts counting from 'now'.
jkl = new Timer("2010/2/8 13:56:11.9966"); //moment I finished this file
jkl.exactly.howMany.status //2 days, 21 hours, 37 minutes, ...
jkl.exactly.conversions.status; //0.09 months, 2.9 days, (0.41 weeks), ...
jkl.rounded.howMany.status; //3 days
jkl.rounded.conversions.status; //3 days, 72 hours, 4320 minutes, ...
uio = new Timer(2012, 12, 12, 12, 12, 12, 12); //end of the world!
uio.rounded.howMany.fireworks(); //takes you to some very nice fireworks
*/
You’re welcome.