Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #6019 (reopened defect)

Opened 3 years ago

Last modified 3 years ago

[PATCH] Changing default date format affects date objects written to MySQL

Reported by: kevin.olbrich@gmail.com Assigned to: David
Priority: normal Milestone: 1.2.7
Component: ActiveRecord Version: 1.1.6
Severity: normal Keywords: default date format
Cc:

Description

If you change the default date format to anything other than the default affects the way that dates are written to the database. MySQL doesn't understand those other formats very well, and it can easily lead to an invalid date in the database. This usually does not raise an exception, but just ends up writing the date as '0000-00-00'.

The solution for this may be to define a :db format that matches that used by the database, and then have the relevant ActiveRecord code use the :db format for formatting dates instead of the :default format.

Change History

09/11/06 22:32:32 changed by rwvtveer@gmail.com

The following patch will fix quoting for Date objects. The :db formats are never used as far as I can see. This patch has only been properly tested with MySQL.

diff -ru rails.orig/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
--- rails.orig/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb   2006-07-27 20:29:49.000000000 +0200
+++ rails/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb        2006-09-12 00:12:28.000000000 +0200
@@ -23,7 +23,7 @@
           when Float, Fixnum, Bignum    then value.to_s
           # BigDecimals need to be output in a non-normalized form and quoted.
           when BigDecimal               then value.to_s('F')
-          when Date                     then "'#{value.to_s}'"
+          when Date                     then "'#{value.strftime("%Y-%m-%d")}'"
           when Time, DateTime           then "'#{quoted_date(value)}'"
           else                          "'#{quote_string(value.to_yaml)}'"
         end
diff -ru rails.orig/activerecord/lib/active_record/connection_adapters/firebird_adapter.rb rails/activerecord/lib/active_record/connection_adapters/firebird_adapter.rb
--- rails.orig/activerecord/lib/active_record/connection_adapters/firebird_adapter.rb   2006-07-08 19:13:21.000000000 +0200
+++ rails/activerecord/lib/active_record/connection_adapters/firebird_adapter.rb        2006-09-12 00:13:14.000000000 +0200
@@ -319,6 +319,8 @@
       def quote(value, column = nil) # :nodoc:
         if [Time, DateTime].include?(value.class)
           "CAST('#{value.strftime("%Y-%m-%d %H:%M:%S")}' AS TIMESTAMP)"
+        elsif value.class == Date
+          "CAST('#{value.strftime("%Y-%m-%d")}' AS DATE)"
         else
           super
         end
diff -ru rails.orig/activerecord/lib/active_record/connection_adapters/sybase_adapter.rb rails/activerecord/lib/active_record/connection_adapters/sybase_adapter.rb
--- rails.orig/activerecord/lib/active_record/connection_adapters/sybase_adapter.rb     2006-07-08 22:35:56.000000000 +0200
+++ rails/activerecord/lib/active_record/connection_adapters/sybase_adapter.rb  2006-09-12 00:14:26.000000000 +0200
@@ -290,6 +290,7 @@
           when TrueClass             then '1'
           when FalseClass            then '0'
           when Float, Fixnum, Bignum then force_numeric?(column) ? value.to_s : "'#{value.to_s}'"
+          when Date                  then "'#{value.strftime("%Y-%m-%d")}'"
           when Time, DateTime        then "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
           else                       super
         end

I am sorry about posting it in this way and not uploading an attachment but the upload doesn't work at this time because the server disk appears to be full.

09/14/06 15:53:59 changed by olbrich

  • summary changed from Changing default date format affects date objects written to MySQL to [PATCH] Changing default date format affects date objects written to MySQL.

(follow-up: ↓ 4 ) 10/09/06 02:09:15 changed by david

  • status changed from new to closed.
  • resolution set to wontfix.

I think its a bad idea to ever change the default to_s. We may well have other parts of the code that relies on the default behavior. Instead, you should add your own predefined format. Kinda like :db is done.

(in reply to: ↑ 3 ) 10/09/06 02:25:12 changed by olbrich

Replying to david:

I think its a bad idea to ever change the default to_s. We may well have other parts of the code that relies on the default behavior. Instead, you should add your own predefined format. Kinda like :db is done.

This makes sense, but suggests that the 'to_s' function should not 'default' to the :default format (if that makes sense) and setting the default format should be deprecated.

I would also argue that if the DB is sensitive to the format that data is written in, it should specify it for the sake of robustness.

10/09/06 02:26:50 changed by david

I'd rather see a patch that prevents the changing of :default, then.

10/09/06 02:28:54 changed by olbrich

Agreed. Working on it.

10/09/06 03:07:31 changed by olbrich

Patch submitted. See Ticket #6363

10/09/06 07:51:32 changed by bitsweat

Shouldn't these cases just use .to_s(:db) ?

10/09/06 11:18:34 changed by olbrich

Perhaps, but I agree with David's assertion that changing the default behavior of 'to_s' is an inherently dangerous thing, and the problem with MySQL is an example of this.

10/09/06 11:56:53 changed by remvee

Isn't to_s also effected by the default locale ruby is running in? If so, doesn't this have the potential to break activerecord if database and application server use different locales?

Also, most adapters do format Time and DateTime but simply pass Date#to_s. Why facilitate those and not Date?

10/09/06 19:29:20 changed by bitsweat

  • status changed from closed to reopened.
  • resolution deleted.
  • milestone set to 1.2.

I agree, but I think that's a separate issue. As remvee comments, the behavior of to_s depends on posix locale. It should use a specific format rather than expecting the default doesn't change.