mysql query to select highest temperature today - mysql

Just learning MYSQL sorry and didn't find the answer from searching here as I am confused about timezones etc.
I have a table like the following;
time (datetime type with time in my timezone in it - eg "2014-11-21 14:23:45")
temp_c (double with temperature at that time)
The server is in a different timezone so I am getting mixed up in how to limit the rows to be sometime today.
So basically I want to find the maximum temperature so far today in my timezone and when it occured, as well as the minimum temperature and when that occured.

SET time_zone = 'your time zone';
SELECT MAX(temp_c)
FROM YourTable
WHERE DATE(time) = DATE(NOW());
Replace your time zone with your actual time zone. This can either be an offset from GMT like -05:00 for 5 hours west of GMT, or a zone name like US/Eastern.
SET time_zone = 'US/Eastern';
For more information on time zones in MySQL see
How do I set the time zone of MySQL?

Related

Selecting dates from MySQL using NOW() with Time Zone mutates results

I'm using a Laravel application that inserts timestamps based upon 'timezone' => 'America/New_York'. All of my data inserted is the correct date time. Which should be expected. I know that the MySQL's own timezone setting doesn't effect the inserted data.
However, I want to retrieve records from 30 mins ago. But when I use MySQL NOW() function its the wrong time. So I set the time_zone to America/New_York that gives me the correct NOW() but all the record dates have been mutated.
SELECT id, updated_at FROM my_table Where id = 6;
Gives me the correct date in my update_at field;
So to select my records within the past 30 mins is use:
SET #PAST_TIME = DATE_SUB(NOW(), INTERVAL 30 MINUTE);
SELECT id, updated_at, #PAST_TIME as past_time FROM my_table Where updated_at >= #PAST_TIME;
Which returns practically every record in my set and as you can see, the past_time is incorrect (I ran this at 9:31 ET).
Recognizing that the time mysql is out of sync, I set the timezone to
SET time_zone = 'America/New_York';
SET #PAST_TIME = DATE_SUB(NOW(), INTERVAL 30 MINUTE);
SELECT id, updated_at, #PAST_TIME as past_time FROM my_table Where updated_at >= #PAST_TIME;
Which outputs the correct PAST_TIME but all the update_at records are mutated. But it shouldn't return some of those records anyway because the mutated results are greater than PAST_TIME
How do I stop the column mutation? while still being able to select my records?
You can think of a timestamp column as essentially storing a UTC date and time. It really does not matter what the session time zone setting was when the timestamp value was stored if you are initializing it with a function such as now() or current_timestamp(); the date and time will be interpreted in the current time zone and converted to UTC (of course, now() returns a value that is time zone dependent but regardless of what the current session time zone is you should end up with the same UTC date and time after conversion). However, how the timestamp is displayed very much depends on what the current session time zone is, for the timestamp will be converted back from UTC to whatever the current time zone in effect is.
(On the other hand, if you have a datetime column initialized with now() what will be stored will very much depend on the current time zone because there is never any time zone conversion done. But then it will always be displayed the same regardless of what the current session time zone is in effect.)
When you want to retrieve records that were updated within the last 30 minutes, it's natural to have in your query somewhere DATE_SUB(NOW(), INTERVAL 30 MINUTE). When you are comparing NOW() or a value computed from NOW() with a timestamp column, again it should not make any difference what the current time zone is. The timestamp column has implicit time zone information (UTC) and you should retrieve the same records regardless. As I would expect, I see exactly the same id values being retrieved before and after you set the America/New_York time zone (one might see some difference due to the time lapse between the two queries; fewer rows might now have been updated in the last 30 minutes). The difference, which is to be expected, is how the dates and times are displayed.
You do want to set the America/New_York time zone just so the dates and times jive with your local time. But you should still be getting the same records regardless.

MySQL - NOW() different value if its in trigger or in select

I have an issue with MySQL NOW() function
if i run:
SELECT NOW();
i get the value:
2015-11-24 13:35:00 (correct value with Swedish winter-time)
But if i use NOW() in a trigger function to update a timestamp column when another column changes like this:
SET NEW.timestamp = NOW();
i get the value:
2015-11-24 12:35:00
How can i solve this or why is it behaving like this?
To get current date and time using NOW(), please set the timezone as per your country to get the correct date and time.
Please check the link here
If you want to change the MySQL server’s time zone to adjust the current date and time returned by the NOW() function, you use the following statement:
SET time_zone = your_time_zone;
MySQL has multiple ways of specifying a timezone - the server has a default time zone and each client can also specify their own time zone on a per-connection basis.
I think that your SELECT is using the time zone specified by your client connection, while the trigger is using the server's default time zone.
https://dev.mysql.com/doc/refman/5.6/en/time-zone-support.html

Group By Localized Date

Tracking the total sales by day based on a table of transactions is quite easy to write. The current code uses a BETWEEN and executes a query for each date. I don't really like this, especially when date ranges are in months.
Now, the date_created field for the transaction is of the type timestamp. And writing a query like works, except for one thing:
SELECT DATE(date_created), sum(sale_total)
FROM
transaction
WHERE DATE(date_created) BETWEEN ? and ?
GROUP BY DATE(date_created)
It works beautifully, except that the database is localized to GMT, and I'm here in CST. So any transactions that occur after 7:00 PM CST will be "pushed" to the next day because it is stored as the next day in GMT.
I guess my question is 2-fold
How would I proceed to GROUP BY the localized date?
Is there a way strictly in MySQL know that I want to use a different timezone in the query? Or will this have to be a manual adjustment?
TIMESTAMP fields are stored as UTC under the hood. If your data is in TIMESTAMP fields, you can set the MySQL time zone to use: SET time_zone = 'America/New_York';
If you've stored the data in DATETIME fields, they get stored in the MySQL system time zone, so conversion would be on you.

Should MySQL have its timezone set to UTC?

Follow up question of
https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc
Should the MySQL timezone be set to UTC or should it be set to be the same timezone as the server or PHP is set? (If it is not UTC)
What are the pros and cons?
It seems that it does not matter what timezone is on the server as long as you have the time set right for the current timezone, know the timezone of the datetime columns that you store, and are aware of the issues with daylight savings time.
On the other hand if you have control of the timezones of the servers you work with then you can have everything set to UTC internally and never worry about timezones and DST, at least when it comes to storing internal time.
Here are some notes I collected of how to work with timezones as a form of cheatsheet for myself and others which might influence what timezone the person will choose for his/her server and how he/she will store date and time.
MySQL Timezone Cheatsheet
Notes:
Changing the timezone will not change the stored datetime or
timestamp, but it will select a different datetime from
timestamp columns
Warning! UTC has leap seconds, these look like '2012-06-30 23:59:60' and can
be added randomly, with 6 months prior notice, due to the slowing of
the earths rotation
GMT confuses seconds, which is why UTC was invented.
Warning! different regional timezones might produce the same datetime value due
to daylight savings time
The timestamp column only supports dates 1970-01-01 00:00:01 to 2038-01-19 03:14:07 UTC, due to a limitation.
Internally a MySQL timestamp column is stored as UTC but
when selecting a date MySQL will automatically convert it to the
current session timezone.
When storing a date in a timestamp, MySQL will assume that the date
is in the current session timezone and convert it to UTC for
storage.
MySQL can store partial dates in datetime columns, these look like
"2013-00-00 04:00:00"
MySQL stores "0000-00-00 00:00:00" if you set a datetime column as
NULL, unless you specifically set the column to allow null when you
create it.
Read this
To select a timestamp column in UTC format
no matter what timezone the current MySQL session is in:
SELECT
CONVERT_TZ(`timestamp_field`, ##session.time_zone, '+00:00') AS `utc_datetime`
FROM `table_name`
You can also set the sever or global or current session timezone to UTC and then select the timestamp like so:
SELECT `timestamp_field` FROM `table_name`
To select the current datetime in UTC:
SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), ##session.time_zone, '+00:00');
Example result: 2015-03-24 17:02:41
To select the current datetime in the session timezone
SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();
To select the timezone that was set when the server launched
SELECT ##system_time_zone;
Returns "MSK" or "+04:00" for Moscow time for example, there is (or was) a MySQL bug where if set to a numerical offset it would not adjust the Daylight savings time
To get the current timezone
SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);
It will return 02:00:00 if your timezone is +2:00.
To get the current UNIX timestamp (in seconds):
SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();
To get the timestamp column as a UNIX timestamp
SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`
To get a UTC datetime column as a UNIX timestamp
SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', ##session.time_zone)) FROM `table_name`
Get a current timezone datetime from a positive UNIX timestamp integer
SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`
Get a UTC datetime from a UNIX timestamp
SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), ##session.time_zone, '+00:00')
FROM `table_name`
Get a current timezone datetime from a negative UNIX timestamp integer
SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND)
There are 3 places where the timezone might be set in MySQL:
Note: A timezone can be set in 2 formats:
an offset from UTC: '+00:00', '+10:00' or '-6:00'
as a named time zone: 'Europe/Helsinki', 'US/Eastern', or 'MET'
Named time zones can be used only if the time zone information tables
in the mysql database have been created and populated.
in the file "my.cnf"
default_time_zone='+00:00'
or
timezone='UTC'
##global.time_zone variable
To see what value they are set to
SELECT ##global.time_zone;
To set a value for it use either one:
SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET ##global.time_zone='+00:00';
##session.time_zone variable
SELECT ##session.time_zone;
To set it use either one:
SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET ##session.time_zone = "+00:00";
both "##global.time_zone variable" and "##session.time_zone variable" might return "SYSTEM" which means that they use the timezone set in "my.cnf".
For timezone names to work (even for default-time-zone) you must setup your timezone information tables need to be populated: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support.html
Note: you can not do this as it will return NULL:
SELECT
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime`
FROM `table_name`
Setup mysql timezone tables
For CONVERT_TZ to work, you need the timezone tables to be populated
SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;
If they are empty, then fill them up by running this command
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
if this command gives you the error "data too long for column 'abbreviation' at row 1", then it might be caused by a NULL character being appended at the end of the timezone abbreviation
the fix being to run this
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql
echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql
mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql
(make sure your servers dst rules are up to date zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/)
See the full DST (Daylight Saving Time) transition history for every timezone
SELECT
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND) AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC
CONVERT_TZ also applies any necessary DST changes based on the rules in the above tables and the date that you use.
Note:
According to the docs, the value you set for time_zone does not change, if you set it as "+01:00" for example, then the time_zone will be set as an offset from UTC, which does not follow DST, so it will stay the same all year round.
Only the named timezones will change time during daylight savings time.
Abbreviations like CET will always be a winter time and CEST will be summer time while +01:00 will always be UTC time + 1 hour and both won't change with DST.
The system timezone will be the timezone of the host machine where mysql is installed (unless mysql fails to determine it)
You can read more about working with DST here
When not to use UTC by the legendary Jon Skeet: https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/
(For example a scheduled event in the future that represents a time, not an instant in time)
related questions:
How do I set the time zone of MySQL?
MySql - SELECT TimeStamp Column in UTC format
How to get Unix timestamp in MySQL from UTC time?
Converting Server MySQL TimeStamp To UTC
https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp
How do I get the current time zone of MySQL?
MySQL datetime fields and daylight savings time -- how do I reference the "extra" hour?
Converting negative values from FROM_UNIXTIME
Sources:
https://bugs.mysql.com/bug.php?id=68861
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html
http://dev.mysql.com/doc/refman/5.1/en/datetime.html
http://en.wikipedia.org/wiki/Coordinated_Universal_Time
http://shafiqissani.wordpress.com/2010/09/30/how-to-get-the-current-epoch-time-unix-timestamp/
https://web.ivy.net/~carton/rant/MySQL-timezones.txt
PHP and MySQL have their own default timezone configurations. You should synchronize time between your data base and web application, otherwise you could run some issues.
Read this tutorial: How To Synchronize Your PHP and MySQL Timezones
This is a working example:
jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow
The pros and cons are pretty much identical.It depends on whether you want this or not.
Be careful, if MySQL timezone differs from your system time (for instance PHP), comparing the time or printing to the user will involve some tinkering.
How about making your app agnostic of the server's timezone?
Owing to any of these possible scenarios:
You might not have control over the web/database server's timezone settings
You might mess up and set the settings incorrectly
There are so many settings as described in the other answers, and so many things to keep track of, that you might miss something
An update on the server, or a software reset, or another admin, might unknowing reset the servers' timezone to the default - thus breaking your application
All of the above scenarios give rise to breaking of your application's time calculations. Thus it appears that the better approach is to make your application work independent of the server's timezone.
The idea is simply to always create dates in UTC before storing them into the database, and always re-create them from the stored values in UTC as well. This way, the time calculations won't ever be incorrect, because they're always in UTC. This can be achieved by explicity stating the DateTimeZone parameter when creating a PHP DateTime object.
On the other hand, the client side functionality can be configured to convert all dates/times received from the server to the client's timezone. Libraries like moment.js make this super easy to do.
For example, when storing a date in the database, instead of using the NOW() function of MySQL, create the timestamp string in UTC as follows:
// Storing dates
$date = new DateTime('now', new DateTimeZone('UTC'));
$sql = 'insert into table_name (date_column) values ("' . $date . '")';
// Retreiving dates
$sql = 'select date_column from table_name where condition';
$dateInUTC = new DateTime($date_string_from_db, new DateTimeZone('UTC'));
You can set the default timezone in PHP for all dates created, thus eliminating the need to initialize the DateTimeZone class every time you want to create a date.
Check Timezone
SELECT ##system_time_zone as System_tz ,##global.time_zone as MYSQL_timeZone, NOW() as timenow_bymysql;
SET GLOBAL time_zone = '+05:30';
OR
change system time zone then restart MariaDB/MYSQL
and check again timezone

MYSQL - Compare NOW() and a date at Paris TimeZone in a request

I have a value stored as a DateTime (Paris date-time).
How can I, into a VIEW, know if a stored date is before or equal to NOW(), with NOW() at Paris TimeZone in any case?
PS : I do not have any control over the SQL server.
To Ensure that the date is in paris time zone you can use CONVERT_TZ to convert between time zones. For example the following query will compare the NOW() date with the stored date and gives you the difference (in days) between them, ensuring that the two dates are in a specific time zone, (I don't know the time zone of paris but this is just an example):
select datediff(
Convert_TZ(Now(),"SYSTEM","-08:00"),
Convert_Tz(AddedIn,"SYSTEM","-08:00")
)
from TableName
System returns your current time zone, and for -08:00 is the time zone that you want to convert to as an offset, you can use the name of the time zone or it's offset as specified MySQL Time zone design pattern.
Hope this will help;