Use UTC Time to avoid timezone issues
People in different timezones will see different values for the current date and hour in JavaScript even when viewing the web page simultaneously. This is determined by the user's current timezone as specified on their system.
Generally, when counting down to a specific date, you want the countdown to be the same for everyone, no matter their system's timezone. You can use UTC times to retrieve, set, and compare time values against Universal Coordinated Time (which roughly corresponds to the old standard Greenwich Mean Time (GMT) but ignores daylight savings time).
If you have a date object, you can call myDateObject.toUTCString()
to see what time it corresponds to in UTC. You can also call all the expected getter and setter functions to retrieve or update specific components of the object, such as .getUTCFullYear()
, .getUTCMonth()
, etc.
I would create a startDate
variable using var startDate = new Date()
and then set its date components using the UTC setters. You'll then be able to compare the current date against that variable and JavaScript will be smart enough to take timezone differences into account.
var currDT = new Date();
document.getElementById("hour").value = currDT.getHours();
document.getElementById("minute").value = currDT.getMinutes();
document.getElementById("second").value = currDT.getSeconds();
document.getElementById("date").value = currDT.getDate();
document.getElementById("month").value = currDT.getMonth();
document.getElementById("year").value = currDT.getFullYear();
document.getElementById("submit").addEventListener("click",function(){
var hour = document.getElementById("hour").value;
var minute = document.getElementById("minute").value;
var second = document.getElementById("second").value;
var date = document.getElementById("date").value;
var month = document.getElementById("month").value;
var year = document.getElementById("year").value;
var utcDateTime = new Date();
utcDateTime.setUTCFullYear(year);
utcDateTime.setUTCMonth(month);
utcDateTime.setUTCDate(date);
utcDateTime.setUTCHours(hour);
utcDateTime.setUTCMinutes(minute);
utcDateTime.setUTCSeconds(second);
utcDateTime.setUTCMilliseconds(0);
document.getElementById("output").innerHTML = utcDateTime.toUTCString() + " is equivalent to " +utcDateTime.toString();
});
.table {display:table;}
.row{display:table-row;}
.cell{display:table-cell;font-family:courier;}
What UTC date would you like to see represented in local time?<br/>
<div class="table">
<div class="row">
<div class="cell">
D:<input id="date"/><br/>M:<input id="month"/><br/>Y:<input id="year"/>
</div>
<div class="cell">H:<input id="hour"/> <br/>M:<input id="minute"/> <br/>S:<input id="second"/></div>
</div>
</div>
<input type="button" id="submit" value="Show me UTC Time!"/>
<div id="output"></div>
This brings me to my next point...
Date objects can be compared directly
Instead of comparing hours to hours, years to years, months to months, and so on, you can compare two date objects directly to see which one comes earlier or later. You can even subtract one date object from the other to find the time (in milliseconds) between the two dates.
The code below will populate the dateDifference
variable with a number representing the number of days since the sale started (assuming startDate
is the sale's start date and currentDate
is the current date).
var dateDifference = (currentDate - startDate) / 86400000 >>> 0;
We divide it by 86,400,000 just to convert milliseconds to days. The ... >>> 0
bitwise operation just truncates off any decimals for us, converting the number to an integer.
If the sale hasn't started yet, dateDifference
will be a negative number; otherwise it well tell us which day of the sale we're currently on (using array index notation, so 0
for the first day, 1
for the second day, and so on).
Hopefully that's got you thinking about neat ways to programmatically determine which elements to show or hide.
Try not to repeat yourself, especially when it comes to strings
It's not much fun to have to go through your code and update a bunch of strings when something changes nine months down the road. You can make it easier on yourself by storing repeated strings of text into variables.
var expiredClass = "bem-sale-week--item-expired";
var openClass = "bem-sale-week--item-open";
Since these are constants, a common standard is to name the variables with all capital letters; you can do that if you find it helpful, but the important thing is to be internally consistent.
I would take this concept (of capturing reusable strings in variables) a step farther for the element IDs of your daily deals, and throw them into an array of objects.
var dayElements = [
{id: "day-one",list: "day-one-list"},
{id: "day-two",list: "day-two-list"},
{id: "day-three",list: "day-three-list"},
{id: "day-four",list: "day-four-list"},
{id: "day-five",list: "day-five-list"}];
This gives us a few nice advantages. Remember how earlier I said you could store the current day of the sale in a dateDifference
variable? Well, you could use that to access the corresponding day and list elements without having to create a bunch of else if
statements.
Your final SetDivContent
method might end up looking like this:
function SetDivContent() {
var currentDate = new Date();
var dateDifference = (currentDate - startDate) / 86400000 >> 0;
if (dateDifference < 0) { // sale hasn't started yet
document.getElementById("bem-sale-week-tocome").className = "show";
} else if (dateDifference >= dayElements.length) { // sale is over
document.getElementById("bem-sale-week-ended").className = "show";
} else {
document.getElementById(dayElements[dateDifference].list).className += "open";
}
for (var i = 0; i < dayElements.length; i++) {
if (dateDifference === i) {
document.getElementById(dayElements[i].id).className = openClass;
} else if (dateDifference > i) {
document.getElementById(dayElements[i].id).className = expiredClass;
}
}
}
This way your script is almost good to go if you decide to have another sale that spans a different number of days. You'd just need to update the dayElements
array to reflect the elements on the page (and update the startDate
of course).