2

So I am trying to sort an array so that the first item would be the same as the current day and month or the closest entry.

My array looks like this:

[
    [
       "Firstname Lastname",
        "1979-01-03",
        "40"
    ],
    [
        "Firstname Lastname",
        "1996-01-23",
        "23"
    ],
    [
        "Firstname Lastname",
        "1977-01-28",
        "41"
    ],
    [
        "Firstname Lastname",
        "1983-03-11",
        "35"
    ],
    [
       "Firstname Lastname",
       "1977-03-30",
        "41"
    ],
    [
       "Firstname Lastname",
        "1975-05-08",
        "43"
    ]
]

I did figure out how to sort the array based on the day of the month but then it ignores the month itself

relativeYearDay(date) {
    let differenceDay = new Date(date).getDate() - new Date().getDate();

     if (differenceDay < 0) {
         differenceDay += 365;
     }

     return differenceDay;
}

getUpcomingBirthdays() {
     return this.birthdays.slice(0).sort((a, b) => {
         return this.relativeYearDay(a[1]) - this.relativeYearDay(b[1]);
    });
},

Like I mentioned this returns a sorted array based on the day of the month.

How would I do it for both day and month?

6
  • So you're trying to sort the array by date, ignoring year? If your format was consistent, just chop off the first 5 characters of the string ("yyyy-") and sort by what's left. Commented Jan 23, 2019 at 16:25
  • 1
    Transform the date to timestamp and sort it using that. Commented Jan 23, 2019 at 16:25
  • 'Math.round(new Date("2013/09/05 15:34:00").getTime()/1000)' Commented Jan 23, 2019 at 16:26
  • Does "closest entry" look backwards? IE, would January 22nd be the closest, or furthest, value from January 23rd? Commented Jan 23, 2019 at 16:33
  • 1
    @TylerRoper It will if you use a fixed year at the time of the new Date object creation... Commented Jan 23, 2019 at 16:40

4 Answers 4

1

Actually, since you want to sort by next birthdays, you can set the current year to all the dates when comparing to the current date. When the difference between they is negative (i.e birthday already occurs), you can add an offset of 1 year from now.

const birthdays = [
    ["Firstname Lastname", "1979-01-03", "40"],
    ["Firstname Lastname", "1996-01-23", "23"],
    ["Firstname Lastname", "1977-01-28", "41"],
    ["Firstname Lastname", "1983-03-11", "35"],
    ["Firstname Lastname", "1977-03-30", "41"],
    ["Firstname Lastname", "1975-05-08", "43"]
];

function distanceToBirthday(date)
{
    let currDate = new Date();
    currDate.setHours(0, 0, 0, 0);
    let currYear = currDate.getFullYear();

    let offset = new Date();
    offset.setHours(0, 0, 0, 0);
    offset.setFullYear(currYear + 1);

    date = new Date(date + " 00:00");
    date.setFullYear(currYear);

    let diff = date - currDate;
    return (diff < 0) ? diff + offset.getTime() : diff;
}

function getUpcomingBirthdays(bdays)
{
    return bdays.slice(0).sort(
        (a, b) => distanceToBirthday(a[1]) - distanceToBirthday(b[1])
    );
}

console.log(getUpcomingBirthdays(birthdays));

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! This and @michael-lynch answer are nearly the same! This makes sense and works like a charm.
1

Your original answer was very close. When sorting you just need to figure out the date of the users NEXT upcoming birthday.

const birthdays = [
    [ "Firstname Lastname", "1979-01-03", "40" ],
    [ "Firstname Lastname", "1996-01-23", "23" ],
    [ "Firstname Lastname", "1977-01-28", "41" ],
    [ "Firstname Lastname", "1983-03-11", "35" ],
    [ "Firstname Lastname", "1977-03-30", "41" ],
    [ "Firstname Lastname", "1975-05-08", "43" ]
];


function getNextBirthday(date) {
    // Current Date
    let currentDate = new Date();

    // Set the users birthday to this year (originally from thier birth year)
    let birthday = new Date(date);
    birthday.setFullYear(currentDate.getFullYear());

    // If the birthday has already occured this year.  Then thier next birthday is next year.
    if (birthday - currentDate < 0) {
        birthday.setFullYear(currentDate.getFullYear() + 1);
    }

    // Return the users next birthday as a date.
    return birthday;
}

function getUpcomingBirthdays() {
     return birthdays.slice(0).sort((a, b) => {
         return getNextBirthday(a[1]) - getNextBirthday(b[1]);
    });
}

Edit: Added comments & fix small bug in code.

Comments

0

I misread the question and thought you wanted just the nearest to the current date.

In simple coding... and may give you some ideas to turn it into a sorting routine

const data = [
    [
       "Firstname Lastname",
        "1979-01-03",
        "40"
    ],
    [
        "Firstname Lastname",
        "1996-01-23",
        "23"
    ],
    [
        "Firstname Lastname",
        "1977-01-28",
        "41"
    ],
    [
        "Firstname Lastname",
        "1983-03-11",
        "35"
    ],
    [
       "Firstname Lastname",
       "1977-03-30",
        "41"
    ],
    [
       "Firstname Lastname",
        "1975-05-08",
        "43"
    ]
];
const now = new Date().getTime();
let nearestIndex = -1;
let nearest = 0;

data.forEach( (item, index) => {
  if(nearest ==0 || now-new Date(item[1]).getTime() < nearest) {
    nearest = now-new Date(item[1]).getTime();
    nearestIndex = index;
  }  
});

console.log(`Nearest date is at index ${nearestIndex}`, data[nearestIndex], nearest, nearestIndex);

Comments

0

You could sort the array by an sorting algorithm with sections, where you take a date as separator and move smaller values to the end of the array, and sort all other by date.

This approach uses the a part string, because ISO 8601 dates are sortable by string.

var array = [["Firstname Lastname", "1979-01-03", "40"], ["Firstname Lastname", "1996-01-23", "23"], ["Firstname Lastname", "1977-01-28", "41"], ["Firstname Lastname", "1983-03-11", "35"], [ "Firstname Lastname","1977-03-30", "41"], [ "Firstname Lastname", "1975-05-08", "43"]],
    day = (new Date).toISOString().slice(5, 10)

array.sort(({ 1: a }, { 1: b }) =>
    (a.slice(5) < day) - (b.slice(5) < day) || a.slice(5).localeCompare(b.slice(5)));

console.log(array.map(a => a.join(' | ')));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.