Wednesday, July 30, 2008

Calculating the nth Date in Flash

One thing that's not easy to calculate in Flash is the occurrence of floating dates. For example, in the US, Thanksgiving Day occurs on the fourth Thursday of November whereas, in Canada, it occurs on the second Monday of October. But how do you calculate which is the fourth Thursday or the second Monday in any given month?

The answer is this function:

function nthDay(nth, weekday, month, year) {
var lookup:Object = {first:1, second:2, third:3, fourth:4, fifth:5, last:0, firstlast:-1, secondlast:-2, thirdlast:-3, fourthlast:-4, fifthlast:-5, penultimate:-1, antepenultimate:-2, preantepenultimate:-3, sun:0, mon:1, tue:2, wed:3, thu:4, fri:5, sat:6, sunday:0, monday:1, tuesday:2, wednesday:3, thursday:4, friday:5, saturday:6, jan:0, feb:1, mar:2, apr:3, may:4, jun:5, jul:6, aug:7, sep:8, oct:9, nov:10, dec:11, january:0, february:1, march:2, april:3, may:4, june:5, july:6, august:7, september:8, october:9, november:10, december:11};
for (i in lookup) {
if (nth.toLowerCase() == i) {
nth = lookup[i];
}
if (weekday.toLowerCase() == i) {
weekday = lookup[i];
}
if (month.toLowerCase() == i) {
month = lookup[i];
}
}
var nthDate:Date = new Date(year, month + ((nth <= 0) ? 1 : 0), 1);
var dayofweek:Number = nthDate.getDay();
var offset:Number = weekday - dayofweek;
nthDate = new Date(year, month + ((nth <= 0) ? 1 : 0), nthDate.getDate() + (offset + (nth - (offset >= 0 ? 1 : 0)) * 7));
if (nthDate.getMonth() <> month) {
return "**ERROR ** nthDay (" + nth + ") Out of range";
} else {
return nthDate;
}
}

The function accepts four arguments:
  • nth - an integer that represents which nth day occurrence to search for, e.g. 1, 2, 3, 4, 5
    n.b. A zero value will return the date of the last weekday.
    n.b. A negative value will return the nth day counting back from the end of the month.
  • weekday - day of the week to search for (Sunday = 0, Monday = 1, etc.)
  • month - month to search in (January = 0, February = 1, etc.)
  • year - year to search in (1995, 2008, etc.)
The function returns a new Date Object (nthDate) containing the nth occurrence unless there's an error, in which case it will return an error message.

So, to calculate Thanksgiving Day, you would use:

trace("US Thanksgiving Day = " + nthDay(4, 4, 10, 2008));
// outputs Thu Nov 27 00:00:00 GMT+0000 2008
trace("Canada Thanksgiving Day = " + nthDay(2, 1, 9, 2008));
// outputs Mon Oct 13 00:00:00 GMT+0000 2008


The function can be used to calculate any possible occurrence. For example, you can use it to work out the last Tuesday in a month with nthDay(0, 2, 10, 2008).
You can use it to count backwards from the end of the month so, to find the last but one Tuesday in a month, you would use nthDay(-1, 2, 10, 2008);

You can also combine the function with existing date objects:

today = new Date();
nthDay(0, 6, today.getMonth(), today.getFullYear()));
// will trace the last Saturday of the current month
trace("= " + nthDay(2, today.getDay(), today.getMonth() + 2, today.getFullYear()));
// will trace the second occurrence of this weekday in two months time


Last, but by no means least, the function lets you replace all those ugly numbers with user-friendly string references such as "first", "second", "last", "nov", "tues", "penultimate", etc.

Instead of writing nthDay(-2, 2, 10, 2008) you can use:
nthDay("secondlast", "tue", "oct", 2008) or
nThDay("antepenultimate", "tuesday", "October", 2008)

Thanksgiving Day in the US would then be written thus:
nthDay("fourth", "thursday", "november", 2008)
while the equivalent holiday in Canada would be:
nthDay("second", "mon", "oct", 2008)

No comments: