3

I have a funny bug in my calculation about interest days. I go through each day and check which day it is (1 to 31). Now I found a problem: In October the count doesn't work properly. That means the 27th is the 26th, or the 29th is the 28th. Is this a well know problem? Maybe the problem is in my code, but, because it works over another period, it seems to be fine.

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript">
        function berecheZinstage() {
            //eingabe von den Feldern holen
            var strVon = txtVonDatum.value;
            var strBis = txtBisDatum.value;
            //label um das Resultat anzuzeigen
            var resultatTage = document.getElementById("lblTage");
            var resultatZinsTage = document.getElementById("lblZinstage");
            //tag als Milisekunden
            var tagMs = 86400000;
            var monatCount;
            //Eingabeformat umwandeln für die Berechung
            strVon = strVon.replace(/-/g, "/");
            strBis = strBis.replace(/-/g, "/");
            var vonDatum = new Date(strVon);
            var bisDatum = new Date(strBis);
            var zinsTage = 0;
            if (bisDatum > vonDatum) {
                var totTage = bisDatum - vonDatum;
                var nDays = Math.round(totTage / (1000 * 60 * 60 * 24));

                var pruefMS = vonDatum.getTime();
                var startMS = vonDatum.getTime();
                var endeMS = bisDatum.getTime();
                var febCount = 0;
                var langCount = 0;
                var tage = 0;
                for (var i = 0; i < nDays; i++) {
                   pruefMS = pruefMS + tagMs;
                   var pruefDatum = new Date(pruefMS);
                    var pruefMonat = pruefDatum.getMonth();
                    var pruefJahr = pruefDatum.getFullYear();

                    var pruefTag = pruefDatum.getDate();

                    if (pruefTag == 1 && pruefDatum != startMS) {
                        if (pruefMonat == 2) {
                            var istSchaltjahr = new Date(pruefJahr, 1, 29).getMonth() == 1;
                            if (istSchaltjahr) {
                                tage++;
                            }
                            else {
                                tage = tage + 2;
                            }
                        }
                    }
                    if (pruefTag != 31) {
                        tage++;
                    }
                }
                resultatZinsTage.innerText = tage.toString();
                resultatTage.innerText = pruefTag;//nDays.toString();
            }
            else {
                resultatTage.innerText = "Bis Datum muss grösser sein als von Datum";
            }

        }

    </script>

    <title>Zinstage berechen</title>
</head>

<body>
    <table style="width:100%;">
        <tr>
            <td style="width:100px;"><input id="txtVonDatum" type="text" /></td>
            <td style="width:100px;"><input id="txtBisDatum" type="text" /></td>
            <td style="width:100px;"><button id="btnCalcDays" type="button" onclick="berecheZinstage();">Berechnen</button></td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>Tage:</td>
            <td><label id="lblTage"></label></td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>Zinstage:</td>
            <td><label id="lblZinstage"></label></td>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
    </table>
</body>
</html>

Thanks, Marlowe

Cilan
  • 13,101
  • 3
  • 34
  • 51
Marlowe
  • 252
  • 3
  • 15
  • On a side note, you DO know that JavaScript doesn't have block-scoped variables, don't you? – toniedzwiedz Dec 19 '13 at 21:58
  • The Date code is not broken. – Pointy Dec 19 '13 at 21:58
  • @HugoTunius - почему? – Yuriy Galanter Dec 19 '13 at 22:00
  • @Doorhandle German, I think? :P – tckmn Dec 19 '13 at 22:01
  • 2
    @Marlowe Can you tell us an example of where it works out ok? Indexes of dates aren't always what people expect (e.g. months go from 0 to 11.) – Scott Mermelstein Dec 19 '13 at 22:03
  • 1
    You do know that not every month has 31 days? And why is the code in German? – Cilan Dec 19 '13 at 22:04
  • 1
    @Doorhandle Probably because the OP speaks German. – Dave Newton Dec 19 '13 at 22:06
  • @DaveNewton Then did he do google translate on this? I had to edit some words, actually, in this question – Cilan Dec 19 '13 at 22:07
  • 3
    What's that thing that happens in October? Isn't there a weekend when you get just a little bit more sleep? How long is that day? – Pointy Dec 19 '13 at 22:09
  • 1
    @Doorhandle Jeff Atwood's take on English: "Now, if askers try to use English and put in “sorry, my English isn’t very good”, that’s fine. Heck, a lot of native English speakers aren’t very good at it, either! The reason we have collaborative editing is to learn and improve together. This is totally fine and even encouraged. (Please do try to make sense, as our users are often brilliant, but not telepathic as far as I know.)" [link](http://blog.stackoverflow.com/2009/07/non-english-question-policy/) It's good that you edited the language, but it was understandable. Google translate did fine. – Scott Mermelstein Dec 19 '13 at 22:12
  • For counting days why don't you just use `var totTage = bisDatum - vonDatum; var nDays = Math.round(totTage / (1000 * 60 * 60 * 24));`? Btw. `pruefMonat === 1` is February – metadings Dec 19 '13 at 22:17
  • @Doorhandle Doubt it, it wouldn't be able to do such a good job. – Dave Newton Dec 19 '13 at 22:19
  • If I go through the days 2013-10-25 till 2013-10-31 and read the day with pruefDatum.getDate() I get the following output: 25 26 27 27 28 29 – Marlowe Dec 21 '13 at 12:04

2 Answers2

1

I don't understand what this code is trying to achieve, but the problem is DST (Daylight Saving Time).

Adding 86400000 millis for each day should work ok. But in locales that use DST (default in Germany), the result of date "2013/10/01 00:00:00" + 31*86400000 would be "2013/10/31 23:00:00".

Actually if we include the timezone, it would be "2013/10/01 00:00:00 GMT+0200" + 31*86400000 would be "2013/10/31 23:00:00 GMT+0100", so the addition is correct in UTC terms.

Likewise in March, the resulting date would be "2013/04/01 01:00:00", but we don't see the error since we're only counting the days.

When performing operations like this, always use UTC to avoid headaches :)

foibs
  • 3,258
  • 1
  • 19
  • 13
  • Thanks for all help. But even when I add " 00:00:00 GMT+0200" to create the date, I still have the same problem. What I do: I go through all days from start to end and check witch day in month it is. If it's the 31th don't count. But the problem in October is, somewhere it does not return the right day of the month. In 2013 till October 27th it's all OK, but the 28th is still the 27th. So at the end, the 31th is the 30th in the program and the day will be counted, what not should be happen, because in reality it is the 31th. – Marlowe Dec 20 '13 at 15:42
  • Use only UTC functions. Otherwise you will always have similar problems. You can use `getTimezoneOffset()` to fix the timezone differences, but in the end UTC is the way to go. http://www.w3schools.com/jsref/jsref_obj_date.asp – foibs Dec 20 '13 at 15:50
  • Thanks, but where I have to deduct this difference? At the daily milliseconds? – Marlowe Dec 20 '13 at 16:11
  • I still suggest using UTC dates. See here how to create UTC dates: http://stackoverflow.com/questions/439630/how-do-you-create-a-javascript-date-object-with-a-set-timezone-without-using-a-s . If you still want to use getTimezoneOffset, you need to keep last value from the previous loop, and subtract the difference of the previous offset and the current offset, so you only actually change the value when the offset has changed – foibs Dec 20 '13 at 16:38
  • Even if I don't use the UTC. In your explanation the 31th October is still the 31th not the 30th. So it not solved the problem, that I don't get the 28th October 2013. :-( – Marlowe Dec 21 '13 at 11:26
  • In my example October 31st should be November 1st, so it's the same issue. I see you accepted my answer. Did you manage to sort it out? – foibs Dec 21 '13 at 18:46
0

Here is now the working code. With the hint given by foibs I've built a little hack to calculate the interest days.

<script type="text/javascript">
    function calcInterestDays() {
        //get the values from the input fields
        var strFrom = document.getElementById("txtFromDate").value;
        var strTill = document.getElementById("txtTillDate").value;
       //format strings
        strFrom = strFrom.replace(/-/g, "/");
        strTill = strTill.replace(/-/g, "/");
        var fromDate = new Date(strFrom);
        var tillDate = new Date(strTill);
        var msDay = 86400000;
        var startMS = fromDate.getTime();
        var totDays = Math.round((tillDate - fromDate) / (1000 * 60 * 60 * 24));
        var totMs = startMS;
        var outputStr = "";
        var days = 0;
        for (var i = 0; i < totDays; i++) {
            totMs = totMs + msDay;               
            var checkDate = new Date(totMs);
            var splitDate = checkDate.toString().split(" ");
            if (splitDate[6] == "0200") {
                var calcDay = new Date(totMs);
            }
            else {
                var calcDay = new Date(totMs + 3600000);
            }

            if (calcDay.getDate() == 1 && totMs != startMS) {
                if (calcDay.getMonth() == 2) {
                    var istSchaltjahr = new Date(calcDay.getFullYear(), 1, 29).getMonth() == 1;
                    if (istSchaltjahr) {
                        days++;
                    }
                    else {
                        days = days + 2;
                    }
                }
            }
            if (calcDay.getDate() != 31) {
                days++;
            }

            outputStr = outputStr + "<br>" + calcDay;
        }            
        document.getElementById("lblTotDays").innerHTML = totDays;
        document.getElementById("lblInterestDays").innerHTML = days;
        document.getElementById("output").innerHTML = outputStr;
    }
</script>

Thanks for all the help.

Marlowe
  • 252
  • 3
  • 15