1

I've written an app in Javascript which countdowns to various days (Christmas, Paddy's Day, etc.). I have two problems:

Problem 1:

It works fine on Chrome, but the times are displayed as "NaN" on Safari (iPhone).

I've seen other solutions on OS suggesting to change the date format to include "/" instead of "-" to format the date, but this didn't work for me (or else I'm misunderstanding something).

Problem 2

The countdown does not automatically count down in real time for the paddysDay() function. If I click the button, it updates. The other two functions update automatically every 1000ms. I'm using the exact same setTimeout for all three functions so I can't fathom why it's not working in paddysDay().

Here is the code. Please note that in the xmas() function, I've formatted the date using "/" instead of "-". This format does not work in Chrome OR Safari.

<body>

<fieldset>
<legend><h2>How Many Sleeps Until...?</h2></legend>

<center>
<button onclick = "xmas()">Christmas</button>
<p id="xmas" style="text-align:left;"></p>
<br/>

<button onclick = "myBday()">My Birthday</button>
<p id="myBday" style="text-align:left;"></p>
<br/>

<button onclick = "paddysDay()">Paddy's Day</button>
<p id="paddysDay1" style="text-align:left;"></p>
<p id="paddysDay2" style="text-align:left;"></p>

<br/>

<button onclick = "yourBday()">Your Birthday</button>
<p id="yourBday" style="text-align:left;"></p>
<br/>

</center>

<script>

function xmas() {
  var rightNow = new Date();
  var currentMonth = (rightNow.getMonth()+1);
  var currentDay = rightNow.getDate();

  var nextXmasYear = rightNow.getFullYear();
    if (currentMonth == 12 && currentDay > 25) {
      nextXmasYear++;
    };

  var nextXmasDate = nextXmasYear + '/12/24T23:59:99.999z';
  var xmasDay = new Date(nextXmasDate);

  var diffSeconds = Math.floor((xmasDay.getTime()-rightNow.getTime())/1000);
  var days = 0;
  var hours = 0;
  var minutes = 0;
  var seconds = 0;

  if (currentMonth != 12 || (currentMonth == 12 && currentDay != 25)) {
    days = Math.floor(diffSeconds / 86400);
    diffSeconds -= days * 86400;
    hours = Math.floor(diffSeconds / 3600);
    diffSeconds -= hours * 3600;
    minutes = Math.floor(diffSeconds / 60);
    diffSeconds -= minutes * 60;
    seconds = diffSeconds;
  }

  document.getElementById("xmas").innerHTML = "You've got " + days + " days, " + hours + " hours, " + minutes + " minutes, and " + seconds + " seconds until Christmas.";


setTimeout(xmas, 1000);

}


function myBday() {
  var rightNow = new Date();
  var currentMonth = (rightNow.getMonth()+1);
  var currentDay = rightNow.getDate();

  var nextBdayYear = rightNow.getFullYear();

    if (currentMonth > 7 || currentMonth == 7 && currentDay >= 14) {
      nextBdayYear++;
    };

  var nextBdayDate = nextBdayYear + '-07-14T00:00:00.000z';
  var bdayDay = new Date(nextBdayDate);

  var diffSeconds = Math.floor((bdayDay.getTime()-rightNow.getTime())/1000);
  var days = 0;
  var hours = 0;
  var minutes = 0;
  var seconds = 0;

  if (currentMonth != 7 || (currentMonth == 7 && currentDay != 14)) {
    days = Math.floor(diffSeconds / 86400);
    diffSeconds -= days * 86400;
    hours = Math.floor(diffSeconds / 3600);
    diffSeconds -= hours * 3600;
    minutes = Math.floor(diffSeconds / 60);
    diffSeconds -= minutes * 60;
    seconds = diffSeconds;
  }

  document.getElementById("myBday").innerHTML = "You've got " + days + " days, " + hours + " hours, " + minutes + " minutes, and " + seconds + " seconds to find me a gift.";


setTimeout(myBday, 1000);

}


function paddysDay() {
  var rightNow = new Date();
  var currentMonth = (rightNow.getMonth()+1);
  var currentDay = rightNow.getDate();

  var nextPaddysYear = rightNow.getFullYear();

    if (currentMonth > 3 || currentMonth == 3 && currentDay >= 17) {
      nextPaddysYear++;
    };

  var nextPaddysDate = nextPaddysYear + '-03-17T00:00:00.000z';
  var paddysDay = new Date(nextPaddysDate);

  var diffSeconds = Math.floor((paddysDay.getTime()-rightNow.getTime())/1000);
  var days = 0;
  var hours = 0;
  var minutes = 0;
  var seconds = 0;

  if (currentMonth != 3 || (currentMonth == 3 && currentDay != 17)) {
    days = Math.floor(diffSeconds / 86400);
    diffSeconds -= days * 86400;
    hours = Math.floor(diffSeconds / 3600);
    diffSeconds -= hours * 3600;
    minutes = Math.floor(diffSeconds / 60);
    diffSeconds -= minutes * 60;
    seconds = diffSeconds;
  }

  document.getElementById("paddysDay1").innerHTML = "You've got " + days + " days, " + hours + " hours, " + minutes + " minutes, and " + seconds + " seconds until ...";

setTimeout(paddysDay, 1000);

}

function yourBday(){
  document.getElementById("yourBday").innerHTML = "I don't even know who you are, let alone your birthday. Dear Lord, who do think I am? Mark Zuckerberg?";
return;
}

</script>


</fieldset>

<br/>
<div style="height:500px;">
<iframe src="intro"></iframe>
</div>

</body>

Thank you! This is driving me insane!

  • Please don't ask multiple questions in a post, and also reduce your code to the minimum required to demonstrate the issue. – RobG Feb 23 '20 at 12:11

1 Answers1

3

You have bumped up against the fact that date-string parsing is still not completely standardized across browsers. This format (all three variations) is cross-browser-safe:

  • 2011-10-10
  • 2011-10-10T14:48:00
  • 2011-10-10T14:48:00.000+09:00

Some browsers are happy to parse some other formats (such as the 2020/12/24T23:59:99.999z format you use in your code), but the above ones are the ones to use if you want to be fully cross-platform. I'm assuming iPhone Safari is one of the ones that doesn't like the format you're using. Even if it does, other browsers will choke on your format.

EDIT: Also - there are several third-party libraries that make comparing dates and such much, much easier so individual developers don't have to reinvent the wheel every time they want to do what should be fairly simple date-related logic. Moment.js is hugely popular, and there are others.

Hope this helps!

avocadatoria
  • 493
  • 3
  • 9
  • 1
    Thanks for your response @avocadatoria! I think I use the format that you suggested in my second and third functions (myBday()) and paddysDay()) but and they also don't work in Safari. Any idea why this could be?? I'm not entirely sure how to use libraries yet (I am a total newbie!) but I'll take a look at Moment.js. Thanks again :) – geoffpevlin Feb 22 '20 at 22:19
  • @geoffpevlin not sure why Safari would be choking on those, but glad you're looking at moment.js; it's a good lib to know about. Among other things, it also handles cross-browser inconsistencies, so if Safari in particular still gives you trouble when using it, you can be pretty sure that your `NaN` value is coming from somewhere else. (Unless I'm missing something; entirely possible!) – avocadatoria Feb 23 '20 at 04:02
  • Also @geoffpevlin, you're not quite using the cross-browser format for those other two functions either. You're using `2020-07-14T00:00:00.000z`, which is close to the long form of the standard format (`2011-10-10T14:48:00.000+09:00`) but not quite there. (The "z" means "Zulu" aka GMT time but I believe you need to "spell it out," so to speak: "+00:00" instead of "z"; again, though, the moment.js docs will tell you what formats it can parse.) – avocadatoria Feb 23 '20 at 04:11
  • Please don't suggest using the built–in parser, even for formats supported by ECMA-262. E.g. Safari parses 2011-10-10T14:48:00 as UTC, not local so it's not "safe". – RobG Feb 23 '20 at 12:15