2

So I am trying to make a simple counter. I essentially want to find the difference between Jun 5, 2011 00:00:00 date and now. Then display this date in the format of Years Months Days Hours Minutes Seconds.

I went to timeanddate.com to calculate the difference. This website is very reliable and it tells me the difference is 7 years, 9 months, 11 days, 20 hours, 38 minutes, 4 seconds. But my code tells me its 7 years, 9 months, 13 days. What am I doing wrong & how can I fix it? Is there now function that calculate all this for me?

<html>
<body>

<p id="demo"></p>

<script>
// Date to start on
var startDate = new Date("Jun 5, 2011 00:00:00").getTime();

// Update the count down every 1 second
var x = setInterval(function() {

  // Get todays date and time
  var now = new Date().getTime();
    
  // Find how long its been since the start date and now
  var distance = (now - startDate);
    
  // Time calculations
  var years = Math.floor(distance / 31536000000);
  var months = Math.floor((distance % 31536000000)/2628000000);
  var days = Math.floor(((distance % 31536000000) % 2628000000)/86400000);
    
  // Output the result in an element with id="demo"
  document.getElementById("demo").innerHTML = years + " years, " + months + " months, " + days + " days ";
    
}, 1000);
</script>

</body>
</html>
Paul
  • 127
  • 1
  • 1
  • 7

2 Answers2

1

A year does not always have 365 days. Compared to the web site you refer to, there is also another difference:

Usually when people speak of "today it is exactly 1 month ago", they mean it was on the same month-date. So 14 March comes exactly 1 month after 14 February, and 14 April comes exactly 1 month after 14 March. This means the length of what a "month" is, depends on what your reference point is. In the example, the first difference is 28 days (in non-leap years), while the second is 31 days.

A solution that comes close to the results you get on the web site, can be achieved with this code:

function dateDiff(a, b) {
    // Some utility functions:
    const getSecs = dt => (dt.getHours() * 24 + dt.getMinutes()) * 60 + dt.getSeconds();
    const getMonths = dt => dt.getFullYear() * 12 + dt.getMonth();

    // 0. Convert to new date objects to avoid side effects
    a = new Date(a);
    b = new Date(b);
    if (a > b) [a, b] = [b, a]; // Swap into order 
    
    // 1. Get difference in number of seconds during the day:
    let diff = getSecs(b) - getSecs(a);
    if (diff < 0) {
        b.setDate(b.getDate()-1); // go back one day
        diff += 24*60*60; // compensate with the equivalent of one day
    }
    // 2. Get difference in number of days of the month
    let days = b.getDate() - a.getDate();
    if (days < 0) {
        b.setDate(0); // go back to (last day of) previous month
        days += b.getDate(); // compensate with the equivalent of one month
    }
    // 3. Get difference in number of months
    const months = getMonths(b) - getMonths(a); 
    return {
        years: Math.floor(months/12),
        months: months % 12,
        days, 
        hours: Math.floor(diff/3600),
        minutes: Math.floor(diff/60) % 24,
        seconds: diff % 60
    };
}

// Date to start on
var startDate = new Date("Jun 5, 2011 00:00:00");

// Update the count every 1 second
setInterval(function() {
    const diff = dateDiff(startDate, new Date);
    const str = Object.entries(diff).map(([name, value]) =>
        value > 1 ? value + " " + name : value ? value + " " + name.slice(0, name.length-1) : ""
    ).filter(Boolean).join(", ") || "0 seconds";  
    document.getElementById("demo").textContent = str;
}, 1000); 
<div id="demo"></div>

Some thoughts

This variable notion of month may lead to unexpected results when instead of the end date, you increase the start date one day at a time: the distance between Feb 28, 2019 and April 1, 2019 is reported as 1 month, 4 days. But when you add 1 day to the first date, the difference is reported as 1 month exactly. Where did those 3 days go? ,-)

So this solution (and the one on the referenced web site) works well when varying the end date. For situations where you would want to vary the start date with "logical" steps in the output, you would need a slightly different algorithm. But then you'll get such "jumps" when varying the end date.

For instance: 28 Feb 2019 - 1 April 2019. Is the difference 1 month + 1 day or 1 month + 4 days? If you think you have the answer, move one of those dates one day closer to the other... there is just no way to have a consistent output that also jumps with 1 day each time one of either dates is moved with 1 day.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • "*there is just no way to have a consistent output*", indeed. When writing rules for dates, it's always a business decision how to treat anomalies such as when does someone born on 29 February have have their birthday? Some use 28 Feb in non–leap years, others 1 Mar. Similarly, 31 May to 30 June might be one month, but 30 June to 30 July may not be, hence "end of month" processing likely occurs occurs on the last day of the month rather than a particular recurring date. :-) – RobG Mar 16 '19 at 22:16
0

Your logic is wrong. Your logic is valid only for years without a leap year as leap year contains one extra day. In your problem two leap years occur. so difference of two occurs