MDY Error Calculator

by _sir

HTML

<script src="https://unpkg.com/[email protected]/moment.js"></script>
<h1>
  DMY to MDY Error Calculator
</h1>
<p>
  Identify issues caused by unintentionally translating between DD/MM/YYYY and MM/DD/YYYY formats with the range of selectable dates.
</p>

<hr>
<div id="yearly">
  <h2>
    Whole Year Calculations
  </h2>
  <p>
    Collect the available options for every day of a year and reports the aggregate counts.
  </p>
  <section>
    <form name="yearly" id="yearlyForm" onsubmit="return false">
      <fieldset>
        <legend>Yearly Settings</legend>
        <div><label><span>Minimum Offset</span> <input name="offsetMin" type="number" value="0"></label></div>
        <div><label><span>Maximum Offset</span> <input name="offsetMax" type="number" value="42"></label></div>
        <div><label><span>Include Weekends</span> <input name="weekends" type="checkbox"></label></div>
        <div><label><span></span> <button id="calcYearly">Calculate</button></label></div>
      </fieldset>
    </form>
    <fieldset>
      <legend>Yearly Reporting</legend>
      <div id="yearlyReport"></div>
    </fieldset>
  </section>

</div>

<div id="yearly">
  <h2>
    Specific Day Issues
  </h2>
  <p>
    Report the available issues for a single day as an issue object.
  </p>
  <section>
    <form name="day" id="dayForm" onsubmit="return false">
      <fieldset>
        <legend>Daily Detail</legend>
        <div><label><span>Date (ISO format)</span> <input id="todayDate" name="isoDate" type="text" value=""></label></div>
        <div><label><span>Minimum Offset</span> <input name="offsetMin" type="number" value="0"></label></div>
        <div><label><span>Maximum Offset</span> <input name="offsetMax" type="number" value="42"></label></div>
        <div><label><span>Include Weekends</span> <input name="weekends" type="checkbox"></label></div>
        <div><label><span></span> <button id="calcDay">Calculate</button></label></div>
      </fieldset>
    </form>
    <fieldset>
     ...

CSS

body {
  margin: 1em;
}

section {
  display: flex;
}

fieldset {
  width: 40%;
  min-width: 30em;
  margin: 1em;

}

legend {
  font-weight: bold;
}

fieldset label>span {
  display: inline-block;
  width: 10em;
  text-align: right;
  padding-right: 1em;
}

fieldset>div {
  margin: 5px;
}

JavaScript

const ISO = 'YYYY-MM-DD';
const MDY = 'MM/DD/YYYY';
const DMY = 'DD/MM/YYYY';
const DOY = 'DDD YYYY';

const makeDateFromDoY = (dayOfYear) => moment(`${dayOfYear} 2023`, DOY);
const parseIso = (isoDate) => moment(isoDate, ISO);
const isoToDMY = (isoDate) => parseIso(isoDate).format(DMY);
const isoToMDY = (isoDate) => parseIso(isoDate).format(MDY);

const changeDMYtoMDYfromIso = (isoDate) => moment(isoToDMY(isoDate), MDY);
const isDMYValidMDY = (isoDate) => changeDMYtoMDYfromIso(isoDate).isValid();
const isNotWeekend = (isoDate) => ![0, 6].includes(parseIso(isoDate).weekday());

const isFlipNotWeekend = (isoDate) => isNotWeekend(changeDMYtoMDYfromIso(isoDate));

// Build Source Data
const dates = new Array(365).fill('')
  .map((v, i) => makeDateFromDoY(i + 1).format(ISO));

const validDMY = dates.filter(isDMYValidMDY);
const isInValidMDY = (isoDate) => validDMY.includes(isoDate);

// Second-round functions
const checkMDYOffsets = (isoDate, minOffset, maxOffset, includeWeekends = false) => {
  const weekendFilter = includeWeekends ? () => true : isNotWeekend;
  const startDate = parseIso(isoDate);
  const validDates = new Array(maxOffset - minOffset).fill('')
    .map((v, i) => parseIso(isoDate).add(i + minOffset, 'days').format(ISO))
    .filter(weekendFilter);
  const checkDates = validDates.filter(isDMYValidMDY);
  const pastDates = checkDates.filter((date) => changeDMYtoMDYfromIso(date).isBefore(startDate, 'day'));
  const validFlips = checkDates.filter((date) => changeDMYtoMDYfromIso(date).diff(startDate, 'days') <= maxOffset).filter(isFlipNotWeekend);
  const futureDates = checkDates.filter((date) => changeDMYtoMDYfromIso(date).diff(startDate, 'days') > maxOffset);
  const futureWeekends = futureDates.filter((date) => !isNotWeekend(changeDMYtoMDYfromIso(date)));
  const futureOutOfRange = futureDates
  const problemCount = pastDates.length + futureDates.length - (includeWeekends ? futureWeekends.length : 0);
  return {
    date: isoDate,
    minOffset,
   ...