Attila
Attila

Reputation: 1177

Checking the order of dates in an object

I am trying to make sure the order of dates entered in an object are in a logical order. Here is my code:

function checkDates(pet) {
        const dates = [
            pet.birthDate,
            pet.saleDate,
            pet.acquisitionDate,
            pet.deathDate
        ].filter( (date) => {
            // filter out undefined items
            return date;
        });

        // list of dates in their chronological order
        const sortedDates = dates.slice(0).sort();

        const inOrder = dates.every( (date, i) => {
            // check to make sure entered date is the same as the chronological date
            return date === sortedDates[i];
        });

        if (!inOrder) {
            throw new ValidationError('The dates are in an illogical order');
        }
    }

The problem is that saleDate and acquisitionDate do not need to be in that order (as defined in the dates array) - they just need to be more than birthDate and less than deathDate. The different dates are not required, for example, the pet object that gets passed through my look like this:

const pet = {
  name: "Sam",
  birthDate: "2017-01-01",
  acquisitionDate: "2017-02-01",
  saleDate: "2017-03-01"
}

Further clarification: If present, birthDate must always come first, and deathDate must always come last. Sale and acquisition must be between birth and death date (if they are present), otherwise, it doesn't matter if sale comes before acquisition or vice-versa.

Upvotes: 0

Views: 833

Answers (4)

cнŝdk
cнŝdk

Reputation: 32145

You are saying that the order of both saleDate and acquisitionDate is not important they just need to be higher than birthDate and lower than deathDate, in that case you can simplify your function to do only these four checks:

function checkDates(pet) {
  var birthDate = new Date(pet.birthDate);
  var saleDate = new Date(pet.saleDate);
  var acquisitionDate = new Date(pet.acquisitionDate);
  var deathDate = pet.deathDate ? new Date(pet.deathDate) : Infinity;

  var inOrder = (birthDate < saleDate) && (birthDate < acquisitionDate) && (saleDate < deathDate) && (acquisitionDate < deathDate);

  if (!inOrder) {
    throw new ValidationError('The dates are in an illogical order');
  }
}

There's no need for using an array and for the sorting and the looping operations, it's really useless.

Demo:

function checkDates(pet) {
  var birthDate = new Date(pet.birthDate);
  var saleDate = new Date(pet.saleDate);
  var acquisitionDate = new Date(pet.acquisitionDate);
  var deathDate = pet.deathDate ? new Date(pet.deathDate) : Infinity;

  var inOrder = (birthDate < saleDate) && (birthDate < acquisitionDate) && (saleDate < deathDate) && (acquisitionDate < deathDate);

  if (!inOrder) {
    throw new ValidationError('The dates are in an illogical order');
  }
}
console.log(checkDates({
      name: "Sam",
      birthDate: "2018-01-01",
      acquisitionDate: "2017-02-01",
      saleDate: "2017-03-01"
    }));

Upvotes: 0

Brett DeWoody
Brett DeWoody

Reputation: 62851

Assuming the deathDate is the only optional property here, but it appears it could be done in two checks:

  • birthDate is less than the minimum of acquisitionDate/saleDate
  • if deathDate, deathDate is greater than the maximum of acquisitionDate/saleDate

Something along these lines:

function checkDates(pet) {
  const inOrder = (
    pet.birthDate < Math.min.apply(null, [pet.acquisitionDate, pet.saleDate]) &&
    pet.deathDate ? pet.deathDate > Math.max.apply(null, [pet.acquisitionDate, pet.saleDate]) : true
  );

  if (!inOrder) {
    throw new ValidationError('The dates are in an illogical order')
  }

  return true;
}


const pet = {
  birthDate: "2017-01-01",
  acquisitionDate: "2017-02-01",
  saleDate: "2017-03-01"
};

console.log(checkDates(pet));

If other properties are optional that would change things a bit but not too drastically.

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386680

You could just iterate the given array, without sorting, becaue all dates have to be in order.

function check({ birthDate, acquisitionDate, saleDate, deathDate }) {
    return [birthDate, acquisitionDate, saleDate, deathDate]
        .filter(Boolean)
        .every((a, i, aa) => !i || aa[i - 1] <= a);
}

console.log(check({ name: "Sam", birthDate: "2017-01-01", acquisitionDate: "2017-02-01", saleDate: "2017-03-01" }));
console.log(check({ name: "Sam", birthDate: "2018-01-01", acquisitionDate: "2017-02-01", saleDate: "2017-03-01" }));

Upvotes: 1

TimoStaudinger
TimoStaudinger

Reputation: 42480

You are on the right path, but sorting isn't necessarily required:

function checkDates(pet) {
    const dates = [
        pet.birthDate,
        pet.saleDate,
        pet.acquisitionDate,
        pet.deathDate
    ].filter(date => date);

    const inOrder =
        (pet.birthDate ? dates.every(date => date >= pet.birthDate) : true) &&
        (pet.deathDate ? dates.every(date => date <= pet.deathDate) : true)

    if (!inOrder) {
        throw new ValidationError('The dates are in an illogical order');
    }
}

Upvotes: 1

Related Questions