Our database uses '0000-00-00 00:00:00' as the default value for many datetime and timestamp fields. MySQL has apparently decided that they only want us to use a valid date or null for these types of fields.
However, the '0000-00-00 00:00:00' values used to be acceptable and our code checks for this value. When I setup a new server, I edit the /etc/mysql/mysql.conf.d/mysqld.cnf file and add one line to the [mysqld] section.
sql_mode=NO_ENGINE_SUBSTITUTION
Today I have attempted to setup a new server. I added the sql_mode=NO_ENGINE_SUBSTITUTION to the MySQL configuration and restarted the mysql service. However, this new server only gets errors.
UPDATE example_table SET active = 1 WHERE example_table_id = 1;
ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'my_date_field' at row 1
I could of course update the database to have NULL values or a "valid" default date such as '1970-01-01 00:00:01', but this would break existing code that checks the data for '0000-00-00 00:00:00'.
Additional Example Information:
Server type: MySQL
Server version: 5.7.22-0ubuntu0.16.04.1 - (Ubuntu)
Protocol version: 10
innodb_version: 5.7.22
SELECT my_date_field FROM example_table WHERE active = 1;
+---------------------+
| my_date_field |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
DESC example_table;
+------------------------------------+--------------+------+-----+---------------------+
| Field | Type | Null | Key | Default |
+------------------------------------+--------------+------+-----+---------------------+
| my_date_field | datetime | NO | | 0000-00-00 00:00:00 |
| active | tinyint(2) | NO | | 1 |
+------------------------------------+--------------+------+-----+---------------------+
I've got other machines on the same version of MySQL working with just sql_mode=NO_ENGINE_SUBSTITUTION and I'm almost to the point of just imaging one of those for this new machine, until such time as the code is updated to look for a valid date or null instead of '0000-00-00 00:00:00'.
The NO_ENGINE_SUBSTITUTION SQL mode doesn't have anything to do with dates. It only did the trick for you because by setting it you also removed the server's default mode, which in modern versions is something on the line of TRADITIONAL, which is a combination mode that, among others, includes NO_ZERO_IN_DATE and NO_ZERO_DATE.
You possibly just want to set a legacy mode for this application at session level, e.g.:
SET ##SESSION.sql_mode = '';
Related
I am new in nodejs and my english is bad please help me, I am just trying to migrate my database in nodejs(express) using knex, and I'm using Mysql for database. I want to rename one field in table, and when I try to migrate my database, I got some problem that say error default value.
here is what I'm trying to do :
My migrate
exports.up = function(knex) {
return knex.schema.table ('tbl_skills', function(table) {
table.renameColumn('preminum_price', 'premium_price')
})
};
Here my database structure
Name | Datatype | length | Default |
id | INT | 20 | No default |
preminum_price | DOUBLE | 5,2 | No default |
insertdate | TIMESTAMP| | 0000-00-00 00:00:00 |
updatedate | TIMESTAMP| | 0000-00-00 00:00:00 |
and this what I got when I'm trying knex migrate:latest
migration file "20191125105226_alter_tbl_skills.js" failed
migration failed with error: alter table `tbl_skills` change `preminum_price` `premium_price` double(5,2) NOT NULL - ER_INVALID_DEFAULT: Invalid default value for 'insertdate'
Error: ER_INVALID_DEFAULT: Invalid default value for 'insertdate'
I dont know to how set value for insertdate with default value. Please help
That is most probably because of server SQL Mode - NO_ZERO_DATE.
In strict mode, don't allow '0000-00-00' as a valid date. You can still insert zero dates with the IGNORE option. When not in strict mode, the date is accepted but a warning is generated. If you have access to my.ini (mysql conf file) remove the NO_ZERO_DATA from sql-mode and restart the server.
You can check it with SHOW VARIABLES LIKE 'sql_mode'
I have a column in my database called time. the type of this column is timestamp and Default value is CURRENT_TIMESTAMP
But after some inserts, in phpMyAdmin it shows the value as datetime, e.g. 2019-05-05 04:24:45 and even the Timezone is shown there and can be changed!
I thought MySQL's timestamp is 4 bytes (compared to 8 bytes of datetime) and doesn't store timezone and data is same as INT(10) such as: 1557094115 (seconds passed since 1970 or something like that)
Can any one please explain this, is it a bug or something?
MySQL version 5.7.25
Edit 1 (Screenshots):
It is a TIMESTAMP column, with default value of CURRENT_TIMESTAMP
As you see it is shown as DATETIME and I cannot compare it with integer value of unix_timestamp... also we can change TimeZone to any value (I thought timestamp doesn't store timezone...)
Edit 2:
If (based on one answer) MySQL stores it as an integer internally, then why can't I compare it with integers? (the following query won't work)
DELETE FROM `table` WHERE time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL :days DAY))
SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '1555980012' for column 'time' at row 1
I also tried it in Sequel Pro and MySQLWorkbench with same results
If you need to see 1557094115, then apply the function UNIX_TIMESTAMP() to the TIMESTAMP or DATETIME column. It's inverse is FROM_UNIXTIME().
mysql> SELECT UNIX_TIMESTAMP("2019-05-05 04:24:45"), FROM_UNIXTIME(1557055485);
+---------------------------------------+---------------------------+
| UNIX_TIMESTAMP("2019-05-05 04:24:45") | FROM_UNIXTIME(1557055485) |
+---------------------------------------+---------------------------+
| 1557055485 | 2019-05-05 04:24:45 |
+---------------------------------------+---------------------------+
More
The internal storage for TIMESTAMP is 1557055485 in UTC; the timezone is added/removed as it is fetched/stored.
The internal storage for DATETIME is (logically, but not actually) the string "2019-05-05 04:24:45" with no hint of timezone. (Actually, it is packed into 5 bytes in some fashion.)
Without any conversion function, fetching TIMESTAMP and DATETIME look the same:
CREATE TABLE `dtts` (
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`dt` datetime DEFAULT NULL,
`just_date` date NOT NULL,
`di` int(11) DEFAULT NULL,
`ts_int` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
1 row in set (0.00 sec)
mysql> select * from dtts
-> ;
+---------------------+---------------------+------------+------------+------------+
| ts | dt | just_date | di | ts_int |
+---------------------+---------------------+------------+------------+------------+
| 2017-06-26 17:52:53 | 2011-06-08 20:45:55 | 2011-06-08 | 20110608 | 1465404577 |
| 2017-06-26 17:52:53 | 2013-03-10 02:35:47 | 2013-03-10 | 20130310 | 1465404577 |
Adding NOW() to both, then SELECTing:
mysql> INSERT INTO dtts (ts, dt) VALUES (NOW(), NOW());
Query OK, 1 row affected, 1 warning (0.00 sec)
| 2019-05-08 14:14:07 | 2019-05-08 14:14:07 | 0000-00-00 | NULL | NULL |
+---------------------+---------------------+------------+------------+------------+
DateTime doesn't store timezone information (it's value only), while MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and convert from UTC to the current time zone for retrieval. What you are seeing from PhpMyAdmin is the retrieved value, not stored value.
Since MySQL 5.6.4, the storage of DateTime has been improved from 8 bytes to 5 bytes (+ fractional seconds storage) Reference
Since MySQL 5.6.4, the DATETIME field requires 5 bytes + 3 bytes fractional. The TIMESTAMP type requires 4 bytes + 3 bytes fractional. Neither of these data types store time zone information. However, both MySQL and phpMyAdmin display TIMESTAMP fields according to the timezone of the database server. You can retrieve the database server's timezone info with the following statements:
SELECT ##global.time_zone, ##session.time_zone;
SELECT EXTRACT(HOUR FROM (TIMEDIFF(NOW(), UTC_TIMESTAMP))) AS `timezone`
If you would like phpMyAdmin to display a different timezone from the database server, you can set the SessionTimeZone property inside of phpMyAdmin's config.inc.php file.
We are migrating our application from MySQL 5.5 to 5.7. As the default value 0000-00-00 is not allowed anymore for date fields in MySQL 5.7 in strict mode, I would like to change the default value to NULL.
The concerned fields are defined as follows:
+------------------+----------------------+------+-----+------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+----------------------+------+-----+------------+----------------+
| event_start_date | date | YES | | 0000-00-00 | |
| event_end_date | date | YES | | 0000-00-00 | |
+------------------+----------------------+------+-----+------------+----------------+
When I try to execute the following ALTER query:
ALTER TABLE events CHANGE event_start_date event_start_date date DEFAULT NULL;
ALTER TABLE events CHANGE event_end_date event_end_date date DEFAULT NULL;
I get the following error:
Invalid default value for 'event_end_date'
I know it would be possible to disable strict mode, but that is not the solution I am looking for. Strangely enough the same query worked for an other table.
Anyone has an idea what is going wrong?
The error happens already in your query on the first line. There you are trying to change the column event_start_date, the error message however is for column event_end_date. You need to change both columns with a single query in order to avoid this error:
ALTER TABLE events CHANGE event_start_date event_start_date date DEFAULT NULL, CHANGE event_end_date event_end_date date DEFAULT NULL;
It probably worked with your other table because you only had one column of type date.
This is the new strict mode in MySQL 5.7. The default SQL_MODE in MySQL 5.7 is:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
The best way is to change the schema as #cansik suggested.
You can also remove NO_ZERO_IN_DATE,NO_ZERO_DATE from sql_mode (not recommended but can be temporary workaround)
set global sql_mode="... choose which modes you need ... "
since 2 weeks I puzzled over timezone issue, everything working fine on my localhost BUT it returns wrong value on dedicated server. Let me tell what i have done so far.
First set global timezone by below query: ( Super privilege both on localhost and server )
SET GLOBAL time_zone = '+00:00';
now run below query to cross check whatever done
SELECT NOW(),##global.time_zone AS gtz,##session.time_zone AS stz,
TIMEDIFF(NOW(), CONVERT_TZ( NOW() , ##session.time_zone , '+00:00' ) )
AS OFFSET;
but it display different results on local and dedicated server
on localhost (192.168.x.x) mysql version : 5.5.8
+---------------------+--------+--------+----------+
| NOW() | gtz | stz | OFFSET |
+---------------------+--------+--------+----------+
| 2012-07-02 07:06:55 | +00:00 | +00:00 | 00:00:00 |
+---------------------+--------+--------+----------+
1 row in set (0.00 sec)
on dedicated server (182.168.x.x) mysql version :5.1.53-log
+---------------------+--------+--------+----------+
| NOW() | gtz | stz | OFFSET |
+---------------------+--------+--------+----------+
| 2012-07-02 12:37:59 | +00:00 | +00:00 | 00:00:00 |
+---------------------+--------+--------+----------+
My question is
why NOW() gives wrong time ( above is IST ) whereas
timezone is set to +00:00 ?
side note :
I run below query
SHOW VARIABLES LIKE '%time%zone%';
on localhost
+------------------+---------------------+
| Variable_name | Value |
+------------------+---------------------+
| system_time_zone | India Standard Time |
| time_zone | +00:00 |
+------------------+---------------------+
on server
+------------------+---------------------+
| Variable_name | Value |
+------------------+---------------------+
| system_time_zone | GMT+5 |
| time_zone | +00:00 |
+------------------+---------------------+
does this will affect the result? OR
is there any bug in earlier version of mysql ?
please help me.
When calling NOW() (and related functions), MySQL converts the computer's system clock to the session timezone:
If the system clock is set to 12:30+05:30 and the session timezone is +00:00, the result will be 07:00.
If the system clock is set to 17:30+05:00 and the session timezone is +00:00, the result will be 12:30.
However, one can 'fool' MySQL into thinking that the system clock is in a different timezone to that which the operating system believes by using the --timezone command line argument to mysqld_safe:
If the system clock is set to 17:30+10:30 and the session timezone is +00:00, but MySQL was started in such a way specifying that the system clock should be understood to be GMT+5, the result will be the same as the second bullet above.
You should therefore check:
That the timezone of the system clock reconciles with the value given in the system_time_zone system variable (if it doesn't, ensure that you are not specifying a --timezone argument to mysqld_safe and that there was no TZ environment variable set when mysqld_safe was invoked);
That the system clock is reporting the correct time in its specified timezone.
You just need to restart mysqld after altering timezone of System..
The Global time zone of MySQL takes timezone of System. When you change any such attribute of system, you just need a restart of Mysqld.
That's it.
1) Change your system time and timezone, if necessary.
2) Open mysql console and put in your timezone, smth like this: SET GLOBAL time_zone = "+04:00";
3) Restart mysql.
i have tested-
SET time_zone='+05:30'; it is working,but i dont have global permission so you try by setting server time +05:30 ->
SET GLOBAL time_zone = '+05:30';
Can MySQL convert a stored UTC time to local time-zoned time directly in a normal select statement?
Let's say you have some data with a timestamp (UTC).
CREATE TABLE `SomeDateTable` (
`id` int(11) NOT NULL auto_increment,
`value` float NOT NULL default '0',
`date` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
)
Then when I
"select value, date from SomeDateTable";
I of course get all the dates as in their stored UTC form.
But let's say that I would like to have them in another timezone (with DST),
can I then add some magic to the select query so that I get all the dates back in the selected timezone?
"select value, TIMEZONE(date, "Europe/Berlin") from SomeDateTable";
Or must I do this in some other layer on top, like in some php code?
(it seems to be how most people have solved this problem).
If your MySQL installation allows you to use CONVERT_TZ it is a very clean solution,
this example shows how to use it.
SELECT CONVERT_TZ( '2010-01-01 12:00', 'UTC', 'Europe/Stockholm' )
However I don't know if this is a good way since some MySQL installation is missing this function, use with care.
Yup, there's the convert_tz function.
For those unable to configure the mysql environment (e.g. due to lack of SUPER access) to use human-friendly timezone names like "America/Denver" or "GMT" you can also use the function with numeric offsets like this:
CONVERT_TZ(date,'+00:00','-07:00')
One can easily use
CONVERT_TZ(your_timestamp_column_name, 'UTC', 'your_desired_timezone_name')
For example:
CONVERT_TZ(timeperiod, 'UTC', 'Asia/Karachi')
Plus this can also be used in WHERE statement and to compare timestamp i would use the following in Where clause:
WHERE CONVERT_TZ(timeperiod, 'UTC', '{$this->timezone}') NOT BETWEEN {$timeperiods['today_start']} AND {$timeperiods['today_end']}
select convert_tz(now(),##session.time_zone,'+03:00')
For get the time only use:
time(convert_tz(now(),##session.time_zone,'+03:00'))
1. Correctly setup your server:
On server, su to root and do this:
# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql
(Note that the command at the end is of course mysql , and, you're sending it to a table which happens to have the same name: mysql.)
Next, you can now # ls /usr/share/zoneinfo .
Use that command to see all the time zone info on ubuntu or almost any unixish server.
(BTW that's the convenient way to find the exact official name of some time zone.)
2. It's then trivial in mysql:
For example
mysql> select ts, CONVERT_TZ(ts, 'UTC', 'Pacific/Tahiti') from example_table ;
+---------------------+-----------------------------------------+
| ts | CONVERT_TZ(ts, 'UTC', 'Pacific/Tahiti') |
+---------------------+-----------------------------------------+
| 2020-10-20 16:59:57 | 2020-10-20 06:59:57 |
| 2020-10-20 17:02:59 | 2020-10-20 07:02:59 |
| 2020-10-20 17:30:08 | 2020-10-20 07:30:08 |
| 2020-10-20 18:36:29 | 2020-10-20 08:36:29 |
| 2020-10-20 18:37:20 | 2020-10-20 08:37:20 |
| 2020-10-20 18:37:20 | 2020-10-20 08:37:20 |
| 2020-10-20 19:00:18 | 2020-10-20 09:00:18 |
+---------------------+-----------------------------------------+
I propose to use
SET time_zone = 'proper timezone';
being done once right after connect to database. and after this all timestamps will be converted automatically when selecting them.