I would be tempted to establish the original year of the event, and then add enough whole years to it to ensure that the value is greater than your reference date (normally today's date). Or, possibly, greater than or equal to the reference date. You can then sort in simple date order.
Edited to add:
I'm not fluent enough in PHP to give an answer in that, but here's a Perl solution.
#!/bin/perl -w
# Sort sequence of dates by next occurrence of anniversary.
# Today's "birthdays" count as low (will appear first in sequence)
use strict;
my $refdate = "2008-10-05";
my @list = (
"1980-04-14", "2007-06-08",
"2008-12-25", "1978-11-03",
"2008-10-04", "2008-10-05",
"2008-10-06", "2008-02-29"
);
sub date_on_or_after
{
my($actdate, $refdate) = @_;
my($answer) = $actdate;
if ($actdate lt $refdate) # String compare OK with ISO8601 format
{
my($act_yy, $act_mm, $act_dd) = split /-/, $actdate;
my($ref_yy, $ref_mm, $ref_dd) = split /-/, $refdate;
$ref_yy++ if ($act_mm < $ref_mm || ($act_mm == $ref_mm && $act_dd < $ref_dd));
$answer = "$ref_yy-$act_mm-$act_dd";
}
return $answer;
}
sub anniversary_compare
{
my $r1 = date_on_or_after($a, $refdate);
my $r2 = date_on_or_after($b, $refdate);
return $r1 cmp $r2;
}
my @result = sort anniversary_compare @list;
print "Before:\n";
print "* $_\n" foreach (@list);
print "Reference date: $refdate\n";
print "After:\n";
print "* $_\n" foreach (@result);
Clearly, this is not dreadfully efficient - to make it efficient, you'd calculate the date_on_or_after() value once, and then sort on those values. Perl's comparison is slightly peculiar - the variables $a and $b are magic, and appear as if out of nowhere.
When run, the script produces:
Before:
* 1980-04-14
* 2007-06-08
* 2008-12-25
* 1978-11-03
* 2008-10-04
* 2008-10-05
* 2008-10-06
* 2008-02-29
Reference date: 2008-10-05
After:
* 2008-10-05
* 2008-10-06
* 1978-11-03
* 2008-12-25
* 2008-02-29
* 1980-04-14
* 2007-06-08
* 2008-10-04
Note that it largely ducks the issue of what happens with the 29th of February, because it 'works' to do so. Basically, it will generate the 'date' 2009-02-29, which compares correctly in sequence. The anniversary for 2000-02-28 would be listed before the anniversary for 2008-02-29 (if 2000-02-28 were included in the data).