Search code examples
javascriptdateleap-year

Javascript calculate same weekday next year


I have some trouble to calculate the weekday of a given date next year. For example: Tuesday, 19. April 2016 is the given date. Now I would calculate: TUESDAY, 18. April 2017. It is very important that the weekdays are always the same.

My problem are the leap-years. I hope you could help me.

$('.changeYear').click(function() {
        var appointments = [];
        for (var i = 1; i <= 22; i++) {
            var date = $('#tr-fix-tag-' + i).val();
            if (date !== "") {
                var splittedDate = date.substr(5).split('.');
                appointments.push(new Date(splittedDate[2], splittedDate[1] - 1, splittedDate[0]));
            }
        }

        var counter = 1;
        $.each(appointments, function() {
            var field = $('#tr-fix-tag-' + counter);
            var date = $(this)[0];
            var newDate = new Date(date.setFullYear(date.getFullYear() + 1));

            if (isSchaltjahr(newDate.getFullYear()))
                field.val(formatDate(new Date(newDate.setDate(newDate.getDate() - 2))));
            else
                field.val(formatDate(new Date(newDate.setDate(newDate.getDate() - 1))));

            counter++;
        });
    });

Solution

  • If you want to add a year and keep the day the same, you can adjust the resulting date by however many days are required to the nearest date of the same day, e.g.

    function sameDayNextYear(d) {
      // Copy date
      var t = new Date(+d);
      // Get current day number
      var startDayNum = d.getDay();
      // Add one year
      t.setFullYear(t.getFullYear() + 1);
      // Move to closest day that is the same day number
      var diff = startDayNum - t.getDay();
      // If diff is more than 3 days, need to subtract rather than add
      diff = (diff > 3) ? diff-7 : diff;
      t.setDate(t.getDate() + diff);
      return t;  
    }
    
    [new Date(2016, 1, 13),  // Sat 13 Feb 2016 - Sat 11 Feb 2017
     new Date(2016, 1, 5),   // Fri 05 Feb 2016 - Fri 03 Feb 2017
     new Date(2016, 1, 6),   // Sat 06 Feb 2016 - Sat 04 Feb 2017
     new Date(2016, 1, 29),  // Mon 29 Feb 2016 - Mon 27 Feb 2017
     new Date(2016, 2, 1)]   // Tue 01 Mar 2016 - Tue 28 Feb 2017
     .forEach(function(d) {
      document.write(d + '<br>' + sameDayNextYear(d) + '<br><br>');
    });

    The above will work for any day in any year, leap or otherwise.

    However, for some dates this means it will go to the next or previous month (e.g. 2016-03-01 goes to 2017-02-28). If you don't want that to happen, you can compare the start and end months and either add or subtract a week to get back to the original month (so to 2017-03-07).