Converting an Excel formula expression into JavaScript code

I am trying to implement the formula from Excel using the JSON object provided below. I have done the computations, but there seems to be an error as the result is not exact. If anyone has any ideas about it, I would appreciate your input. Thank you.

I just want to verify if I made a mistake in the conversion. The correct result should be based on the JSON data below:

https://i.sstatic.net/p1Nwm.png

https://i.sstatic.net/0XLJ2.png

#FORMULA

=IF(AND(H4="Current",I4<$B$6,J4>$B$6),DAYS360($B$6,J4)/360*12,IF(AND(H4="Current",I4>$B$6,J4>$B$6),DAYS360(I4,J4)/360*12,0))

#sample data input (the scheduleData object and effectiveDate input)

effectiveDate = new Date('11/1/2021')
    
    
scheduleData=    [
        {
            "description": "Current Term",
            "startDate": "6/1/2021",
            "endDate": "04/30/2025",
            "annualRent": 359659.19999999995
        },
        {
            "noticeDate": "04/30/2028",
            "description": "Current Term - Rent Adjustment",
            "startDate": "05/01/2025",
            "endDate": "04/30/2029",
            "annualRent": 377642.16000000003
        }
    ]


Compute(scheduleData: any):any{
    let startDate = typeof scheduleData.startDate === 'string' ? new Date(scheduleData.startDate):scheduleData.startDate;
    const endDate = typeof scheduleData.endDate === 'string' ? new Date(scheduleData.endDate):scheduleData.endDate;
    if(!startDate || startDate.toString() === 'Invalid Date'){
    }
    let monthlyRent = scheduleData.annualRent / 12;
    let monthsInPeriod = (this.Days360(startDate, endDate) / 360) * 12 
    let rentInPeriod = monthsInPeriod * monthlyRent;
    return { 
      description: scheduleData.description,
      monthlyRent: monthlyRent,
      monthsInPeriod: monthsInPeriod,
      rentInPeriod: rentInPeriod
    }
  }

  Days360(startDate: Date, endDate: Date, decimalPlace: number = 2){
    if(!startDate || !endDate){
      return undefined;
    }
    let startDay = startDate.getUTCDate();
    let endDay = endDate.getUTCDate();

    if(isLastDayOfMonth(startDate)){
      startDay = 30;
    }

    if(isLastDayOfMonth(startDate) && isLastDayOfMonth(endDate)){
      endDay = 30;
    }
    const computedDays = (((endDate.getUTCFullYear() - startDate.getUTCFullYear()) * 360) + ((endDate.getUTCMonth() - startDate.getUTCMonth()) * 30) + (endDay - startDay));
    return parseFloat(parseFloat(computedDays.toString()).toFixed(decimalPlace));
  }

Answer №1

One aspect of code that I overlooked checking was the isLastDayOfMonth function. After testing your code with a modified version of isLastDayOfMonth, it successfully produced the desired outcome:

function isLastDayOfMonth(inDate: Date): boolean {
  //april,june,sept,nov
  const thirties = [3, 5, 8, 10];
  //jan,mar,may,jul,aug,oct,dec
  const thOnes = [0, 2, 4, 6, 7, 9, 11];
  if (thirties.includes(inDate.getMonth())) { return inDate.getDate() === 30; }
  if (thOnes.includes(inDate.getMonth())) { return inDate.getDate() === 31; }
  if (inDate.getFullYear() % 4 === 0) { return inDate.getDate() === 29; }
  return inDate.getDate() === 28;
}

Update:

I failed to account for the Effective Date in your initial code, which led to discrepancies. While the spreadsheet indicated 41.97 for the first line, I was obtaining 46.97.

By incorporating the following code (in TS Playground), I achieved accurate results:

const effectiveDate = new Date('11/1/2021');

function Compute(scheduleData: any): any {
  let startDate = typeof scheduleData.startDate === 'string' ? new Date(scheduleData.startDate) : scheduleData.startDate;
  const endDate = typeof scheduleData.endDate === 'string' ? new Date(scheduleData.endDate) : scheduleData.endDate;
  if (!startDate || startDate.toString() === 'Invalid Date') {
    return scheduleData;
  }
  let monthlyRent = scheduleData.annualRent / 12;
  let range360: any = (startDate < effectiveDate && endDate > effectiveDate) ?
    Days360(effectiveDate, endDate) :
    (startDate > effectiveDate && endDate > effectiveDate) ?
      Days360(startDate, endDate) :
      0;
  let monthsInPeriod = (range360 / 360) * 12;
  let rentInPeriod = monthsInPeriod * monthlyRent;
  return {
    description: scheduleData.description,
    monthlyRent: monthlyRent,
    monthsInPeriod: monthsInPeriod,
    rentInPeriod: rentInPeriod
  };
}

function Days360(startDate: Date, endDate: Date, decimalPlace: number = 2): number | undefined {
  if (!startDate || !endDate) {
    return undefined;
  }
  let startMonth = startDate.getMonth();
  let startDayOfMonth = startDate.getDate();
  let startYear = startDate.getFullYear();
  let endMonth = endDate.getMonth();
  let endDayOfMonth = endDate.getDate();
  let endYear = endDate.getFullYear();

  let monthsDifference = endMonth - startMonth;
  let dayOfMonthDifference = endDayOfMonth - startDayOfMonth;
  let yearDifference = endYear - startYear;

  let monthsDifferenceInDate360 = 30 * monthsDifference;
  let yearDifferenceInDate360 = 360 * yearDifference;

  let differenceSum = yearDifferenceInDate360 + monthsDifferenceInDate360 + dayOfMonthDifference;
  return parseFloat(parseFloat(differenceSum.toString()).toFixed(decimalPlace));
}
var scheduleData = [{
  "description": "Current Term",
  "startDate": "6/1/2021",
  "endDate": "04/30/2025",
  "annualRent": 359659.19999999995
},
{
  "noticeDate": "04/30/2028",
  "description": "Current Term - Rent Adjustment",
  "startDate": "05/01/2025",
  "endDate": "04/30/2029",
  "annualRent": 377642.16000000003
}
];

scheduleData.forEach(function (sd): void {
  console.log(Compute(sd));
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to specify in TypeScript that if one key is present, another key must also be present, without redundantly reproducing the entire structure

In my code, I have a custom type defined like this (but it's not working): type MyType = | { foo: string; } | { foo: string; barPre: string; barPost: string; } | { foo: string; quxPre: string; qu ...

Ways to verify partially executed php code with the aid of javascript

For my PHP script, the task is to download numerous image files. However, it frequently stops or terminates midway due to various reasons. I have included a message (using flush) after each image download and a successful completion message at the end. Is ...

Tips for creating a helper function that returns a promise for a React hook function

So, I have this React functional component that makes use of both the useState and useEffect hooks: import React, { useState, useEffect } from 'react'; import { requestInfo } from './helpers/helpers'; const App = () => { const [pe ...

Discovering the window.scrollTop, ScrollY, or any other distance value while utilizing CSS scroll snap can be achieved by following these

I am currently utilizing css scroll snap for smooth scrolling through sections that are 100vh in height. The functionality of the scroll snap is quite impressive. However, I need to find a way to determine the exact distance the user has scrolled down the ...

What could be causing my JavaScript to not execute when going back on Safari?

Upon navigating back to a page from another within the same site, I have noticed that half of the functions do not execute properly without any errors appearing in the console. However, upon refreshing the page, everything functions as expected. To troubl ...

Display information from a specific identifier in a modal popup window after clicking a button using PHP and MySQL

When a button is clicked on my website, a popup window appears using modal functionality. The issue I am facing is not being able to retrieve the correct data based on the id of the button. Below is the HTML table code snippet: <tbody> <?php $cou ...

"Overabundance of recursion" error encountered upon submission via jQuery

I'm encountering an issue with my custom submit function that includes validation. Every time I click on Submit, it displays a "Too much recursion" error. $('#searchform').on('submit', function(e){ var validateError = ' ...

Having trouble retrieving the contents of a <div> tag within a JavaScript function

Javascript Code In First ContentPlaceHolder :- <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server"> <script type="text/javascript" > function PrintElem(elem) { alert(elem); Popup($(elem).html()); } ...

When using jQuery's .ajax method, the function is not being called

I am having an issue with calling the addLoadEvent function from the success callback of an AJAX request. The "game" object is created and when I call createGame, it uses jQuery AJAX. Everything works fine except that the addLoadEvent function is not bei ...

Type validation in TypeScript through cross-referencing variables

Can TypeScript be used to define a variable that determines the type of other variables? I want to simplify the process by only needing to check one variable, stateIndicator, which is dependent on other variables to infer their types. type A = {prop1: st ...

Is it possible to modify the CSS produced by Bootstrap in an Angular application?

Just starting out with Angular and Bootstrap I have the following displayed in my browser: Browser Code shown through inspect and this is what I have in my code: <ng-template #newSlaVmData let-modal> <div class="modal-header moda ...

JavaScript Astro file not triggering window.onload event

I need assistance with my Astro components in my App: apps/myProject libs/components/header Within the header.astro component, I have a script that should execute once the entire page is rendered: <script is:inline> console.log('hello!' ...

Every variable declaration that follows must match the data type of the initial declaration

Here's the link I'm using to kickstart a sample node js project with webworker-thread: https://www.npmjs.com/package/webworker-threads Below is my TypeScript code snippet: var Worker = require('webworker-threads').Worker; var worker ...

Make sure to always send back JSON data when using the default error handler in ExpressJS

I'm in the process of developing an API server using ExpressJS. I want to guarantee that the server consistently delivers JSON data rather than HTML data. While I can easily make the server respond with JSON for all customized routes, I encounter diff ...

What is the best way to retrieve an array of objects from Firebase?

I am looking to retrieve an array of objects containing sources from Firebase, organized by category. The structure of my Firebase data is as follows: view image here Each authenticated user has their own array of sources with security rules for the datab ...

What programming language is the best choice for Angular 2 development?

As someone who is new to Angular 2, I've discovered that developers have the option to use TypeScript, ES6, and ES5 for their development needs. I understand that TypeScript is considered the superset of ES6 and ES5. Given the stark differences in sy ...

When you attempt to "add website to homescreen" on an iPhone, Ajax malfunctions

I have a unique website feature that utilizes ajax to dynamically load content when the user interacts with certain buttons. Everything functions smoothly up until a user tries to access the website through the "add to homescreen" option on mobile Safari a ...

`My jquery mobile application fails to trigger the pageinit or ready events`

My website consists of 3 PHP pages: one index page and two subpages for sales and products. The index page has links to these subpages. When I click on the sales link, it is supposed to load sales data either on pageinit or document ready. However, no code ...

"Encountering a problem with the client-session middleware: the value of req.session_state is becoming undefined

I'm facing an issue with client-session middleware in Express. After setting the session_state, it doesn't seem to be accessible when redirecting to a new route. I followed a tutorial on YouTube (client-session part starts at around 36:00) and do ...

An Alternative Approach to Implementing the Ternary Operator in JavaScript

Do you find this logical operation to be rational? const user = users && users[0] || null; Is it identical to this conditional or ternary operation: const user = users ? users[0] : null; ? Let's assume users represents an array. ...