2

Hello stackoverflow community.

I develop a web app and the concept is to display historical currency exchange rates based on time series from past.

For example a user may request exchange rates from 22 May 2020 13:00 to 26 MAY 2020 22:00. Then my backend run a loop and get the rates between those two date times each hour.

All rates in database stored in GMT time zone.

And here is the problem. Let's suppose a user make a request from a time zone offset +10:00. So if this user pick as last date time 26 MAY 2020 22:00, I guess I should grab from my database the rate in 26 MAY 2020 12:00, so to subtract 10 hours.

May this sound stupid, but I'm stuck with this.

What is my logic:

a) Get the users time zone offset via javascript in front-end

var get_timezone_offset = new Date().getTimezoneOffset();

var hrs = parseInt(-(timezone_offset / 60));

var mins = Math.abs(timezone_offset % 60);

var timezone_offset = hrs + ':' + mins;

b) Send users time zone offset to my backend

c) Get rates from my database and convert date stored from GMT to users time zone offset via PHP's Datetime object

$date = new \DateTime('2020-05-26 22:00');

$date->modify(-10 hours);

$date->format('Y-m-d H:i:s');

Is this right? I won't display wrong rates to my users.

Thank you in advance

Vasileios Tsakalis
  • 1,101
  • 2
  • 11
  • 25
  • 2
    The way I handle datetimes is everyone on the server and in the database is ALWAYS UTC. It expects to receive inputs in UTC and outputs are UTC. The client (the javascript front-end) handles display... so that's what should convert dates to the user's timezone. I use moment-timezone for easily converting from UTC to local time. Storing everything on the server in UTC saves a lot of headaches with confusion & daylight savings time – DanielRead May 28 '20 at 16:21
  • 2
    Also, no, your solution wouldn't be correct because simply subtracting 10 hours doesn't account for daylight savings time – DanielRead May 28 '20 at 16:22
  • @DanielRead Thank you very much Daniel. Also I mentioned there are cities with same UTC but with different time. For example Athens Greece has UTC +02:00 and now is 19:30, Cairo Egypt has UTC +02:00 and now is 18:30. So confusing :) – Vasileios Tsakalis May 28 '20 at 16:29
  • 1
    Correct, that's because Athens is currently in daylight savings time +1, while Cairo is not. So the database might store a date like 2020-05-28 00:00:00 for both of them as their UTC datetime, but when you convert it into their local time with moment-timezone, Athens would display "2020-05-28 03:00:00" and Cairo would display "2020-05-28 02:00:00" because it takes daylight savings time into account – DanielRead May 28 '20 at 16:40
  • 1
    @DanielRead Thank you very much!!! – Vasileios Tsakalis May 28 '20 at 16:43

1 Answers1

2

Please read the timezone tag wiki, especially the section titled "Time Zone != Offset". In short, you cannot assume the offset taken now from the user is the same one that will apply at any other point in time.

A simple example is for time zones like America/New_York, which presently is UTC-4, but will switch to UTC-5 when daylight saving time ends in November. But besides DST, many time zones have had changes in their standard time offsets.

Instead of getting the current numeric offset, get the IANA time zone identifier from the browser.

const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
// example: "America/New_York", "Asia/Kolkata", "Europe/Athens", etc.

Then you can use this identifier with PHP's built-in time zone support. For example, the following converts from a local time in a given time zone to the equivalent time in UTC:

$tz = new DateTimeZone("America/New_York");
$date = new DateTime('2020-05-26 22:00', $tz);
$date->setTimeZone(new DateTimeZone("UTC"));
echo $date->format('Y-m-d H:i:s');
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Thank you very much Matt. You're right. But how we handle with browsers that doesn't support IANA time zone identifier, like IE 6-10 – Vasileios Tsakalis May 28 '20 at 17:01
  • 2
    @VasileiosTsakalis Try polyfill such as this one https://github.com/formatjs/date-time-format-timezone to support older browsers – Vinay May 28 '20 at 17:36
  • 1
    There's also [jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect), and [Moment-Timezone](https://momentjs.com/timezone/) which has `moment.tz.guess()`. But really - who is still running IE6?? :) – Matt Johnson-Pint May 28 '20 at 17:39
  • @MattJohnson-Pint Thank you very much :) – Vasileios Tsakalis May 28 '20 at 17:44