Rails and MySql datetime behaviour - mysql

I just noticed something odd in my Rails application.
When I update a DateTime column with a random value like below code, it automatically generates a wrong DateTime and saves it instead of NULL.
user = AdminUser.last
data = {last_sign_in_at: "1234568!"}
user.update_attributes(data)
And it generates a query like below:
UPDATE `admin_users` SET `last_sign_in_at` = '1234-01-01 04:56:02', `updated_at` = '2018-01-24 21:27:50' WHERE `admin_users`.`id` = 3
Where is that odd DateTime value coming from ? And interestingly it works with that specific random value. Not with something like "invalid!" and "1234568!" .
So is this something to do with MySql or Rails query generation ?
Maybe I am not aware of such things in database, as it is not something I work with regularly .

It looks like rails use Time library to convert your 1234568! and if you try that in rails console like Time.zone.parse('1234568!') you get back a Time object Sun, 01 Jan 1234 00:00:00 UTC +00:00 but if you try to do a Date.parse(1234568!) it throws you an ArgumentError: invalid date error so maybe you can parse using date to avoid that.

Related

Python MySQL reads the data wrong for Timestamp(3)

I recently met with a weird problem about SQL timestamp.
I created a table and the column was like
`time` TIMESTAMP(3) DEFAULT '1970-01-01 08:00:01.000'
And I manually inserted 2021-03-18 17:00:32.123
And what I read through python mysql.connector is 2021-03-18 17:00:32.000123 ?????
Seems like I found the rule, then I changed it to TIMESTAMP(1). Guess what I got 2021-03-18 17:00:32.000001
Obviously, it's the way in contrast, what could be the problem, thanks
--- Update---
For the python code, there's nothing special
cursor.execute("select time from table")
times = list(cursor)
And from the debug console, I can see the time is incorrect, as well as the timestamp in UNIX, like
unixTime = times[0].timestamp()
The Unix time will be something like XXXX.000123 instead of XXXX.123
But I can get the correct result from UNIX_TIMESTAMP(), like
cursor.execute("select UNIX_TIMESTAMP(time) from table")
So I think it seems like python mysql lib seems didn't get or convert the format correctly.

Google Apps Script - MySQL data import using JDCB does not work with Date 0000-00-00 [duplicate]

I have a database table containing dates
(`date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00').
I'm using MySQL. From the program sometimes data is passed without the date to the database. So, the date value is auto assigned to 0000-00-00 00:00:00
when the table data is called with the date column it gives error
...'0000-00-00 00:00:00' can not be represented as java.sql.Timestamp.......
I tried to pass null value to the date when inserting data, but it gets assign to the current time.
Is there any way I can get the ResultSet without changing the table structure?
You can use this JDBC URL directly in your data source configuration:
jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull
Whether or not the "date" '0000-00-00" is a valid "date" is irrelevant to the question.
"Just change the database" is seldom a viable solution.
Facts:
MySQL allows a date with the value of zeros.
This "feature" enjoys widespread use with other languages.
So, if I "just change the database", thousands of lines of PHP code will break.
Java programmers need to accept the MySQL zero-date and they need to put a zero date back into the database, when other languages rely on this "feature".
A programmer connecting to MySQL needs to handle null and 0000-00-00 as well as valid dates. Changing 0000-00-00 to null is not a viable option, because then you can no longer determine if the date was expected to be 0000-00-00 for writing back to the database.
For 0000-00-00, I suggest checking the date value as a string, then changing it to ("y",1), or ("yyyy-MM-dd",0001-01-01), or into any invalid MySQL date (less than year 1000, iirc). MySQL has another "feature": low dates are automatically converted to 0000-00-00.
I realize my suggestion is a kludge. But so is MySQL's date handling.
And two kludges don't make it right. The fact of the matter is, many programmers will have to handle MySQL zero-dates forever.
Append the following statement to the JDBC-mysql protocol:
?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
for example:
jdbc:mysql://localhost/infra?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
Instead of using fake dates like 0000-00-00 00:00:00 or 0001-01-01 00:00:00 (the latter should be accepted as it is a valid date), change your database schema, to allow NULL values.
ALTER TABLE table_name MODIFY COLUMN date TIMESTAMP NULL
As an exteme turnaround, when you cannot do an alter to your date column or to update the values, or while these modifications take place, you can do a select using a case/when.
SELECT CASE ModificationDate WHEN '0000-00-00 00:00:00' THEN '1970-01-01 01:00:00' ELSE ModificationDate END AS ModificationDate FROM Project WHERE projectId=1;
you can try like This
ArrayList<String> dtlst = new ArrayList<String>();
String qry1 = "select dt_tracker from gs";
Statement prepst = conn.createStatement();
ResultSet rst = prepst.executeQuery(qry1);
while(rst.next())
{
String dt = "";
try
{
dt = rst.getDate("dt_tracker")+" "+rst.getTime("dt_tracker");
}
catch(Exception e)
{
dt = "0000-00-00 00:00:00";
}
dtlst.add(dt);
}
I wrestled with this problem and implemented the URL concatenation solution contributed by #Kushan in the accepted answer above. It worked in my local MySql instance. But when I deployed my Play/Scala app to Heroku it no longer would work. Heroku also concatenates several args to the DB URL that they provide users, and this solution, because of Heroku's use concatenation of "?" before their own set of args, will not work. However I found a different solution which seems to work equally well.
SET sql_mode = 'NO_ZERO_DATE';
I put this in my table descriptions and it solved the problem of
'0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
There was no year 0000 and there is no month 00 or day 00. I suggest you try
0001-01-01 00:00:00
While a year 0 has been defined in some standards, it is more likely to be confusing than useful IMHO.
just cast the field as char
Eg: cast(updatedate) as char as updatedate
I know this is going to be a late answer, however here is the most correct answer.
In MySQL database, change your timestamp default value into CURRENT_TIMESTAMP. If you have old records with the fake value, you will have to manually fix them.
You can remove the "not null" property from your column in mysql table if not necessary. when you remove "not null" property no need for "0000-00-00 00:00:00" conversion and problem is gone.
At least worked for me.
I believe this is help full for who are getting this below Exception on to pumping data through logstash
Error: logstash.inputs.jdbc - Exception when executing JDBC query {:exception=>#}
Answer:jdbc:mysql://localhost:3306/database_name?zeroDateTimeBehavior=convertToNull"
or if you are working with mysql

json formatting of timestamp

I got an AngularJS client, nodeJS server, and a MySQL DB.
I am trying to delete an entry of a table, when timestamp is a primery key with user Email.
The JSON giving me the this data from the DB:
[{"instanceTime":"2018-02-10T14:19:29.000Z","item":"write papter","email":"admin#gmail.com","ischeck":0},
{"instanceTime":"2018-02-10T14:19:33.000Z","item":"paint chair","email":"admin#gmail.com","ischeck":0},
{"instanceTime":"2018-02-10T15:07:34.000Z","item":"yes","email":"admin#gmail.com","ischeck":0}]
But the deletion with this "instanceTime" gives an error:
DELETE FROM tododb.taskstable WHERE (instanceTime like '2018-02-10T15:07:34.000Z' AND email like 'admin#gmail.com' );
errError: ER_TRUNCATED_WRONG_VALUE: Incorrect datetime value: '2018-02-10T15:07:34.000Z' for column 'instanceTime' at row 1
Why is the formating "2018-02-10T14:19:29.000Z" this way?
When I am using:
DELETE FROM taskstable
WHERE (instanceTime like "2018-02-10 14:19:29" AND email like "admin#gmail.com");
everything works just fine
I did 2 things to fix this problem.
Change DB time field to int(11) and inserted new value with the current UNIX timestamp instead-
insert into taskstable
values (UNIX_TIMESTAMP(NOW()),"to call mom","admin#gmail.com",false);
The UNIX timestamp is a lot easier to manage since it is just a countdown.
I changed the view formatting in the HTML page, to show UNIX time as the desired human-readable version, this way:
{{t.instanceTime * 1000 | date:'yyyy-MM-dd HH:mm:ss'}}
Not exactly what I asked, but I found this a lot easier.

Ruby active record inserting datetime instead of time in mysql

Rails Active Record save uses datetime in insert query although the datatype is time in mysql and time is set in model before saving
mysql schema:
rtime time DEFAULT NULL
ActiveRecord model: Abc
abc = Abc.new {'rtime'=> '18:23 PM'}
abc.save!
corresponding mysql query generated by active record:
insert into abces (rtime) values('2000-01-01 18:23:00');
Later in mysql only the time is stored and date is sliced off, and a warning is also generated.
+-----------------------+
| rtime |
+-----------------------+
| 18:23:00 |
+-----------------------+`
Why is the date appended with time while mysql insertion?
Rails version: 3.2.16
Looks like ActiveRecord often falls back to a DateTime object when assigning a Time in Rails 3+: https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/attribute_assignment.rb#L130
There's some documentation on the conversion method here: http://apidock.com/rails/Time/time_with_datetime_fallback/class. Also, there's a comment that hints at this on line 180 of the same file: # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
Thus it seems Rails 3 often treats Time objects as though they were DateTimes, which explains the odd insert query you're seeing. The behavior seems to be changed in Rails 4 so upgrading may resolve the issue.
In any case the date values seem to simply get truncated by MySQL hence the warning, but the stored time seems correct to me.
Finally, do you need a timezone for this time?

How do you properly update a mysql field with NULL?

How does one properly update a mysql field with a NULL value when using a variable in the sql query?
I have a variable called $timestamp. When it's set to date( Y-m-d h:i:s ) I have to wrap it in quotes because I'm passing a string in my mysql query. When $timestamp is set to NULL, the database query contains '' as the value for $timestamp and the field updates to 0000-00-00 00:00:00. It's important to keep this field as NULL to show that the process has never been run before.
I don't want to use now() because then my sql statement is not in sync with my class variable $timestamp.
I don't want to set $timestamp to 'NULL' because then that variable is not accurate. It's no longer NULL, it's set to a string that contains the word NULL.
What am I missing here?
The correct SQL syntax to set a column to NULL is:
UPDATE Table SET Column = NULL WHERE . . .
(note the lack of quotes around the literal NULL).
Are you performing this UPDATE using SQL or using some kind of framework? If a framework, it should recognize NULL values and pass them to the database correctly for you.
After a lot of research, I've found that this is a well known problem with no good solution if you are writing your sql queries outright.
The correct solution is to use a database abstraction layer like PDO ( for PHP ), or Active Record ( used in frameworks like Codeignitor and Ruby on Rails ).