1

I'm trying to display a chat div that displays between the hours of 8am-6pm Monday to Friday "Online" or show nothing if offline, based on the Eastern Time Zone (NYC), so that customers from Beijing will see Online or Offline based on these hours.

Simply need to show() or hide() the div. So far I have the hours, but I'm not sure how to get them to be in relation to the user time-zone.

$(document).ready(function () {

var start = new Date();
var end = new Date();
var time = new Date().getTime();

if (time > start.setHours(8,00) && time < end.setHours(18,00)) {
    $('.online').show();
}
else {
    $('.offline').hide();
    }
});
benvc
  • 14,448
  • 4
  • 33
  • 54
  • Possible duplicate of [Getting the client's timezone in JavaScript](https://stackoverflow.com/questions/1091372/getting-the-clients-timezone-in-javascript) – Juan Sep 12 '18 at 20:39
  • If you specifically want to cater for the US Eastern Standard Time (UTC-0500), that has been answered many times. However, if what you really want is the time in New York and hence cater for daylight saving offsets, you need a database of historic timezone changes. Likely the easiest solution it to use a library like [*moment-timezone*](https://momentjs.com/timezone/) or [*Luxon*](https://moment.github.io/luxon/), which has built–in support for timezones. – RobG Sep 12 '18 at 22:16
  • Confusing question. You want the Chat to appear 8–6 New York time, or Beijing time? – Stephen R Sep 12 '18 at 22:43
  • It needs to be in New York Time. – quicklaunch2009 Sep 13 '18 at 13:19

3 Answers3

0

The previous answer (seen in edit history) was to use the offset from UTC, however that isn't going to be an option if you want to support Daylight Savings; which is an important thing to do.

As such, the modification to the previous suggestion completely removes the use of UTC. To support daylight savings, the only proper way to get the time from EST is going to be to set the locale to that location, read the time, set up a new date object (which will technically be set up in the client local, but all we really want from it are the day and hour response from the Date object so we will ignore that technicality).

This is done by passing an object with the toLocaleString call which specifies the timezone, and then constructing a new date with the result of that.

var NYDate = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));

var NYHour = NYDate.getHours();
var NYDay = NYDate.getDay()

if (NYHour >= 8 && NYHour <= 18 &&
    NYDay > 0 && NYDay < 6) {
    $('.online').show();
}else {
    $('.online').hide();
}
.online { 
  display: none;
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="online">Online</div>
Travis J
  • 81,153
  • 41
  • 202
  • 273
  • This approach may need to be modified if you want to account for changes due to daylight savings time. New York is on EST (UTC -5) in the winter and EDT (UTC -4) in the summer. – benvc Sep 12 '18 at 21:10
  • Good point with regards to Daylight savings. That would need to be considered. I will edit that in momentarily. – Travis J Sep 12 '18 at 21:14
  • What about sticking closer to the original approach with a little hack to get the current New York timezone so you can just adjust the hours based on whether it returns "EDT" or "EST". Using something like `new Date().toLocaleString('en-US', { timeZone: 'America/New_York', timeZoneName: 'short' }).substr(-3)`? – benvc Sep 12 '18 at 21:37
  • @benvc - Can't really do that because it returns a string from `toLocaleString`. – Travis J Sep 12 '18 at 21:43
  • Right, I am basically suggesting that you parse the string (with the `substr` bit at the end) just to figure out the current timezone and then use that value to do something like `'let offset = (tz === 'EDT') ? -4 : -5'` to get the right timezone offset for your calc. Reason is that I think the `new Date(new Date().toLocaleString(...))` approach is going to convert the eastern time string back to local time and mess up the resulting hour value you are relying on. I could be wrong as I haven't tested to be sure. – benvc Sep 12 '18 at 21:55
  • 1
    This is not a good approach as the *timeZone* option is not widely supported and also implementations are not required to parse the output of *toLocaleString* (which makes sense because the content and formatting is not standardised). – RobG Sep 12 '18 at 22:18
  • @benvc—the format of the string generated by *timeZoneName* is not standardised and is not consistent across implementations. – RobG Sep 12 '18 at 22:22
  • @RobG you are right. Quick test shows that current versions of Firefox, Chrome, and Edge place the short `timeZoneName` at the end of the string for `en-US` formats but anyone looking to roll their own here should consult the [browser compatibility chart](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString#Browser_compatibility). This may be one of those where you just need something like [moment.js](https://momentjs.com/) or have to write a slightly more involved function that calcs the daylight savings date changes for eastern time. – benvc Sep 12 '18 at 22:38
0

No JavaScript needed. You should do this from the server side. (The customer doesn’t tell the store when it’s open, the store tells the customer!)

Assuming your HTML is being generated by some server-side language (PHP, Ruby, etc), set the program to use New York time, and simply calculate if you’re within the “open” times. If you’re open, generate the Chat div. if you’re closed... don’t.

(Or alternately, show/hide it via CSS and classes)

Stephen R
  • 3,512
  • 1
  • 28
  • 45
  • 1
    A server oriented solution is a good idea, since the OP doesn't know how accurate the client's system clock is. The logic can be as simple as passing the required offset to the client, or just don't include the chat thing during the "closed" period. – RobG Sep 13 '18 at 01:07
0

Turns out that this is not a completely trivial task using JavaScript (as noted in the answer from @StephenR, this may be easier to deal with server side). And as noted in some of the comments, using a library may be the better js approach.

That said, after thinking a bit about the comments from @RobG regarding varying browser support for options like timeZone in toLocaleString, I was curious what it would take to solve this another way (makes me grateful for the various js date libraries). Snippet below...

const getOffset = (month, date, day, hour) => {
  // assume EST offset
  let offset = 5;
  // adjust to EST offset as needed
  if ((month > 2 && month < 10) || (month === 2 && date > 14)) {
    offset = 4;
  } else if (month === 2 && date > 7 && date < 15) {
    if ((day && date - day > 7) || (day === 0 && hour - offset >= 2)) {
      offset = 4;
    }
  } else if (month === 10 && date < 8) {
    if ((day && date - day < 0) || (day === 0 && hour - offset < 1)) {
      offset = 4;
    }
  }
  
  return offset;
};

const isOnline = () => {
  const dt = new Date(); // current datetime
  let year = dt.getUTCFullYear(); // utc year
  let month = dt.getUTCMonth(); // utc month (jan is 0)
  let date = dt.getUTCDate(); // utc date
  let hour = dt.getUTCHours(); // utc hours (midnight is 0)
  let day = dt.getUTCDay(); // utc weekday (sunday is 0)
  let offset = getOffset(month, date, day, hour);
  if (hour - offset < 0) {
    hour = 24 + hour - offset;
    day = day ? day - 1 : 6;
    if (date === 1) {
      if (!month) {
        year -= 1;
        month = 11;
      } else {
        month -= 1;
      }
      
      date = new Date(year, month + 1, 0).getDate();
    } else {
      date -= 1;
    } 
  } else {
    hour -= offset;
  }
  
  if (day > 0 && day < 6 && hour > 7 && hour < 19) {
    return true;
  }
  
  return false;
};


if (isOnline()) {
  console.log('online'); // handle online
} else {
  console.log('offline'); // handle offline
}
benvc
  • 14,448
  • 4
  • 33
  • 54