EDIT: I eventually found the solution, posting here in case someone might find it useful. The short version is that JavaScript dates are a pain to work with.
ORIGINAL POST:
I'm making a web page that calculates whether or not it is recycling week, and if it is, which neighborhood is scheduled for pickup.
This demo uses the first day of a previously scheduled recycling week as the date of demarcation and counts in 14 day increments from that date. Every 14th day represents the start of a new recycling week. The message displayed changes depending on the time of day and what day of the week it is.
The issue I was running into was that the start date for the next recycling week would be incorrect for a few hours each day. I figured it was a time zone thing, but setting the time zone on the demarcation date produced the same result.
In the end I ended up changing the date format on the demarcation date and it worked.
I went from this...
var demarcationdate = new Date("2017-03-13");
...to this...
var demarcationdate= new Date("2017-03-13").toLocaleString("en-US", {timeZone: "America/New_York"});
...to this, which finally worked.
var demarcationdate = new Date("March 13, 2017 00:00:00");
Here's a link to the demo on CodePen: https://codepen.io/mikejandreau/pen/MxZmZq
The HTML:
<header class="masthead" id="map">
<div class="container h-100">
<div class="row h-100 align-items-center">
<div class="col-12 text-center text-white">
<h1 class="display-4 mb-4">
<span id="greeting" class="greeting"></span>
</h1>
<p class="lead">
<span id="todaysDate"></span>
<span id="neighborhood"></span>
<span id="futureDate"></span>
</p>
<p>
<span id="followingWeek"></span>
</p>
</div>
</div>
</div>
</header>
The CSS (not really important, but here it is anyway):
#map {
height: 100%;
height: 100vh;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
The JS:
// greeting based on time of day
var thehours = new Date().getHours();
var greeting = document.getElementById('greeting');
var themessage;
var morning = ('Good morning!');
var afternoon = ('Good afternoon!');
var evening = ('Good evening!');
if (thehours >= 0 && thehours < 12) {
themessage = morning;
} else if (thehours >= 12 && thehours < 17) {
themessage = afternoon;
} else if (thehours >= 17 && thehours < 24) {
themessage = evening;
}
greeting.innerHTML= themessage; // show greeting, always on
// neighborhood for day of week
var scheduleCurrentDate = new Date();
var scheduleAllDays = [
{
day: "Sunday",
neighborhood: "recycling pickup is scheduled for the <strong>Fairmount Neighborhood</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Sunday+Image"
},
{
day: "Monday",
neighborhood: "recycling pickup is scheduled for the <strong>West Market Neighborhood</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Monday+Image"
},
{
day: "Tuesday",
neighborhood: "recycling pickup is scheduled for the <strong>Union Street Neighborhood</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Tuesday+Image"
},
{
day: "Wednesday",
neighborhood: "recycling pickup is scheduled for the <strong>Broadway and State Street Neighborhoods</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Wednesday+Image"
},
{
day: "Thursday",
neighborhood: "recycling pickup is scheduled for the <strong>Downtown Neighborhood</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Thursday+Image"
},
{
day: "Friday",
neighborhood: "recycling pickup is scheduled for the <strong>East Hills Neighborhood</strong>",
image:
"https://via.placeholder.com/1920x1080/555555/666666/?text=Friday+Image"
},
{
day: "Saturday",
neighborhood: "recycling pickup is scheduled for the <strong>Kenduskeag Neighborhood</strong>",
image:
"https://via.placeholder.com/450x800/555555/666666/?text=Saturday+Image"
}
];
// document.getElementById("day").innerHTML = scheduleAllDays[scheduleCurrentDate.getDay()].day;
// document.getElementById("neighborhood").innerHTML = scheduleAllDays[scheduleCurrentDate.getDay()].neighborhood + " (excluding holidays). ";
document.getElementById("map").style.background =
"url('" + scheduleAllDays[scheduleCurrentDate.getDay()].image + "') no-repeat center"; // show background image, based on day of the week
// calculate bi-weekly schedule
function treatAsUTC(date) {
var result = new Date(date);
result.setMinutes(result.getMinutes() - result.getTimezoneOffset());
return result;
}
function daysBetween(startDate, endDate) {
var millisecondsPerDay = 24 * 60 * 60 * 1000;
return Math.floor((treatAsUTC(endDate) - treatAsUTC(startDate)) / millisecondsPerDay);
}
// start date based on most recently scheduled recycling week
var demarcationdate = new Date("March 13, 2017 00:00:00"); // start date based on previously scheduled recycling week
showTodaysDate = document.getElementById('todaysDate'),
showNeighborhood = document.getElementById('neighborhood'),
showFutureDate = document.getElementById('futureDate'),
nextWeekBegins = document.getElementById('followingWeek'),
monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
today = new Date(),
days = daysBetween(demarcationdate,today),
daystill = 14 - days%14,
rec = days%14==0,
d = new Date();
// add remaining days to current date to get next recycling week start date
d.setDate(today.getDate() + daystill);
// format dates to make them easy to read
var currentDate = (dayNames[today.getDay()] + ", " + monthNames[today.getMonth()] + " " + today.getDate() + ", " + today.getFullYear());
var nextDate = (monthNames[d.getMonth()] + " " + d.getDate());
// show current date, always on
showTodaysDate.innerHTML="Today is "+currentDate.toString()+", and ";
// show start date of next recycling week and days remaining, always on
nextWeekBegins.innerHTML="The next recycling week begins " + dayNames[d.getDay()] + ", " + nextDate.toString() + " ("+daystill+" days from now)."
// Conditional display rules
var date1 = new Date(today); // today's date
var date2 = new Date(d); // day next recycling week starts
var timeDiff = Math.abs(date2.getTime() - date1.getTime()); // caluclate time between two dates
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)); // convert that time to days
if (diffDays <= 7) {
// if (rec === true) { // ignore this, it's just to test 'showNeighborhood'
// if it is not a recycling week, show the start date of the following recycling week
showFutureDate.innerHTML="there is <strong>no recycling pickup</strong> scheduled this week.";
} else {
// if it is a recycling week, show scheduled neighborhood
showNeighborhood.innerHTML = scheduleAllDays[scheduleCurrentDate.getDay()].neighborhood + " (excluding holidays). ";
}