I am developing a web application in which remainders will be sent to subscribers at a particular time of the day. Let's say a person John fills a form and asks to send email remainder at 12 pm every day. I have developed a cron job for this purpose but I am having issues related to time. Here is my problem if John is from USA then the email have to be sent according to US time and so on. Now I use MYSQL to store the time zone and Time from each person. But How do I schedule the emails according to specific time zone. My server time is set to UTC. So if a person has time zone of GMT +5 how many hours I have to add in the UTC so that emails should be sent at correct time.
I don't need the code just give me a common formula to calculate the correct time of email.
Thanks a lot,
Ahmar.
Take a look at the convert-tz function.
mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
-> '2004-01-01 13:00:00'
mysql> SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');
-> '2004-01-01 22:00:00'
Don't calculate it, use the database. Mysql has the best timezone support of any of the mainstream RDBMS. Its even better than Oracle as far as having sensible ways of updating its database from Olson.
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_convert-tz
Should give you a clue.
Related
What to accomplish:
I want to export the user's activity (from the previous week) every monday morning between 4 and 5 am respecting the user's local timezone.
Issue:
Timezones..
Situation:
I'm running a PHP web service with the timezone set to UTC for the script and MySQL database. So all timestamps in the system are set to UTC and the user's timezone is stored with their account information.
I have a CRON scheduled to run and call the script every hour at the 30 minute mark.
Now the step I'm "stuck" at is on the part on how to determine if there are users in the system with a timezone set where it is currently between 04 and 05 am on a monday (when it's 19:30 UTC time for the server for example).
Current solution:
Thanks to #deceze in the comments for this suggestion!
(which seems to be an efficient way or at least the most logical way, which I completely skipped for some reason)
Do the timezone conversion on database level to filter the users.
WHERE
DATE_FORMAT(CONVERT_TZ(NOW(), '+00:00', users.raw_offset), "%w%H") = '104'
Previous solution:
Fetch all the active users, iterate them, create a new \DateTime with the timezone that is specified by the user, do an "if monday between 4-5 am" check, if so, execute the script for that user and continue with the next user. But this seems really inefficient if we would talk about thousands of users or something?
$users = (new Models\User) -> getActiveUsers();
foreach ($users as $user) {
$localTimeUser = new \DateTime("now", new \DateTimeZone($user -> getTimezone()));
if ($localTimeUser -> format('NH') === '104') {
// execute
}
}
I could also "reverse" the determination by doing something like "in which timezone is it currently monday morning and get me the users with that timezone" but I haven't figured out the best way to check for that yet.
This is the first situation where I'm having trouble with timezones and I'm having a really hard time on figuring out the most efficient way to do something like this.
Is there a really straightforward solution that I'm currently missing or is checking thousands of user's timezones the only doable way?
Subnote:
The value 104 I compare with is just the easiest way I thought of, to have one value that indicates the day and the hour (1 = monday, 04 = 04:00 - 04:59 am) instead of checking between values etc.
Introduction to my website
My website is for visitors in Korea(AKA Republic of Korea).
And the server for My website is in the United States of America.
And PHPMyAdmin displays EDT when it runs a query SELECT ## system_time_zone.
Structure of my website
When I first uploaded my website to this server in October this year, I checked the DB time.
And it seemed that there was a time difference of 13 hours with Korea. So I added 3600 * 13 seconds to DB time(without setting timezone) as follows.
const Offset = 3600 * 13;
$SelectNow = $PDO->prepare('SELECT DATE_ADD(NOW(), INTERVAL '.Offset.' SECOND)');
$SelectNow->execute() or exit;
$DbNow = $SelectNow->fetchColumn();
My website takes $DbNow as above and uses it in various situations.
For example, in the posting situation, enter $DbNow in the datetime field of the INSERT INTO query as follows:
$WriteNote = $PDO->prepare('INSERT INTO table_note(my_datetime, my_contents) VALUES("'.$DbNow.'", :my_contents)');
$WriteNote->bindValue(':my_contents', $my_contents, PDO::PARAM_STR);
$WriteNote->execute();
The problem situation
One day in November of this year, when I wrote a post and checked the date field(my_datetime) of the post, I got an additional time difference of one hour with Korea.
Apparently, at the end of October, I corrected the time difference of 3600 * 13. And then I confirmed that it matches the Korean time. However, in November, There is a time difference of one hour!
Guess the cause
It seems that US summer time is being applied to the DB server of my website. Did I guess right?
My question
1) How can I solve this time difference fundamentally?
Is it correct to convert DB time to KST?
Or is it the correct way to convert to UTC and then added 3600 * x to UTC?
2) Even though the problem is resolved, some of the existing data in my DB has a time difference of one hour with Korean time.
What query do I use if I want to select the data with a time difference?
And how much more or subtract it from the data to get rid of the 1 hour time difference?
Use UTC to store time in Database.
change your queries to insert with UTC datetimes.
Use external libraries to convert UTC to respective timezones.
(below are the my personal recommendation.)
There may be best of it.
PHP : Carbon
Javascript : Moment, moment timezone.
No, it takes timezone of Database server resides in.
little manual verification, or create a job to change all dates in UTC.
Edit:
http://carbon.nesbot.com/docs/
I mean you can create a script and run with cron job.
I want to use the following code to SELECT data older then 1 minute.
SELECT * FROM `auth_temp` WHERE date > (NOW() - INTERVAL 1 MINUTE)
But it didn't work. Then I checked some other topics and one person talked about the server time, I just asked my host and he said the server time is: 15:30
When at my place and the logs in MySQL it is 21:30, aka 6 hours later.
Anyone how I should asjust my code to that?
Thank you all!
You are hitting a timezone issue. Most servers run on UTC. If you have a TIMESTAMP as the field type, MySQL will convert the time from server time to UTC and back. You can adjust what MySQL considers server time using SET time_zone = timezone; (Docs). If you actually care about timezones it is advisable to just use UTC and convert in your application.
Your current SQL statement will only select data newer than 1 minute. Change it to:
SELECT * FROM auth_temp WHERE date < (NOW() - INTERVAL 1 MINUTE)
This will select data that is older than one minute. If you are using NOW() for setting the date column when you are inserting the row then that small fix should do it even if the time zones are different between your application and database layer. If you are setting the date column from your application layer you will have syncing issues if the time zone is set differently than the database layer.
It sounds like the MySQL server is either running in a different time zone or running on Universal Time (UTC) which is common. Running MySQL on UTC time is a good way to deal with users in multiple time zones. In your code, you should be able to synchronize the time zones in use on the database and application layers if it's set to UTC time easily. If it's set to a different time zone, it should be possible as well but not recommended.
With the help of a friend, I got a webpage going that tracks different stats and saves it in an SQL database.
One of the information that returns, is when the latest score was submitted to the database. It works fine, but the webhost is in a different timezone and I am unable to change that timezone.
So therefore I was thinking about changing our query to one which returns how long ago the score was added.
Current code:
$statement = $adapter->query("
select name,
SUM(score_1) as score_1,
SUM(score_2) as score_2,
SUM(score_3) as score_3,
(SUM(score_1)+SUM(score_2)+SUM(score_3)) as total,
DATE_FORMAT(MAX(creation_time), '%d %b %H:%i') as creation_time
from score_entry
WHERE DATE(creation_time) = CURDATE()
group by name ORDER BY total DESC");
It grabs the information stored in the past day (from 00:00 this day), and I'm not sure if that is also affected by the incorrect timezone.
After a lot of searching around, I can't seem to find the solution to my exact problem.
I have tried to set the timezone in MySQL, but it's a shared host by Namecheap, they don't allow it.
Take a look at the time zone documentation.
Using the SET time_zone = timezone; command you will be able to set the time zone on a per-connection basis.
In addition, storing dates in a TIMESTAMP column makes MySQL convert the time to UTC and then it converts it back to the current time zone when you access it. Thus it makes storing and retrieving time zone agnostic.
Set the time zone in your PHP script using the posted solution. It's also possible to send it the datetime to use in your query using PHP's date function.
I'm creating a site where i need to use registered users timezones to determine if they are available to receive emails on specific days based on what they set in their dashboard.
The main thing im wanting to tackle is that i would like the option of showing those users who are available NOW at the top of the results to save people having to search through pages of people to find those who are available.
I have a rough idea of a function i could use to show/hide the email form on the users page... Its more about the query on the search page that will display all the users and how best to order the results.
The default timezone will be GMT.
So if today was monday and the following users had their availability set as:
USER | timezone | availability_today | emails_received
1 | America/Los_Angeles | 2 | 1 (still available)
2 | America/New_York | 0 | 0 (not available)
3 | Europe/London | 1 | 1 (not available)
I think its more a question of what date/timezone I'm actually saving/accessing. In the email table id have a DATE_SENT column so i can count how many emails have been sent to compare against their availability. But if the site is GMT... that wouldn't be the users correct time if they were in the US or Australia...
Like i said, its more about the select statement on the search page that i cant figure out with all the timezones there would be. My host doesn't support CONVERT_TZ.
Or do i just calculate it all in GMT?
I'm just as confused asking the question as you are reading it im sure. Hopefully someone understands enough to offer a suggestion. Its probably not as confusing as im making it out to be.
EDIT:-
The issue:
Say its Monday GMT. In a users (not visitors) country its tuesday and they have their availability set as 0. If i use GMT its monday on the server so an email will get through. And on Tuesday (Weds in the users country) they wont get one.
Visitors wont have to register to view the search results. They will need to if they want to email a user. The users page is easy enough as its dealing with one conversion.
Couple of options...
(1) Store everything in GMT in datetime column. You can perform the manipulation on your end by performing MySQL queries such as
SELECT 'my date' - INTERVAL 5 HOUR
(2) Store everything in timestamp columns in the user's current timezone. You can set the timezone for the current database connection by executing the query...
SET time_zone = 'Europe/London'
View the current time zone with
SELECT ##time_zone;
Replace 'Europe/London' with the correct timezone. When MySQL uses timestamps it internally stores the data in GMT. When you pull the data back out, MySQL will automatically convert the time back into whatever timezone the client has currently set.
Store times in epoch time, converting for display only using FROM_UNIXTIME(). Forget multiple timezones, as Mr Sokolov so eloquently put it,
that way leads madness