如何计算在两个日期之间经过的 "quarters" 的数量,其中季度不仅仅是一年中的一个季度,而是特定日期?

How can I calculate the number of "quarters" that have passed between 2 dates, where quarters are not simply a quarter of a year, but specific dates?

我正在尝试使用 Javascript 制作一个 "Rent Arrears Calculator",我想要的功能之一是可以选择计算每周、每月或每季度的租金。

如果按季交房租,过了某一天,迟交的季度数就会增加。这些季度日是每年的 25/03、24/06、29/09/ 和 25/12。

当输入日期的月份大于季度日期的月份,但其日期小于季度日期时,我的代码目前 returns 值不正确。

即对于 2014 年 6 月 24 日的 "First missed payment date" 和 2015 年 4 月 22 日的日期,这应该是 return 4,而不是 returns 1。它应该是 return 4 因为这次已经过了 4 个季度日期(24/06/2014、29/09/2014、25/12/2014 和 25/03/2015)。

这是我的代码:

function getNumberPeriods() {
        var years = (getNumberYears());
        var days = (getNumberDays());
        if ((getPeriodLength()) == "Weekly") {
            return ((days - (days % 7)) / 7);
        } else if ((getPeriodLength()) == "Monthly") {
            var months = ((((options.untilDate).getMonth()) + 1) - (((options.dueDate).getMonth()) + 1) + (12 * years));
            if (((options.untilDate).getDate()) < ((options.dueDate).getDate())) {
                months--;
            }
            return (months + 1);
        } else if ((getPeriodLength()) == "Quarterly") {
            if ((options.dueDate).getMonth() == 2) {
                if (((options.untilDate).getMonth() <= 5) && ((options.untilDate).getDate() < 24)) {
                    return (1+(years * 4));
                }
                else if (((options.untilDate).getMonth() <= 5) && ((options.untilDate).getDate() >= 24)) {
                    return (2+(years * 4));
                }
                else if (((options.untilDate).getMonth() <= 8) && ((options.untilDate).getDate() < 29)) {
                    return (2 + (years * 4));
                }
                else if (((options.untilDate).getMonth() <= 8) && ((options.untilDate).getDate() >= 29)) {
                    return (3 + (years * 4));
                }
                else if (((options.untilDate).getMonth() <= 11) && ((options.untilDate).getDate() < 25)) {
                    return (3 + (years * 4));
                }
                else if (((options.untilDate).getMonth() <= 11) && ((options.untilDate).getDate() >= 25)) {
                    return ((years * 4)+4);
                }
                else return (years * 4);
            }
            else if ((options.dueDate).getMonth() == 5) {
                if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() < 25) {
                    return (3 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() >= 25) {
                    return (4+(years * 4));
                }
                else if ((options.untilDate).getMonth() <= 8 && (options.untilDate).getDate() < 29) {
                    return ((years * 4)+1);
                }
                else if ((options.untilDate).getMonth() <= 8 && (options.untilDate).getDate() >= 29) {
                    return ((years * 4)+2);
                }
                else if ((options.untilDate).getMonth() <= 11 && (options.untilDate).getDate() < 25) {
                    return (2 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 11 && (options.untilDate).getDate() >= 25) {
                    return (3 + (years * 4));
                }
                else return (years * 4);
            }
            else if ((options.dueDate).getMonth() == 8) {
                if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() < 25) {
                    return (2 + (years * 4));
                }
                if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() >= 25) {
                    return (3 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 5 && (options.untilDate).getDate() < 24) {
                    return (3 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 5 && (options.untilDate).getDate() >= 24) {
                    return (4+(years * 4));
                }
                else if ((options.untilDate).getMonth() <= 11 && (options.untilDate).getDate() < 25) {
                    return ((years * 4)+1);
                }
                else if ((options.untilDate).getMonth() <= 11 && (options.untilDate).getDate() >= 25) {
                    return ((years * 4)+2);
                }
                else return (years * 4);
            }
            else if ((options.dueDate).getMonth() == 11) {
                if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() < 25) {
                    return ((years * 4)+1);
                }
                else if ((options.untilDate).getMonth() <= 2 && (options.untilDate).getDate() >= 25) {
                    return ((years * 4)+2);
                }
                else if ((options.untilDate).getMonth() <= 5 && (options.untilDate).getDate() < 24) {
                    return (2 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 5 && (options.untilDate).getDate() >= 24) {
                    return (3 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 8 && (options.untilDate).getDate() < 29) {
                    return (3 + (years * 4));
                }
                else if ((options.untilDate).getMonth() <= 8 && (options.untilDate).getDate() >= 29) {
                    return ((years * 4)+4);
                }
                else return (years * 4);
            }
            else alert("not werkin");
        }
    }


    function getNumberDays() {
        return ((((options.untilDate)) - ((options.dueDate))) / (1000 * 60 * 60 * 24));
    }
    function getNumberYears() {
        var dueMonth = (options.dueDate).getMonth();
        var dueDay = (options.dueDate).getDate();
        var dueYear = (options.dueDate).getFullYear();
        var untilYear = (options.untilDate).getFullYear();
        var untilMonth = (options.untilDate).getMonth();
        var untilDay = (options.untilDate).getDate();
        var diffyears = untilYear - dueYear; 

        if (untilMonth < dueMonth - 1){
         diffyears--;
            }
        if (dueMonth - 1 == untilMonth && untilDay < dueDay){
        diffyears--;
            }
        return diffyears;

this 是我的 JS fiddle 的 link(我知道 fiddle 的其他部分无法正常工作,但我还没有还没到那些)。

任何帮助将不胜感激!

泽赫拉

以下代码将经过的季度计入 passed

var quarters = [{'month':3, 'day':25}, {'month':6, 'day':24}, 
    {'month':9, 'day':29}, {'month':12, 'day':25}];

var year = options.dueDate.getFullYear();
var passed = 0; // this is the number of passed quarters
var quarterIndex = 0;
do {
    // month is 0 based
    var reference = new Date(
        year, 
        quarters[quarterIndex].month - 1, 
        quarters[quarterIndex].day);

    if( (reference >= options.dueDate) && (reference <= options.untilDate) ) {
        passed ++;
    }

    quarterIndex++;
    if(4 == quarterIndex) {
        quarterIndex = 0;
        year++;
    }
} while(reference < options.untilDate);

在您的代码中,您试图掩盖所有可能存在的情况。对于这个问题(以及大多数其他有大量案例的问题),这不是一个很好的方法。相反,尝试以不同的方式思考:您可以遍历季度日期并查看它们是否在 dueDateuntilDate 之间的时间段内。但是,您缺少日期的 year 部分来执行此操作。我建议在开始时使用 dueDate 的年份来构造 Date 对象,然后在每次迭代中增加年份,直到 year 变得大于 untilDate 的年份.

这是代码清单:

     } else if ((getPeriodLength()) == "Quarterly") {
        // We have an array of all the quarter dates
        var quarterDates = [
            {
                'm': 3,
                'd': 25
            },
            {
                'm': 6,
                'd': 24
            },
            {
                'm': 9,
                'd': 29
            },
            {
                'm': 12,
                'd': 25
            }];
        // The count of missed periods
        var count = 0;
        // Initial year value
        var year = options.dueDate.getFullYear();
        // Condition on when to stop
        while (year <= options.untilDate.getFullYear()) {
            for(var i in quarterDates) {
                // Just a precaution, because foreach in js
                // loops through all properties of the object
                // and there might be functions and we want to
                // skip them   
                if (typeof(quarterDates[i]) != 'function') {
                    // Construct a Date object
                    // Note: months in js have numbers from 0 to 11
                    var qDate = new Date(year, quarterDates[i].m - 1, quarterDates[i].d);
                    // If the date is in the given period
                    if (qDate >= options.dueDate && qDate <= options.untilDate) {
                        // Increase the counter
                        count++;
                    }
                }
            }
            // Increase the value
            year++;
        }
        return count;
    }