Calculate Years and Months since a Specific Date

I am trying to come up with a simple solution to:

current date - indicated date with format “January 4, 2018” = years and months since the indicated date.

I looked at the Datejs but I was unable to figure out how to use it to do a simple math date calculation.

I came up with this but I am not sure if this is the way to go. Suggestions are welcomed.

var dPast = 'January 4, 2018'
var d1 = new Date(); //"now"
var d2 = new Date(dPast);
var dCalc = Math.abs((d1-d2)/31556952000);   // difference in milliseconds
var diff = Math.round(10 * dCalc)/10;   // difference in years rounded to tenth

alert('It has been ' + diff + ' years since ' + dPast);

Edit: Solved. Here is a solution that I got from a Reddit user:

var dPast = 'January 4, 2018'
var d1 = new Date(); //"now"
var d2 = new Date(dPast);

var years = d1.getYear() - d2.getYear()
var months = d1.getMonth() - d2.getMonth()
alert(`It has been ${years} years and ${months} months`)

You won’t like that solution if today’s month is “before” dPast’s month. Try it with

dPast = 'December 4, 2017';

and you’ll get “It has been 3 years and -4 months.” Which is true in a sense but probably not what you’re looking for.

If you think you’ll do this kind of date math ever again, I suggest installing the Dayjs library. Download the dayjs.min.js file from the JSDelivr site and save it to the Drafts/Library/Scripts folder in iCloud. With that library in place, you can do stuff like this:

require('dayjs.min.js');

let dPast = 'December 4, 2017';
let d1 = dayjs();
let d2 = dayjs(dPast);

let m = Math.round(d1.diff(d2, 'month', true));

let y = Math.floor(m/12);
if (y == 0) {
  alert(`\n${m} months since ${dPast}`);
}
else {
  m = m % 12;
  if (m == 0) {
    alert(`${y} years since ${dPast}`);
  }
  else {
    alert(`${y} years, ${m} months since ${dPast}`);
  }
}

The important part is the line

let m = Math.round(d1.diff(d2, 'month', true));

This first calculates the difference between the two dates in months, including fractional months. It then rounds to the nearest month.

The rest of the script is just some fiddling with the output. The “years” part is omitted from the output if the difference is less than a year and the “months” part is omitted if the difference is a whole number of years.

2 Likes

@drdrang Thank you. The final push for me to starting learning JavasScript, was after listening to your last episode on Mac Power Users. Glad to see you in the forums. Your code was a step up as I wanted to keep things simple as a beginner. However, I went step by step to understand it. I will leave a footprint here for my own reference and for anyone in the future.

/*********
Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates and times for modern browsers with a largely Moment.js-compatible API.

Step 1: Download the dayjs.min.js file from the JSDelivr site: https://www.jsdelivr.com/package/npm/dayjs

Step 2 : Save the downloaded file to the Drafts/Library/Scripts folder in iCloud. 
*/

require('dayjs.min.js'); // Tell Drafts to use Dayjs script

let dPast = 'December 4, 2017'; // set the date from the past
let d1 = dayjs(); // tell Dayjs to parse the date
let d2 = dayjs(dPast); // set the current date

/******
* Math.round() - is a function that is used to return a number rounded to the nearest integer (whole) value.

* To get the difference in months, pass the month as the second argument. By default, dayjs#diff will truncate the result to zero decimal places, returning an integer. If you want a floating point number, pass true as the third argument.

*Read more: https://day.js.org/docs/en/display/difference#docsNav
*/

let m = Math.round(d1.diff(d2, 'month', true));

/******
* Divide the number of months (obtained earlier) by 12 to see how many years. This number will be rounded to an integer (whole number). If the result is less than 1 (years) the rounded number will be set to 0. For example 11/12 = 0.916666667 This will be rounded to 0.
*/

let y = Math.floor(m/12); 
if (y == 0) {
  alert(`\n${m} months since ${dPast}`); // Alert that "x" number of months but no years have passed since the indicated date.
}
/* Remainder
An amount left over after division (happens when the first number does not divide exactly by the other). Example: 19 cannot be divided exactly by 5. The closest you can get without going over is 3 x 5 = 15, which is 4 less than 19. So 4 is the remainder.

In JavaScript, the remainder operator (%) returns the remainder left over when one operand is divided by a second operand. It always takes the sign of the dividend.
*/
else {
  m = m % 12;
  if (m == 0) {
    alert(`${y} years since ${dPast}`); //If the remainder is 0 than a whole year(s) have passed since the indicated date but no months.
  }
  else {
    alert(`${y} years, ${m} months since ${dPast}`); // Years and months since the indicated date.
  }
}
1 Like

I made further improvements to the script to convert numbers into words. Sharing in case anyone else needs this.

require('dayjs.min.js');

let dPast = draft.content.match(/Loss:\s*(\w+ \d{1,2}, \d{4})/)[1];
let d1 = dayjs();
let d2 = dayjs(dPast);

var m = Math.round(d1.diff(d2, 'month', true));
var y = Math.floor(m/12);

//Funciton - Convert numebrs to words

function numeral(number){
   var numbers = ['zero','one','two','three','four','five','six','seven','eight','nine','ten','eleven'];
   return numbers[number]
}

// Convert singular to plural

y == 1 ? yearWord = 'year' : yearWord = 'years';
m % 12 == 1 ? monthWord = 'month' : monthWord = 'months';

if (y == 0) {
    var month = numeral(m);
    var timeSince = (month + ' ' + monthWord)
}
else {
  m = m % 12;
  if (m == 0) {
    var year = numeral(y);
    var timeSince = (year + ' ' + yearWord);
  }
  else {
    var year = numeral(y);
    var month = numeral(m);
    var timeSince = (year + ' ' + yearWord + ' and ' + month + ' ' + monthWord);
  }
}

editor.setSelectedText(timeSince)

I like how you decided you didn’t need a general solution to the “numbers into words” problem and built a solution for the small, specific problem at hand. I’m assuming the date of loss will never be more than twelve years ago.

Correct. In my case, I am using the script for writing psychological reports where the date of loss (date of accident) is usually not greater than five years from today.