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
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');
Related
I am building backend queue system. My app's users need to automatically fetch data from server around 08:00:00 AM, individually for each time zone.
Every user needs to be assigned to a specific time a day. He can fetch data only at this time as the app uses API that has specific calls-per-minute limits.
How do I synchronize clients with server?
NOTE
I ran into specific problems, and solved it already. I am posting the solution right away as a complete answer that combines many answers I found on SO while solving it.
Core of the solution
For clarity use time values in UTC that is supported in each Java/PHP/MySQL, because:
Although GMT and UTC share the same current time in practice, there is a basic difference between the two:
GMT is a time zone officially used in some European and African countries. The time can be displayed using both the 24-hour format (0 - 24) or the 12-hour format (1 - 12 am/pm).
UTC is not a time zone, but a time standard that is the basis for civil time and time zones worldwide. This means that no country or territory officially uses UTC as a local time.
source
It gives you simple solution as once you use UTC, you only need to convert it to server's or clients' time zone for display purposes.
Managing client's time zone
You need to send client's time zone to backend to calculate what time do you want him to call API. You want to convert 08:00:00 local time to UTC, but here's a trick, because there are incompatible time zones' strings between Java and PHP.
// Java/Android
SimpleDateFormat sdf = new SimpleDateFormat("z");
I live in Poland, and using the code above I get 2 different values depending on seasons (CET for winter time and CEST for summer time).
// PHP
$tz1 = new DateTimeZone('CET');
$tz2 = new DateTimeZone('CEST');
The problem is that when I pass it to PHP, CET works perfectly as it's supported time zone string, but CEST is not.
To unify your code, you need to use:
// Java/Android
SimpleDateFormat sdf = new SimpleDateFormat("ZZZZ");
which gives you a time zone likethis:
GMT+01:00 // for CET
GMT+02:00 // for CEST
Remember that when you send it in URL like http://api.domain.com?timezone=GTM+02:00, you need to change + into %2B as timezone converted to GTM 02:00 won't work in PHP.
Calculating queue time for users
Once you get client's time zone, in PHP you convert 08:00:00 AM local time to UTC.
$tz = new DateTimeZone('GMT+02:00');
$dt = new DateTime('2017-03-30 08:00:00', $tz);
$dt->setTimezone(new DateTimeZone('UTC'));
echo $dt->format('H:i:s');
// echoes 06:00:00
Then you store calculated value in MySQL at type TIME column. You don't need to care about time zone in the database as TIME and DATE types are time zone independent.
Setting alarm at calculated UTC time
You get 06:00:00 as a response in the app, and you set AlarmManager using Calendar object like this:
// set UTC as a time zone
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTime(new Date());
long timeNow = cal.getTimeInMillis();
// set 06:00:00
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.HOUR_OF_DAY, 6);
// make sure to set alarm in future
long timeAlarm = cal.getTimeInMillis();
if (timeAlarm <= timeNow) {
cal.add(Calendar.HOUR_OF_DAY, 24);
}
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(),
24*60*60*1000, pintent);
The diffrence between 2 dates - current time and mysql time. This can be backdoored when user change his PC time and the code is Bypassing him from the diffrence check.
I've tried to use
mktime()
but its not working when my mysql date is 1451094007 (Sat, 26 Dec 2015 01:40:07 GMT) and real world time is for example 1451108407 (Sat, 26 Dec 2015 05:40:07 GMT) 4 hours later, and minimum difference is 10 hours user can still add some hours on him own PC and bypass time.
How can I get any world time which can't be manipulated?
You get all timezones using in the world store in array then run in loop
foreach($timezonearray as $timezone){
$time = new DateTime($timezone);
echo $time->format('Y-m-d H:i:s');
}
it will print result like this
http://www.timehubzone.com/worldclock
single way
$time = new DateTime('Africa/Abidjan');
echo $time->format('Y-m-d H:i:s');
you can get all time zones here
timezones list
You can use other services such as http://worldclockapi.com/
(see http://worldclockapi.com/api/json/utc/now)
Fetch the result and feed them to variable.
Basically, your application should use the server time where it's hosted (configured with server clock) and time() should have respected the server clock
I'm developing a website where I have to deal with different possible timezones from the users. This becomes a great problem since the website hosts time-delicate events like auctions.
All dates/times on the server are in UTC. Database stores everything in UTC timestamps. PHP default timezone is set to UTC too (date_default_timezone_set('UTC');).
Now, my problem is how I should interact with the users, whether I'm only showing a date or, more important, I'm reading a date/time from user input.
A concrete example:
An auction has a deadline, which I store in database as UTC.
When I view the auction on the website, a javascript timer uses a Date object to calculate the remaining time. It automatically converts the timezone to GMT+0100 (my local timezone). So if the deadline is '2013-08-08 10:46:08' (UTC), the javascript date object will return Aug 08 2013 11:26:15 GMT+0100 (GMT Standard Time).
If the current time is greater than 11:46:08 then the timer says that the remaining time is 00:00 (which is correct).
But if I try to insert a bid, the server accepts since the condition on the MySQL INSERT evaluates to true:
INSERT INTO Bids ... WHERE ... AND auction_deadline > NOW() ...
( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')
All this mumbo jumbo of timezone melts my brains. What am I missing here? I'm almost certain that storing all dates/times in UTC inside the database is the best. I just can't think crystal clear how do deal with it between the user and the database.
Your problem doesn't involve timezones at all, just the fact that clients can turn their clocks or have their clock skewed considerably. For that the fix is to poll the server every once in a while for an offset fix to use in calculations.
In fact, you don't even need date objects. There is a certain universal instant in time when the auction ends. Let's say it is 1375960662823. Right now, the universal instant in time is 1375960669199, so from that we see that the auction ends in 6 seconds (1375960662823 - 1375960669199 ~ 6000 ). It will end in 6 seconds regardless if I am in Morocco or Japan. Do you understand it yet?
To generate these numbers, on the client side you can call var now = Date.now() + skewFix where skewFix is the correction that needs to applied in case client has time skew or manually set their computer to wrong time.
In PHP, you can generate it with $now = time() * 1000;
This is rather a typical subject yet very complex for most to understand. First thing, you never mention the DAYLIGHT SAVING. yeah I am increasing your tension :).
Now let us see how we can do this. You did a good job by saving the Time in UTC. Now, I hope you have registered members and that each member has ability to set their preferred timezone, otherwise you will show Server' timezone based time to them.
When you through "start time" to user you must send them after converting UTC time to their time, similarly when you accept TIME from browser be it user action or javascript you need to convert that time to UTC considering the fact that user is that time zone that he select for his profile.
Hope that clear the idea on where you are going wrong? Please read through day light saving as that will play an important role too when you move ahead with other logic on same.
EDIT:
You can use javascript's Timezone offset, for auto submission and user input based on his settings.
Date in JavaScript uses local timezone. You should get UTC time for the user and send it to the server
new Date
Thu Aug 08 2013 17:00:14 GMT+0530 (India Standard Time)
(new Date("Thu Aug 08 2013 17:00:14")).toUTCString();
"Thu, 08 Aug 2013 11:30:14 GMT"
This will resolve the timezone issue between the server and client.
You said
( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')
In MySQL - NOW returns the current time in the server's local time zone (docs).
You probably want something like UTC_TIMESTAMP which returns the current time in UTC (docs).
Also - you probably shouldn't accept any input time from the client JavaScript at all. Only trust your own clock. When a bid is placed, use the time on your server in MySQL or in PHP. Don't accept it as input.
You can do the following
once page is loaded, send an ajax request to server with timezone offset of user. You can get timezone offset using the following code.
var curdate = new Date()
var offset = curdate.getTimezoneOffset()
offset is timezone offset in minute.
I think it will help.
everytime when you get the date from the clientside, you can use the getUTC to convert to UTC date ie:
var todayDate = new Date();
var todayDateInUTC = new Date(todayDate.getUTCFullYear(), todayDate.getUTCMonth(), todayDate.getUTCDate(), todayDate.getUTCHours(), todayDate.getUTCMinutes(), todayDate.getUTCSeconds());
so right before you insert the bid date to database, use the getUTC functions to convert it into UTC format.
I have a web application that allows users to select to have a certain operation performed at a specific hour on a specific weekday (ex: 7pm Friday) -- recurring every weekday. My users are located in different timezones. Therefore I would like to store the day/hour in one time zone format so that my cron job which runs hourly can query my database and quickly grab all the rows that represent tasks to be performed that hour. What's the best way to accomplish this?
Basically I need to know how to take
Friday 7:00pm in Boston, MA or Saturday 3:00pm San Francisco, CA and convert both to GMT (and store in my DB). That way when I run my cron job once an hour I know exactly what value to query the database for given what GMT day/hour it currently is.
EDIT 1
Through playing around I came up with something:
date_default_timezone_set('America/New_York');
$time = strtotime('Friday 8:00pm');
echo date('w : G', $time);
echo '<br>';
date_default_timezone_set('GMT');
$date = date('w : G', $time);
echo $time;
echo '<br>';
echo $date;
The output is:
5 : 20
1331942400
6 : 0
Is this basically the right track?
EDIT 2
Useful detail, I'm actually lucky enough to have my user's timezone information stored as one of these:
http://www.php.net/manual/en/timezones.php
If you store the users time zone already, you can add the GMT offset to the time to get the GMT date.
I'm located in Colorado which is currently -7 GMT:
$offset = -7;
$gmt = ($offset * 60 * 60) + time();
would give the the unix timestamp for the GMT timezone.
Then make sure your server has GMT as the default or set timezone, you can set the timezone using:
date_default_timezone_set('GMT');
I am working on a project where i need to SHOW the visitor of the website a message in the contacts area like:
Contact no: +91-99-3241-5285 [You can call us now]
The message is highlighted in the above line, now my question is, how to compare the user's time zone with the working hours of the company's office.
P.S. - Suppose the company is in INDIA, and its working hours are 9.00am to 5.00pm.
Any suggestions?
Use javascript to determine the users timezone offset:
http://www.w3schools.com/jsref/jsref_gettimezoneoffset.asp
var d = new Date()
var gmtHours = -d.getTimezoneOffset()/60;
document.write("The local time zone is: GMT " + gmtHours);
Then calculate e.g. the current time in INDIA (GMT + 5:30 if i'm not wrong) and show "you can call us now" if the resulting time is within the working hours.
var diff = gmtHours - 5.5; // -> difference between users timezone and india in hours
var indiaDate = new Date();
indiaDate.setTime(d.getTime() - (diff * 60 * 60 * 1000));
document.write("<br />Current time in India: " + indiaDate.toString());
See the working demo at: http://jsfiddle.net/roberkules/RLsw9/
The replies immediately below your question are correct. There should be no need to know the client's time zone to calculate whether or not the current time is within hours of operation. It doesn't really matter whether it's currently 8:00am US Pacific, 11:00am US Eastern, or 11:00pm in Manila, Philippines. The important thing is what time it is relative to the business hours, not relative to the client.
Typically on all web servers I run, I set the server time to UTC. When people enter their hours, either have them enter it in GMT or, if you want them to be able to enter the hours in their local time, have a time zone list or combo box on the page. You can use PHP's DateTimeZone::listAbbreviations() function to help.
So, for example, say someone enters that their hours are from 9:00am to 5:00pm in the Asia/Calcutta time zone. When you're using the time for calculations, do something like this, assuming you have rows named something like hrs_start, hrs_end, and hrs_tz:
$hrs_tz = new DateTimeZone($row['hrs_tz']);
$hrs_start = new DateTime($row['hrs_start'], $hrs_tz);
$hrs_end = new DateTime($row['hrs_end'], $hrs_tz);
Now you can use these hours to calculate whether or not the hours are in or out of their business hours.