<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -13,9 +13,6 @@ module ActionView
     #   the select_month method would use simply &quot;date&quot; (which can be overwritten using &lt;tt&gt;:prefix&lt;/tt&gt;) instead of
     #   &quot;date[month]&quot;.
     module DateHelper
-      include ActionView::Helpers::TagHelper
-      DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
-
       # Reports the approximate distance in time between two Time or Date objects or integers as seconds.
       # Set &lt;tt&gt;include_seconds&lt;/tt&gt; to true if you want more detailed approximations when distance &lt; 1 min, 29 secs
       # Distances are reported based on the following table:
@@ -52,7 +49,7 @@ module ActionView
       #   distance_of_time_in_words(from_time, from_time - 45.seconds, true)  # =&gt; less than a minute
       #   distance_of_time_in_words(from_time, 76.seconds.from_now)           # =&gt; 1 minute
       #   distance_of_time_in_words(from_time, from_time + 1.year + 3.days)   # =&gt; about 1 year
-      #   distance_of_time_in_words(from_time, from_time + 4.years + 15.days + 30.minutes + 5.seconds) # =&gt; over 4 years
+      #   distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # =&gt; over 4 years
       #
       #   to_time = Time.now + 6.years + 19.days
       #   distance_of_time_in_words(from_time, to_time, true)     # =&gt; over 6 years
@@ -109,19 +106,36 @@ module ActionView
       alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
 
       # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based
-      # attribute (identified by +method+) on an object assigned to the template (identified by +object+). It's
-      # possible to tailor the selects through the +options+ hash, which accepts all the keys that each of the
-      # individual select builders do (like &lt;tt&gt;:use_month_numbers&lt;/tt&gt; for select_month) as well as a range of discard
-      # options. The discard options are &lt;tt&gt;:discard_year&lt;/tt&gt;, &lt;tt&gt;:discard_month&lt;/tt&gt; and &lt;tt&gt;:discard_day&lt;/tt&gt;. Set
-      # to true, they'll drop the respective select. Discarding the month select will also automatically discard the
-      # day select. It's also possible to explicitly set the order of the tags using the &lt;tt&gt;:order&lt;/tt&gt; option with an
-      # array of symbols &lt;tt&gt;:year&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:day&lt;/tt&gt; in the desired order. Symbols may be omitted
-      # and the respective select is not included.
-      #
-      # Pass the &lt;tt&gt;:default&lt;/tt&gt; option to set the default date. Use a Time object or a Hash of &lt;tt&gt;:year&lt;/tt&gt;,
-      # &lt;tt&gt;:month&lt;/tt&gt;, &lt;tt&gt;:day&lt;/tt&gt;, &lt;tt&gt;:hour&lt;/tt&gt;, &lt;tt&gt;:minute&lt;/tt&gt;, and &lt;tt&gt;:second&lt;/tt&gt;.
-      #
-      # Passing &lt;tt&gt;:disabled =&gt; true&lt;/tt&gt; as part of the +options+ will make elements inaccessible for change.
+      # attribute (identified by +method+) on an object assigned to the template (identified by +object+). You can
+      # the output in the +options+ hash.
+      #
+      # ==== Options
+      # * &lt;tt&gt;:use_month_numbers&lt;/tt&gt; - Set to true if you want to use month numbers rather than month names (e.g.
+      #    &quot;2&quot; instead of &quot;February&quot;).
+      # * &lt;tt&gt;:use_short_month&lt;/tt&gt;   - Set to true if you want to use the abbreviated month name instead of the full
+      #   name (e.g. &quot;Feb&quot; instead of &quot;February&quot;).
+      # * &lt;tt&gt;:add_month_number&lt;/tt&gt;  - Set to true if you want to show both, the month's number and name (e.g.
+      #   &quot;2 - February&quot; instead of &quot;February&quot;).
+      # * &lt;tt&gt;:use_month_names&lt;/tt&gt;   - Set to an array with 12 month names if you want to customize month names.
+      #   Note: You can also use Rails' new i18n functionality for this.
+      # * &lt;tt&gt;:date_separator&lt;/tt&gt;    - Specifies a string to separate the date fields. Default is &quot;&quot; (i.e. nothing).
+      # * &lt;tt&gt;:start_year&lt;/tt&gt;        - Set the start year for the year select. Default is &lt;tt&gt;Time.now.year - 5&lt;/tt&gt;.
+      # * &lt;tt&gt;:end_year&lt;/tt&gt;          - Set the end year for the year select. Default is &lt;tt&gt;Time.now.year + 5&lt;/tt&gt;.
+      # * &lt;tt&gt;:discard_day&lt;/tt&gt;       - Set to true if you don't want to show a day select. This includes the day
+      #   as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
+      #   first of the given month in order to not create invalid dates like 31 February.
+      # * &lt;tt&gt;:discard_month&lt;/tt&gt;     - Set to true if you don't want to show a month select. This includes the month
+      #   as a hidden field instead of showing a select field. Also note that this implicitly sets :discard_day to true.
+      # * &lt;tt&gt;:discard_year&lt;/tt&gt;      - Set to true if you don't want to show a year select. This includes the year
+      #   as a hidden field instead of showing a select field.
+      # * &lt;tt&gt;:order&lt;/tt&gt;             - Set to an array containing &lt;tt&gt;:day&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:year&lt;/tt&gt; do
+      #   customize the order in which the select fields are shown. If you leave out any of the symbols, the respective
+      #   select will not be shown (like when you set &lt;tt&gt;:discard_xxx =&gt; true&lt;/tt&gt;. Defaults to the order defined in
+      #   the respective locale (e.g. [:year, :month, :day] in the en-US locale that ships with Rails).
+      # * &lt;tt&gt;:include_blank&lt;/tt&gt;     - Include a blank option in every select field so it's possible to set empty
+      #   dates.
+      # * &lt;tt&gt;:default&lt;/tt&gt;           - Set a default date if the affected date isn't set or is nil.
+      # * &lt;tt&gt;:disabled&lt;/tt&gt;          - Set to true if you want show the select fields as disabled.
       #
       # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
       #
@@ -165,9 +179,9 @@ module ActionView
         InstanceTag.new(object_name, method, self, options.delete(:object)).to_date_select_tag(options, html_options)
       end
 
-      # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
-      # time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
-      # You can include the seconds with &lt;tt&gt;:include_seconds&lt;/tt&gt;.
+      # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a
+      # specified time-based attribute (identified by +method+) on an object assigned to the template (identified by
+      # +object+). You can include the seconds with &lt;tt&gt;:include_seconds&lt;/tt&gt;.
       #
       # This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
       # &lt;tt&gt;:ignore_date&lt;/tt&gt; is set to +true+.
@@ -178,7 +192,8 @@ module ActionView
       #   # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
       #   time_select(&quot;post&quot;, &quot;sunrise&quot;)
       #
-      #   # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute
+      #   # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted
+      #   # attribute
       #   time_select(&quot;order&quot;, &quot;submitted&quot;)
       #
       #   # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute
@@ -210,7 +225,8 @@ module ActionView
       # If anything is passed in the html_options hash it will be applied to every select tag in the set.
       #
       # ==== Examples
-      #   # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
+      #   # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on
+      #   # attribute
       #   datetime_select(&quot;post&quot;, &quot;written_on&quot;)
       #
       #   # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
@@ -230,12 +246,12 @@ module ActionView
         InstanceTag.new(object_name, method, self, options.delete(:object)).to_datetime_select_tag(options, html_options)
       end
 
-      # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
-      # It's also possible to explicitly set the order of the tags using the &lt;tt&gt;:order&lt;/tt&gt; option with an array of
-      # symbols &lt;tt&gt;:year&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:day&lt;/tt&gt; in the desired order. If you do not supply a Symbol,
-      # it will be appended onto the &lt;tt&gt;:order&lt;/tt&gt; passed in. You can also add &lt;tt&gt;:date_separator&lt;/tt&gt;,
-      # &lt;tt&gt;:datetime_separator&lt;/tt&gt; and &lt;tt&gt;:time_separator&lt;/tt&gt; keys to the +options+ to control visual display of
-      # the elements.
+      # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the
+      # +datetime+. It's also possible to explicitly set the order of the tags using the &lt;tt&gt;:order&lt;/tt&gt; option with
+      # an array of symbols &lt;tt&gt;:year&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:day&lt;/tt&gt; in the desired order. If you do not
+      # supply a Symbol, it will be appended onto the &lt;tt&gt;:order&lt;/tt&gt; passed in. You can also add
+      # &lt;tt&gt;:date_separator&lt;/tt&gt;, &lt;tt&gt;:datetime_separator&lt;/tt&gt; and &lt;tt&gt;:time_separator&lt;/tt&gt; keys to the +options+ to
+      # control visual display of the elements.
       #
       # If anything is passed in the html_options hash it will be applied to every select tag in the set.
       #
@@ -270,14 +286,13 @@ module ActionView
       #   select_datetime(my_date_time, :prefix =&gt; 'payday')
       #
       def select_datetime(datetime = Time.current, options = {}, html_options = {})
-        separator = options[:datetime_separator] || ''
-        select_date(datetime, options, html_options) + separator + select_time(datetime, options, html_options)
+        DateTimeSelector.new(datetime, options, html_options).select_datetime
       end
 
       # Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
       # It's possible to explicitly set the order of the tags using the &lt;tt&gt;:order&lt;/tt&gt; option with an array of
-      # symbols &lt;tt&gt;:year&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:day&lt;/tt&gt; in the desired order. If you do not supply a Symbol, it
-      # will be appended onto the &lt;tt&gt;:order&lt;/tt&gt; passed in.
+      # symbols &lt;tt&gt;:year&lt;/tt&gt;, &lt;tt&gt;:month&lt;/tt&gt; and &lt;tt&gt;:day&lt;/tt&gt; in the desired order. If you do not supply a Symbol,
+      # it will be appended onto the &lt;tt&gt;:order&lt;/tt&gt; passed in.
       #
       # If anything is passed in the html_options hash it will be applied to every select tag in the set.
       #
@@ -307,12 +322,7 @@ module ActionView
       #   select_date(my_date, :prefix =&gt; 'payday')
       #
       def select_date(date = Date.current, options = {}, html_options = {})
-        options.reverse_merge!(:order =&gt; [], :date_separator =&gt; '')
-        [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
-
-        options[:order].inject([]) { |s, o|
-          s &lt;&lt; self.send(&quot;select_#{o}&quot;, date, options, html_options)
-        }.join(options[:date_separator])
+        DateTimeSelector.new(date, options, html_options).select_date
       end
 
       # Returns a set of html select-tags (one for hour and minute)
@@ -343,9 +353,7 @@ module ActionView
       #   select_time(my_time, :time_separator =&gt; ':', :include_seconds =&gt; true)
       #
       def select_time(datetime = Time.current, options = {}, html_options = {})
-        separator = options[:time_separator] || ''
-        select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) +
-          (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '')
+        DateTimeSelector.new(datetime, options, html_options).select_time
       end
 
       # Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
@@ -366,15 +374,12 @@ module ActionView
       #   select_second(my_time, :field_name =&gt; 'interval')
       #
       def select_second(datetime, options = {}, html_options = {})
-        val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
-        options[:use_hidden] ?
-          (options[:include_seconds] ? _date_hidden_html(options[:field_name] || 'second', val, options) : '') :
-          _date_select_html(options[:field_name] || 'second', _date_build_options(val), options, html_options)
+        DateTimeSelector.new(datetime, options, html_options).select_second
       end
 
       # Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
-      # Also can return a select tag with options by &lt;tt&gt;minute_step&lt;/tt&gt; from 0 through 59 with the 00 minute selected
-      # The &lt;tt&gt;minute&lt;/tt&gt; can also be substituted for a minute number.
+      # Also can return a select tag with options by &lt;tt&gt;minute_step&lt;/tt&gt; from 0 through 59 with the 00 minute
+      # selected. The &lt;tt&gt;minute&lt;/tt&gt; can also be substituted for a minute number.
       # Override the field name using the &lt;tt&gt;:field_name&lt;/tt&gt; option, 'minute' by default.
       #
       # ==== Examples
@@ -391,11 +396,7 @@ module ActionView
       #   select_minute(my_time, :field_name =&gt; 'stride')
       #
       def select_minute(datetime, options = {}, html_options = {})
-        val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
-        options[:use_hidden] ?
-          _date_hidden_html(options[:field_name] || 'minute', val, options) :
-          _date_select_html(options[:field_name] || 'minute',
-            _date_build_options(val, :step =&gt; options[:minute_step]), options, html_options)
+        DateTimeSelector.new(datetime, options, html_options).select_minute
       end
 
       # Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
@@ -416,9 +417,7 @@ module ActionView
       #   select_minute(my_time, :field_name =&gt; 'stride')
       #
       def select_hour(datetime, options = {}, html_options = {})
-        val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
-        options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'hour', val, options) :
-          _date_select_html(options[:field_name] || 'hour', _date_build_options(val, :end =&gt; 23), options, html_options)
+        DateTimeSelector.new(datetime, options, html_options).select_hour
       end
 
       # Returns a select tag with options for each of the days 1 through 31 with the current day selected.
@@ -439,11 +438,7 @@ module ActionView
       #   select_day(my_time, :field_name =&gt; 'due')
       #
       def select_day(date, options = {}, html_options = {})
-        val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
-        options[:use_hidden] ? _date_hidden_html(options[:field_name] || 'day', val, options) :
-          _date_select_html(options[:field_name] || 'day',
-            _date_build_options(val, :start =&gt; 1, :end =&gt; 31, :leading_zeros =&gt; false),
-            options, html_options)
+        DateTimeSelector.new(date, options, html_options).select_day
       end
 
       # Returns a select tag with options for each of the months January through December with the current month
@@ -481,36 +476,7 @@ module ActionView
       #   select_month(Date.today, :use_month_names =&gt; %w(Januar Februar Marts ...))
       #
       def select_month(date, options = {}, html_options = {})
-        locale = options[:locale]
-
-        val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
-        if options[:use_hidden]
-          _date_hidden_html(options[:field_name] || 'month', val, options)
-        else
-          month_options = []
-          month_names = options[:use_month_names] || begin
-            key = options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
-            I18n.translate key, :locale =&gt; locale
-          end
-          month_names.unshift(nil) if month_names.size &lt; 13
-
-          1.upto(12) do |month_number|
-            month_name = if options[:use_month_numbers]
-              month_number
-            elsif options[:add_month_numbers]
-              month_number.to_s + ' - ' + month_names[month_number]
-            else
-              month_names[month_number]
-            end
-
-            month_options &lt;&lt; ((val == month_number) ?
-              content_tag(:option, month_name, :value =&gt; month_number, :selected =&gt; &quot;selected&quot;) :
-              content_tag(:option, month_name, :value =&gt; month_number)
-            )
-            month_options &lt;&lt; &quot;\n&quot;
-          end
-          _date_select_html(options[:field_name] || 'month', month_options.join, options, html_options)
-        end
+        DateTimeSelector.new(date, options, html_options).select_month
       end
 
       # Returns a select tag with options for each of the five years on each side of the current, which is selected.
@@ -537,158 +503,369 @@ module ActionView
       #   select_year(2006, :start_year =&gt; 2000, :end_year =&gt; 2010)
       #
       def select_year(date, options = {}, html_options = {})
-        if !date || date == 0
+        DateTimeSelector.new(date, options, html_options).select_year
+      end
+    end
+
+    class DateTimeSelector #:nodoc:
+      extend ActiveSupport::Memoizable
+      include ActionView::Helpers::TagHelper
+
+      DEFAULT_PREFIX = 'date'.freeze unless const_defined?('DEFAULT_PREFIX')
+      POSITION = {
+        :year =&gt; 1, :month =&gt; 2, :day =&gt; 3, :hour =&gt; 4, :minute =&gt; 5, :second =&gt; 6
+      }.freeze unless const_defined?('POSITION')
+
+      def initialize(datetime, options = {}, html_options = {})
+        @options      = options.dup
+        @html_options = html_options.dup
+        @datetime     = datetime
+      end
+
+      def select_datetime
+        # TODO: Remove tag conditional
+        # Ideally we could just join select_date and select_date for the tag case
+        if @options[:tag] &amp;&amp; @options[:ignore_date]
+          select_time
+        elsif @options[:tag]
+          order = date_order.dup
+          order -= [:hour, :minute, :second]
+
+          @options[:discard_year]   ||= true unless order.include?(:year)
+          @options[:discard_month]  ||= true unless order.include?(:month)
+          @options[:discard_day]    ||= true if @options[:discard_month] || !order.include?(:day)
+          @options[:discard_minute] ||= true if @options[:discard_hour]
+          @options[:discard_second] ||= true unless @options[:include_seconds] &amp;&amp; !@options[:discard_minute]
+
+          # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+          # valid (otherwise it could be 31 and february wouldn't be a valid date)
+          if @options[:discard_day] &amp;&amp; !@options[:discard_month]
+            @datetime = @datetime.change(:day =&gt; 1)
+          end
+
+          [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
+          order += [:hour, :minute, :second] unless @options[:discard_hour]
+
+          build_selects_from_types(order)
+        else
+          &quot;#{select_date}#{@options[:datetime_separator]}#{select_time}&quot;
+        end
+      end
+
+      def select_date
+        order = date_order.dup
+
+        # TODO: Remove tag conditional
+        if @options[:tag]
+          @options[:discard_hour]     = true
+          @options[:discard_minute]   = true
+          @options[:discard_second]   = true
+
+          @options[:discard_year]   ||= true unless order.include?(:year)
+          @options[:discard_month]  ||= true unless order.include?(:month)
+          @options[:discard_day]    ||= true if @options[:discard_month] || !order.include?(:day)
+
+          # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are
+          # valid (otherwise it could be 31 and february wouldn't be a valid date)
+          if @options[:discard_day] &amp;&amp; !@options[:discard_month]
+            @datetime = @datetime.change(:day =&gt; 1)
+          end
+        end
+
+        [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
+
+        build_selects_from_types(order)
+      end
+
+      def select_time
+        order = []
+
+        # TODO: Remove tag conditional
+        if @options[:tag]
+          @options[:discard_month]    = true
+          @options[:discard_year]     = true
+          @options[:discard_day]      = true
+          @options[:discard_second] ||= true unless @options[:include_seconds]
+
+          order += [:year, :month, :day] unless @options[:ignore_date]
+        end
+
+        order += [:hour, :minute]
+        order &lt;&lt; :second if @options[:include_seconds]
+
+        build_selects_from_types(order)
+      end
+
+      def select_second
+        if @options[:use_hidden] || @options[:discard_second]
+          build_hidden(:second, sec) if @options[:include_seconds]
+        else
+          build_options_and_select(:second, sec)
+        end
+      end
+
+      def select_minute
+        if @options[:use_hidden] || @options[:discard_minute]
+          build_hidden(:minute, min)
+        else
+          build_options_and_select(:minute, min, :step =&gt; @options[:minute_step])
+        end
+      end
+
+      def select_hour
+        if @options[:use_hidden] || @options[:discard_hour]
+          build_hidden(:hour, hour)
+        else
+          build_options_and_select(:hour, hour, :end =&gt; 23)
+        end
+      end
+
+      def select_day
+        if @options[:use_hidden] || @options[:discard_day]
+          build_hidden(:day, day)
+        else
+          build_options_and_select(:day, day, :start =&gt; 1, :end =&gt; 31, :leading_zeros =&gt; false)
+        end
+      end
+
+      def select_month
+        if @options[:use_hidden] || @options[:discard_month]
+          build_hidden(:month, month)
+        else
+          month_options = []
+          1.upto(12) do |month_number|
+            options = { :value =&gt; month_number }
+            options[:selected] = &quot;selected&quot; if month == month_number
+            month_options &lt;&lt; content_tag(:option, month_name(month_number), options) + &quot;\n&quot;
+          end
+          build_select(:month, month_options.join)
+        end
+      end
+
+      def select_year
+        if !@datetime || @datetime == 0
           val = ''
           middle_year = Date.today.year
-        elsif date.kind_of?(Fixnum)
-          val = middle_year = date
         else
-          val = middle_year = date.year
+          val = middle_year = year
         end
 
-        if options[:use_hidden]
-          _date_hidden_html(options[:field_name] || 'year', val, options)
+        if @options[:use_hidden] || @options[:discard_year]
+          build_hidden(:year, val)
         else
-          options[:start_year] ||= middle_year - 5
-          options[:end_year]   ||= middle_year + 5
-          step                   = options[:start_year] &lt; options[:end_year] ? 1 : -1
-
-          _date_select_html(options[:field_name] || 'year',
-            _date_build_options(val,
-              :start =&gt; options[:start_year],
-              :end =&gt; options[:end_year],
-              :step =&gt; step,
-              :leading_zeros =&gt; false
-            ), options, html_options)
+          options                 = {}
+          options[:start]         = @options[:start_year] || middle_year - 5
+          options[:end]           = @options[:end_year] || middle_year + 5
+          options[:step]          = options[:start] &lt; options[:end] ? 1 : -1
+          options[:leading_zeros] = false
+
+          build_options_and_select(:year, val, options)
         end
       end
 
       private
-        def _date_build_options(selected, options={})
-          options.reverse_merge!(:start =&gt; 0, :end =&gt; 59, :step =&gt; 1, :leading_zeros =&gt; true)
+        %w( sec min hour day month year ).each do |method|
+          define_method(method) do
+            @datetime.kind_of?(Fixnum) ? @datetime : @datetime.send(method) if @datetime
+          end
+        end
+
+        # Returns translated month names, but also ensures that a custom month
+        # name array has a leading nil element
+        def month_names
+          month_names = @options[:use_month_names] || translated_month_names
+          month_names.unshift(nil) if month_names.size &lt; 13
+          month_names
+        end
+        memoize :month_names
+
+        # Returns translated month names
+        #  =&gt; [nil, &quot;January&quot;, &quot;February&quot;, &quot;March&quot;,
+        #           &quot;April&quot;, &quot;May&quot;, &quot;June&quot;, &quot;July&quot;,
+        #           &quot;August&quot;, &quot;September&quot;, &quot;October&quot;,
+        #           &quot;November&quot;, &quot;December&quot;]
+        #
+        # If :use_short_month option is set
+        #  =&gt; [nil, &quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;,
+        #           &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;]
+        def translated_month_names
+          begin
+            key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
+            I18n.translate(key, :locale =&gt; @options[:locale])
+          end
+        end
+
+        # Lookup month name for number
+        #  month_name(1) =&gt; &quot;January&quot;
+        #
+        # If :use_month_numbers option is passed
+        #  month_name(1) =&gt; 1
+        #
+        # If :add_month_numbers option is passed
+        #  month_name(1) =&gt; &quot;1 - January&quot;
+        def month_name(number)
+          if @options[:use_month_numbers]
+            number
+          elsif @options[:add_month_numbers]
+            &quot;#{number} - #{month_names[number]}&quot;
+          else
+            month_names[number]
+          end
+        end
+
+        def date_order
+          @options[:order] || translated_date_order
+        end
+        memoize :date_order
+
+        def translated_date_order
+          begin
+            I18n.translate(:'date.order', :locale =&gt; @options[:locale]) || []
+          end
+        end
+
+        # Build full select tag from date type and options
+        def build_options_and_select(type, selected, options = {})
+          build_select(type, build_options(selected, options))
+        end
+
+        # Build select option html from date value and options
+        #  build_options(15, :start =&gt; 1, :end =&gt; 31)
+        #  =&gt; &quot;&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;
+        #      &lt;option value=\&quot;2\&quot;&gt;2&lt;/option&gt;
+        #      &lt;option value=\&quot;3\&quot;&gt;3&lt;/option&gt;...&quot;
+        def build_options(selected, options = {})
+          start         = options.delete(:start) || 0
+          stop          = options.delete(:end) || 59
+          step          = options.delete(:step) || 1
+          leading_zeros = options.delete(:leading_zeros).nil? ? true : false
 
           select_options = []
-          (options[:start] || 0).step((options[:end] || 59), options[:step] || 1) do |i|
-            value = options[:leading_zeros] ? sprintf(&quot;%02d&quot;, i) : i
+          start.step(stop, step) do |i|
+            value = leading_zeros ? sprintf(&quot;%02d&quot;, i) : i
             tag_options = { :value =&gt; value }
             tag_options[:selected] = &quot;selected&quot; if selected == i
-
             select_options &lt;&lt; content_tag(:option, value, tag_options)
           end
           select_options.join(&quot;\n&quot;) + &quot;\n&quot;
         end
 
-        def _date_select_html(type, html_options, options, select_tag_options = {})
-          _date_name_and_id_from_options(options, type)
-          select_options = {:id =&gt; options[:id], :name =&gt; options[:name]}
-          select_options.merge!(:disabled =&gt; 'disabled') if options[:disabled]
-          select_options.merge!(select_tag_options) unless select_tag_options.empty?
+        # Builds select tag from date type and html select options
+        #  build_select(:month, &quot;&lt;option value=&quot;1&quot;&gt;January&lt;/option&gt;...&quot;)
+        #  =&gt; &quot;&lt;select id=&quot;post_written_on_2i&quot; name=&quot;post[written_on(2i)]&quot;&gt;
+        #        &lt;option value=&quot;1&quot;&gt;January&lt;/option&gt;...
+        #      &lt;/select&gt;&quot;
+        def build_select(type, select_options_as_html)
+          select_options = {
+            :id =&gt; input_id_from_type(type),
+            :name =&gt; input_name_from_type(type)
+          }.merge(@html_options)
+          select_options.merge!(:disabled =&gt; 'disabled') if @options[:disabled]
+
           select_html = &quot;\n&quot;
-          select_html &lt;&lt; content_tag(:option, '', :value =&gt; '') + &quot;\n&quot; if options[:include_blank]
-          select_html &lt;&lt; html_options.to_s
+          select_html &lt;&lt; content_tag(:option, '', :value =&gt; '') + &quot;\n&quot; if @options[:include_blank]
+          select_html &lt;&lt; select_options_as_html.to_s
+
           content_tag(:select, select_html, select_options) + &quot;\n&quot;
         end
 
-        def _date_hidden_html(type, value, options)
-          _date_name_and_id_from_options(options, type)
-          hidden_html = tag(:input, :type =&gt; &quot;hidden&quot;, :id =&gt; options[:id], :name =&gt; options[:name], :value =&gt; value) + &quot;\n&quot;
+        # Builds hidden input tag for date part and value
+        #  build_hidden(:year, 2008)
+        #  =&gt; &quot;&lt;input id=&quot;post_written_on_1i&quot; name=&quot;post[written_on(1i)]&quot; type=&quot;hidden&quot; value=&quot;2008&quot; /&gt;&quot;
+        def build_hidden(type, value)
+          tag(:input, {
+            :type =&gt; &quot;hidden&quot;,
+            :id =&gt; input_id_from_type(type),
+            :name =&gt; input_name_from_type(type),
+            :value =&gt; value
+          }) + &quot;\n&quot;
         end
 
-        def _date_name_and_id_from_options(options, type)
-          options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : &quot;[#{type}]&quot;)
-          options[:id] = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
+        # Returns the name attribute for the input tag
+        #  =&gt; post[written_on(1i)]
+        def input_name_from_type(type)
+          prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
+          prefix += &quot;[#{@options[:index]}]&quot; if @options[:index]
+
+          field_name = @options[:field_name] || type
+          if @options[:include_position]
+            field_name += &quot;(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)&quot;
+          end
+
+          @options[:discard_type] ? prefix : &quot;#{prefix}[#{field_name}]&quot;
+        end
+
+        # Returns the id attribute for the input tag
+        #  =&gt; &quot;post_written_on_1i&quot;
+        def input_id_from_type(type)
+          input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
+        end
+
+        # Given an ordering of datetime components, create the selection html
+        # and join them with their appropriate seperators
+        def build_selects_from_types(order)
+          select = ''
+          order.reverse.each do |type|
+            separator = separator(type) unless type == order.first # don't add on last field
+            select.insert(0, separator.to_s + send(&quot;select_#{type}&quot;).to_s)
+          end
+          select
+        end
+
+        # Returns the separator for a given datetime component
+        def separator(type)
+          case type
+            when :month, :day
+              @options[:date_separator]
+            when :hour
+              (@options[:discard_year] &amp;&amp; @options[:discard_day]) ? &quot;&quot; : @options[:datetime_separator]
+            when :minute
+              @options[:time_separator]
+            when :second
+              @options[:include_seconds] ? @options[:time_separator] : &quot;&quot;
+          end
         end
     end
 
     class InstanceTag #:nodoc:
-      include DateHelper
-
       def to_date_select_tag(options = {}, html_options = {})
-        date_or_time_select(options.merge(:discard_hour =&gt; true), html_options)
+        datetime_selector(options, html_options).select_date
       end
 
       def to_time_select_tag(options = {}, html_options = {})
-        date_or_time_select(options.merge(:discard_year =&gt; true, :discard_month =&gt; true), html_options)
+        datetime_selector(options, html_options).select_time
       end
 
       def to_datetime_select_tag(options = {}, html_options = {})
-        date_or_time_select(options, html_options)
+        datetime_selector(options, html_options).select_datetime
       end
 
       private
-        def date_or_time_select(options, html_options = {})
-          locale = options[:locale]
-
-          defaults = { :discard_type =&gt; true }
-          options  = defaults.merge(options)
-          datetime = value(object)
-          datetime ||= default_time_from_options(options[:default]) unless options[:include_blank]
-
-          position = { :year =&gt; 1, :month =&gt; 2, :day =&gt; 3, :hour =&gt; 4, :minute =&gt; 5, :second =&gt; 6 }
-
-          order = options[:order] ||= I18n.translate(:'date.order', :locale =&gt; locale)
-
-          # Discard explicit and implicit by not being included in the :order
-          discard = {}
-          discard[:year]   = true if options[:discard_year] or !order.include?(:year)
-          discard[:month]  = true if options[:discard_month] or !order.include?(:month)
-          discard[:day]    = true if options[:discard_day] or discard[:month] or !order.include?(:day)
-          discard[:hour]   = true if options[:discard_hour]
-          discard[:minute] = true if options[:discard_minute] or discard[:hour]
-          discard[:second] = true unless options[:include_seconds] &amp;&amp; !discard[:minute]
-
-          # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are valid
-          # (otherwise it could be 31 and february wouldn't be a valid date)
-          if datetime &amp;&amp; discard[:day] &amp;&amp; !discard[:month]
-            datetime = datetime.change(:day =&gt; 1)
-          end
-
-          # Maintain valid dates by including hidden fields for discarded elements
-          [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
-
-          # Ensure proper ordering of :hour, :minute and :second
-          [:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }
-
-          date_or_time_select = ''
-          order.reverse.each do |param|
-            # Send hidden fields for discarded elements once output has started
-            # This ensures AR can reconstruct valid dates using ParseDate
-            next if discard[param] &amp;&amp; (date_or_time_select.empty? || options[:ignore_date])
-
-            date_or_time_select.insert(0,
-              self.send(&quot;select_#{param}&quot;,
-                datetime,
-                options_with_prefix(position[param], options.merge(:use_hidden =&gt; discard[param])),
-                html_options))
-            date_or_time_select.insert(0,
-              case param
-                when :hour then (discard[:year] &amp;&amp; discard[:day] ? &quot;&quot; : &quot; &amp;mdash; &quot;)
-                when :minute then &quot; : &quot;
-                when :second then options[:include_seconds] ? &quot; : &quot; : &quot;&quot;
-                else &quot;&quot;
-              end)
-          end
-
-          date_or_time_select
+        def datetime_selector(options, html_options)
+          datetime = value(object) || default_datetime(options)
+
+          options = options.dup
+          options[:field_name]           = @method_name
+          options[:include_position]     = true
+          options[:prefix]             ||= @object_name
+          options[:index]              ||= @auto_index
+          options[:datetime_separator] ||= ' &amp;mdash; '
+          options[:time_separator]     ||= ' : '
+
+          DateTimeSelector.new(datetime, options.merge(:tag =&gt; true), html_options)
         end
 
-        def options_with_prefix(position, options)
-          prefix = &quot;#{@object_name}&quot;
-          if options[:index]
-            prefix &lt;&lt; &quot;[#{options[:index]}]&quot;
-          elsif @auto_index
-            prefix &lt;&lt; &quot;[#{@auto_index}]&quot;
-          end
-          options.merge(:prefix =&gt; &quot;#{prefix}[#{@method_name}(#{position}i)]&quot;)
-        end
+        def default_datetime(options)
+          return if options[:include_blank]
 
-        def default_time_from_options(default)
-          case default
+          case options[:default]
             when nil
               Time.current
             when Date, Time
-              default
+              options[:default]
             else
+              default = options[:default].dup
+
               # Rename :minute and :second to :min and :sec
               default[:min] ||= default[:minute]
               default[:sec] ||= default[:second]
@@ -699,8 +876,11 @@ module ActionView
                 default[key] ||= time.send(key)
               end
 
-              Time.utc_time(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec])
-            end
+              Time.utc_time(
+                default[:year], default[:month], default[:day],
+                default[:hour], default[:min], default[:sec]
+              )
+          end
         end
     end
 </diff>
      <filename>actionpack/lib/action_view/helpers/date_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,22 +3,22 @@ require 'abstract_unit'
 class DateHelperDistanceOfTimeInWordsI18nTests &lt; Test::Unit::TestCase
   include ActionView::Helpers::DateHelper
   attr_reader :request
-  
+
   def setup
     @from = Time.mktime(2004, 6, 6, 21, 45, 0)
   end
-  
+
   uses_mocha 'date_helper_distance_of_time_in_words_i18n_test' do
     # distance_of_time_in_words
 
     def test_distance_of_time_in_words_calls_i18n
       { # with include_seconds
-        [2.seconds,  true]  =&gt; [:'less_than_x_seconds', 5],   
-        [9.seconds,  true]  =&gt; [:'less_than_x_seconds', 10],  
-        [19.seconds, true]  =&gt; [:'less_than_x_seconds', 20],  
-        [30.seconds, true]  =&gt; [:'half_a_minute',       nil], 
-        [59.seconds, true]  =&gt; [:'less_than_x_minutes', 1], 
-        [60.seconds, true]  =&gt; [:'x_minutes',           1], 
+        [2.seconds,  true]  =&gt; [:'less_than_x_seconds', 5],
+        [9.seconds,  true]  =&gt; [:'less_than_x_seconds', 10],
+        [19.seconds, true]  =&gt; [:'less_than_x_seconds', 20],
+        [30.seconds, true]  =&gt; [:'half_a_minute',       nil],
+        [59.seconds, true]  =&gt; [:'less_than_x_minutes', 1],
+        [60.seconds, true]  =&gt; [:'x_minutes',           1],
 
         # without include_seconds
         [29.seconds, false] =&gt; [:'less_than_x_minutes', 1],
@@ -38,7 +38,7 @@ class DateHelperDistanceOfTimeInWordsI18nTests &lt; Test::Unit::TestCase
 
     def assert_distance_of_time_in_words_translates_key(passed, expected)
       diff, include_seconds = *passed
-      key, count = *expected    
+      key, count = *expected
       to = @from + diff
 
       options = {:locale =&gt; 'en-US', :scope =&gt; :'datetime.distance_in_words'}
@@ -49,11 +49,11 @@ class DateHelperDistanceOfTimeInWordsI18nTests &lt; Test::Unit::TestCase
     end
   end
 end
-  
+
 class DateHelperSelectTagsI18nTests &lt; Test::Unit::TestCase
   include ActionView::Helpers::DateHelper
   attr_reader :request
-  
+
   uses_mocha 'date_helper_select_tags_i18n_tests' do
     def setup
       I18n.stubs(:translate).with(:'date.month_names', :locale =&gt; 'en-US').returns Date::MONTHNAMES</diff>
      <filename>actionpack/test/template/date_helper_i18n_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -557,11 +557,8 @@ class DateHelperTest &lt; ActionView::TestCase
   end
 
   def test_select_date_with_incomplete_order
-    expected = %(&lt;select id=&quot;date_first_day&quot; name=&quot;date[first][day]&quot;&gt;\n)
-    expected &lt;&lt; %(&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;4&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;5&lt;/option&gt;\n&lt;option value=&quot;6&quot;&gt;6&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;7&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;8&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;9&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;10&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;11&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;12&lt;/option&gt;\n&lt;option value=&quot;13&quot;&gt;13&lt;/option&gt;\n&lt;option value=&quot;14&quot;&gt;14&lt;/option&gt;\n&lt;option value=&quot;15&quot;&gt;15&lt;/option&gt;\n&lt;option value=&quot;16&quot; selected=&quot;selected&quot;&gt;16&lt;/option&gt;\n&lt;option value=&quot;17&quot;&gt;17&lt;/option&gt;\n&lt;option value=&quot;18&quot;&gt;18&lt;/option&gt;\n&lt;option value=&quot;19&quot;&gt;19&lt;/option&gt;\n&lt;option value=&quot;20&quot;&gt;20&lt;/option&gt;\n&lt;option value=&quot;21&quot;&gt;21&lt;/option&gt;\n&lt;option value=&quot;22&quot;&gt;22&lt;/option&gt;\n&lt;option value=&quot;23&quot;&gt;23&lt;/option&gt;\n&lt;option value=&quot;24&quot;&gt;24&lt;/option&gt;\n&lt;option value=&quot;25&quot;&gt;25&lt;/option&gt;\n&lt;option value=&quot;26&quot;&gt;26&lt;/option&gt;\n&lt;option value=&quot;27&quot;&gt;27&lt;/option&gt;\n&lt;option value=&quot;28&quot;&gt;28&lt;/option&gt;\n&lt;option value=&quot;29&quot;&gt;29&lt;/option&gt;\n&lt;option value=&quot;30&quot;&gt;30&lt;/option&gt;\n&lt;option value=&quot;31&quot;&gt;31&lt;/option&gt;\n)
-    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
-
-    expected &lt;&lt;  %(&lt;select id=&quot;date_first_year&quot; name=&quot;date[first][year]&quot;&gt;\n)
+    # NOTE: modified this test because of minimal API change
+    expected =  %(&lt;select id=&quot;date_first_year&quot; name=&quot;date[first][year]&quot;&gt;\n)
     expected &lt;&lt; %(&lt;option value=&quot;2003&quot; selected=&quot;selected&quot;&gt;2003&lt;/option&gt;\n&lt;option value=&quot;2004&quot;&gt;2004&lt;/option&gt;\n&lt;option value=&quot;2005&quot;&gt;2005&lt;/option&gt;\n)
     expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
 
@@ -569,6 +566,10 @@ class DateHelperTest &lt; ActionView::TestCase
     expected &lt;&lt; %(&lt;option value=&quot;1&quot;&gt;January&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;February&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;March&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;April&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;May&lt;/option&gt;\n&lt;option value=&quot;6&quot;&gt;June&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;July&lt;/option&gt;\n&lt;option value=&quot;8&quot; selected=&quot;selected&quot;&gt;August&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;September&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;October&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;November&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;December&lt;/option&gt;\n)
     expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
 
+    expected &lt;&lt; %(&lt;select id=&quot;date_first_day&quot; name=&quot;date[first][day]&quot;&gt;\n)
+    expected &lt;&lt; %(&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;4&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;5&lt;/option&gt;\n&lt;option value=&quot;6&quot;&gt;6&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;7&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;8&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;9&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;10&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;11&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;12&lt;/option&gt;\n&lt;option value=&quot;13&quot;&gt;13&lt;/option&gt;\n&lt;option value=&quot;14&quot;&gt;14&lt;/option&gt;\n&lt;option value=&quot;15&quot;&gt;15&lt;/option&gt;\n&lt;option value=&quot;16&quot; selected=&quot;selected&quot;&gt;16&lt;/option&gt;\n&lt;option value=&quot;17&quot;&gt;17&lt;/option&gt;\n&lt;option value=&quot;18&quot;&gt;18&lt;/option&gt;\n&lt;option value=&quot;19&quot;&gt;19&lt;/option&gt;\n&lt;option value=&quot;20&quot;&gt;20&lt;/option&gt;\n&lt;option value=&quot;21&quot;&gt;21&lt;/option&gt;\n&lt;option value=&quot;22&quot;&gt;22&lt;/option&gt;\n&lt;option value=&quot;23&quot;&gt;23&lt;/option&gt;\n&lt;option value=&quot;24&quot;&gt;24&lt;/option&gt;\n&lt;option value=&quot;25&quot;&gt;25&lt;/option&gt;\n&lt;option value=&quot;26&quot;&gt;26&lt;/option&gt;\n&lt;option value=&quot;27&quot;&gt;27&lt;/option&gt;\n&lt;option value=&quot;28&quot;&gt;28&lt;/option&gt;\n&lt;option value=&quot;29&quot;&gt;29&lt;/option&gt;\n&lt;option value=&quot;30&quot;&gt;30&lt;/option&gt;\n&lt;option value=&quot;31&quot;&gt;31&lt;/option&gt;\n)
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
     assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), :start_year =&gt; 2003, :end_year =&gt; 2005, :prefix =&gt; &quot;date[first]&quot;, :order =&gt; [:day])
   end
 
@@ -909,6 +910,10 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, select_datetime(Time.mktime(2003, 8, 16, 8, 4, 18), { :datetime_separator =&gt; &quot;&amp;mdash;&quot;, :date_separator =&gt; &quot;/&quot;, :time_separator =&gt; &quot;:&quot;, :start_year =&gt; 2003, :end_year =&gt; 2005, :prefix =&gt; &quot;date[first]&quot;}, :class =&gt; 'selector')
   end
 
+  def test_select_datetime_should_work_with_date
+    assert_nothing_raised { select_datetime(Date.today) }
+  end
+
   def test_select_time
     expected = %(&lt;select id=&quot;date_hour&quot; name=&quot;date[hour]&quot;&gt;\n)
     expected &lt;&lt; %(&lt;option value=&quot;00&quot;&gt;00&lt;/option&gt;\n&lt;option value=&quot;01&quot;&gt;01&lt;/option&gt;\n&lt;option value=&quot;02&quot;&gt;02&lt;/option&gt;\n&lt;option value=&quot;03&quot;&gt;03&lt;/option&gt;\n&lt;option value=&quot;04&quot;&gt;04&lt;/option&gt;\n&lt;option value=&quot;05&quot;&gt;05&lt;/option&gt;\n&lt;option value=&quot;06&quot;&gt;06&lt;/option&gt;\n&lt;option value=&quot;07&quot;&gt;07&lt;/option&gt;\n&lt;option value=&quot;08&quot; selected=&quot;selected&quot;&gt;08&lt;/option&gt;\n&lt;option value=&quot;09&quot;&gt;09&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;10&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;11&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;12&lt;/option&gt;\n&lt;option value=&quot;13&quot;&gt;13&lt;/option&gt;\n&lt;option value=&quot;14&quot;&gt;14&lt;/option&gt;\n&lt;option value=&quot;15&quot;&gt;15&lt;/option&gt;\n&lt;option value=&quot;16&quot;&gt;16&lt;/option&gt;\n&lt;option value=&quot;17&quot;&gt;17&lt;/option&gt;\n&lt;option value=&quot;18&quot;&gt;18&lt;/option&gt;\n&lt;option value=&quot;19&quot;&gt;19&lt;/option&gt;\n&lt;option value=&quot;20&quot;&gt;20&lt;/option&gt;\n&lt;option value=&quot;21&quot;&gt;21&lt;/option&gt;\n&lt;option value=&quot;22&quot;&gt;22&lt;/option&gt;\n&lt;option value=&quot;23&quot;&gt;23&lt;/option&gt;\n)
@@ -986,31 +991,8 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), {:include_seconds =&gt; false}, :class =&gt; 'selector')
   end
 
-  uses_mocha 'TestDatetimeAndTimeSelectUseTimeCurrentAsDefault' do
-    def test_select_datetime_uses_time_current_as_default
-      time = stub(:year =&gt; 2004, :month =&gt; 6, :day =&gt; 15, :hour =&gt; 16, :min =&gt; 35, :sec =&gt; 0)
-      Time.expects(:current).returns time
-      expects(:select_date).with(time, anything, anything).returns('')
-      expects(:select_time).with(time, anything, anything).returns('')
-      select_datetime
-    end
-
-    def test_select_time_uses_time_current_as_default
-      time = stub(:year =&gt; 2004, :month =&gt; 6, :day =&gt; 15, :hour =&gt; 16, :min =&gt; 35, :sec =&gt; 0)
-      Time.expects(:current).returns time
-      expects(:select_hour).with(time, anything, anything).returns('')
-      expects(:select_minute).with(time, anything, anything).returns('')
-      select_time
-    end
-
-    def test_select_date_uses_date_current_as_default
-      date = stub(:year =&gt; 2004, :month =&gt; 6, :day =&gt; 15)
-      Date.expects(:current).returns date
-      expects(:select_year).with(date, anything, anything).returns('')
-      expects(:select_month).with(date, anything, anything).returns('')
-      expects(:select_day).with(date, anything, anything).returns('')
-      select_date
-    end
+  def test_select_time_should_work_with_date
+    assert_nothing_raised { select_time(Date.today) }
   end
 
   def test_date_select
@@ -1231,6 +1213,30 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, output_buffer
   end
 
+  def test_date_select_with_separator
+    @post = Post.new
+    @post.written_on = Date.new(2004, 6, 15)
+
+    expected = %{&lt;select id=&quot;post_written_on_1i&quot; name=&quot;post[written_on(1i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1999&quot;&gt;1999&lt;/option&gt;\n&lt;option value=&quot;2000&quot;&gt;2000&lt;/option&gt;\n&lt;option value=&quot;2001&quot;&gt;2001&lt;/option&gt;\n&lt;option value=&quot;2002&quot;&gt;2002&lt;/option&gt;\n&lt;option value=&quot;2003&quot;&gt;2003&lt;/option&gt;\n&lt;option value=&quot;2004&quot; selected=&quot;selected&quot;&gt;2004&lt;/option&gt;\n&lt;option value=&quot;2005&quot;&gt;2005&lt;/option&gt;\n&lt;option value=&quot;2006&quot;&gt;2006&lt;/option&gt;\n&lt;option value=&quot;2007&quot;&gt;2007&lt;/option&gt;\n&lt;option value=&quot;2008&quot;&gt;2008&lt;/option&gt;\n&lt;option value=&quot;2009&quot;&gt;2009&lt;/option&gt;\n}
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; / &quot;
+
+    expected &lt;&lt; %{&lt;select id=&quot;post_written_on_2i&quot; name=&quot;post[written_on(2i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1&quot;&gt;January&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;February&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;March&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;April&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;May&lt;/option&gt;\n&lt;option value=&quot;6&quot; selected=&quot;selected&quot;&gt;June&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;July&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;August&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;September&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;October&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;November&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;December&lt;/option&gt;\n}
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; / &quot;
+
+    expected &lt;&lt; %{&lt;select id=&quot;post_written_on_3i&quot; name=&quot;post[written_on(3i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;4&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;5&lt;/option&gt;\n&lt;option value=&quot;6&quot;&gt;6&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;7&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;8&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;9&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;10&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;11&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;12&lt;/option&gt;\n&lt;option value=&quot;13&quot;&gt;13&lt;/option&gt;\n&lt;option value=&quot;14&quot;&gt;14&lt;/option&gt;\n&lt;option value=&quot;15&quot; selected=&quot;selected&quot;&gt;15&lt;/option&gt;\n&lt;option value=&quot;16&quot;&gt;16&lt;/option&gt;\n&lt;option value=&quot;17&quot;&gt;17&lt;/option&gt;\n&lt;option value=&quot;18&quot;&gt;18&lt;/option&gt;\n&lt;option value=&quot;19&quot;&gt;19&lt;/option&gt;\n&lt;option value=&quot;20&quot;&gt;20&lt;/option&gt;\n&lt;option value=&quot;21&quot;&gt;21&lt;/option&gt;\n&lt;option value=&quot;22&quot;&gt;22&lt;/option&gt;\n&lt;option value=&quot;23&quot;&gt;23&lt;/option&gt;\n&lt;option value=&quot;24&quot;&gt;24&lt;/option&gt;\n&lt;option value=&quot;25&quot;&gt;25&lt;/option&gt;\n&lt;option value=&quot;26&quot;&gt;26&lt;/option&gt;\n&lt;option value=&quot;27&quot;&gt;27&lt;/option&gt;\n&lt;option value=&quot;28&quot;&gt;28&lt;/option&gt;\n&lt;option value=&quot;29&quot;&gt;29&lt;/option&gt;\n&lt;option value=&quot;30&quot;&gt;30&lt;/option&gt;\n&lt;option value=&quot;31&quot;&gt;31&lt;/option&gt;\n}
+
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    assert_dom_equal expected, date_select(&quot;post&quot;, &quot;written_on&quot;, { :date_separator =&gt; &quot; / &quot; })
+  end
+
   def test_time_select
     @post = Post.new
     @post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
@@ -1330,6 +1336,33 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, output_buffer
   end
 
+  def test_time_select_with_separator
+    @post = Post.new
+    @post.written_on = Time.local(2004, 6, 15, 15, 16, 35)
+
+    expected = %{&lt;input type=&quot;hidden&quot; id=&quot;post_written_on_1i&quot; name=&quot;post[written_on(1i)]&quot; value=&quot;2004&quot; /&gt;\n}
+    expected &lt;&lt; %{&lt;input type=&quot;hidden&quot; id=&quot;post_written_on_2i&quot; name=&quot;post[written_on(2i)]&quot; value=&quot;6&quot; /&gt;\n}
+    expected &lt;&lt; %{&lt;input type=&quot;hidden&quot; id=&quot;post_written_on_3i&quot; name=&quot;post[written_on(3i)]&quot; value=&quot;15&quot; /&gt;\n}
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_written_on_4i&quot; name=&quot;post[written_on(4i)]&quot;&gt;\n)
+    0.upto(23) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 15}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; - &quot;
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_written_on_5i&quot; name=&quot;post[written_on(5i)]&quot;&gt;\n)
+    0.upto(59) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 16}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; - &quot;
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_written_on_6i&quot; name=&quot;post[written_on(6i)]&quot;&gt;\n)
+    0.upto(59) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 35}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    assert_dom_equal expected, time_select(&quot;post&quot;, &quot;written_on&quot;, { :time_separator =&gt; &quot; - &quot;, :include_seconds =&gt; true })
+  end
+
   def test_datetime_select
     @post = Post.new
     @post.updated_at = Time.local(2004, 6, 15, 16, 35)
@@ -1412,6 +1445,47 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, output_buffer
   end
 
+  def test_datetime_select_with_separators
+    @post = Post.new
+    @post.updated_at = Time.local(2004, 6, 15, 15, 16, 35)
+
+    expected = %{&lt;select id=&quot;post_updated_at_1i&quot; name=&quot;post[updated_at(1i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1999&quot;&gt;1999&lt;/option&gt;\n&lt;option value=&quot;2000&quot;&gt;2000&lt;/option&gt;\n&lt;option value=&quot;2001&quot;&gt;2001&lt;/option&gt;\n&lt;option value=&quot;2002&quot;&gt;2002&lt;/option&gt;\n&lt;option value=&quot;2003&quot;&gt;2003&lt;/option&gt;\n&lt;option value=&quot;2004&quot; selected=&quot;selected&quot;&gt;2004&lt;/option&gt;\n&lt;option value=&quot;2005&quot;&gt;2005&lt;/option&gt;\n&lt;option value=&quot;2006&quot;&gt;2006&lt;/option&gt;\n&lt;option value=&quot;2007&quot;&gt;2007&lt;/option&gt;\n&lt;option value=&quot;2008&quot;&gt;2008&lt;/option&gt;\n&lt;option value=&quot;2009&quot;&gt;2009&lt;/option&gt;\n}
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; / &quot;
+
+    expected &lt;&lt; %{&lt;select id=&quot;post_updated_at_2i&quot; name=&quot;post[updated_at(2i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1&quot;&gt;January&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;February&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;March&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;April&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;May&lt;/option&gt;\n&lt;option value=&quot;6&quot; selected=&quot;selected&quot;&gt;June&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;July&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;August&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;September&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;October&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;November&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;December&lt;/option&gt;\n}
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; / &quot;
+
+    expected &lt;&lt; %{&lt;select id=&quot;post_updated_at_3i&quot; name=&quot;post[updated_at(3i)]&quot;&gt;\n}
+    expected &lt;&lt; %{&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;\n&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;\n&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;\n&lt;option value=&quot;4&quot;&gt;4&lt;/option&gt;\n&lt;option value=&quot;5&quot;&gt;5&lt;/option&gt;\n&lt;option value=&quot;6&quot;&gt;6&lt;/option&gt;\n&lt;option value=&quot;7&quot;&gt;7&lt;/option&gt;\n&lt;option value=&quot;8&quot;&gt;8&lt;/option&gt;\n&lt;option value=&quot;9&quot;&gt;9&lt;/option&gt;\n&lt;option value=&quot;10&quot;&gt;10&lt;/option&gt;\n&lt;option value=&quot;11&quot;&gt;11&lt;/option&gt;\n&lt;option value=&quot;12&quot;&gt;12&lt;/option&gt;\n&lt;option value=&quot;13&quot;&gt;13&lt;/option&gt;\n&lt;option value=&quot;14&quot;&gt;14&lt;/option&gt;\n&lt;option value=&quot;15&quot; selected=&quot;selected&quot;&gt;15&lt;/option&gt;\n&lt;option value=&quot;16&quot;&gt;16&lt;/option&gt;\n&lt;option value=&quot;17&quot;&gt;17&lt;/option&gt;\n&lt;option value=&quot;18&quot;&gt;18&lt;/option&gt;\n&lt;option value=&quot;19&quot;&gt;19&lt;/option&gt;\n&lt;option value=&quot;20&quot;&gt;20&lt;/option&gt;\n&lt;option value=&quot;21&quot;&gt;21&lt;/option&gt;\n&lt;option value=&quot;22&quot;&gt;22&lt;/option&gt;\n&lt;option value=&quot;23&quot;&gt;23&lt;/option&gt;\n&lt;option value=&quot;24&quot;&gt;24&lt;/option&gt;\n&lt;option value=&quot;25&quot;&gt;25&lt;/option&gt;\n&lt;option value=&quot;26&quot;&gt;26&lt;/option&gt;\n&lt;option value=&quot;27&quot;&gt;27&lt;/option&gt;\n&lt;option value=&quot;28&quot;&gt;28&lt;/option&gt;\n&lt;option value=&quot;29&quot;&gt;29&lt;/option&gt;\n&lt;option value=&quot;30&quot;&gt;30&lt;/option&gt;\n&lt;option value=&quot;31&quot;&gt;31&lt;/option&gt;\n}
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; , &quot;
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_updated_at_4i&quot; name=&quot;post[updated_at(4i)]&quot;&gt;\n)
+    0.upto(23) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 15}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; - &quot;
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_updated_at_5i&quot; name=&quot;post[updated_at(5i)]&quot;&gt;\n)
+    0.upto(59) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 16}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    expected &lt;&lt; &quot; - &quot;
+
+    expected &lt;&lt; %(&lt;select id=&quot;post_updated_at_6i&quot; name=&quot;post[updated_at(6i)]&quot;&gt;\n)
+    0.upto(59) { |i| expected &lt;&lt; %(&lt;option value=&quot;#{sprintf(&quot;%02d&quot;, i)}&quot;#{' selected=&quot;selected&quot;' if i == 35}&gt;#{sprintf(&quot;%02d&quot;, i)}&lt;/option&gt;\n) }
+    expected &lt;&lt; &quot;&lt;/select&gt;\n&quot;
+
+    assert_dom_equal expected, datetime_select(&quot;post&quot;, &quot;updated_at&quot;, { :date_separator =&gt; &quot; / &quot;, :datetime_separator =&gt; &quot; , &quot;, :time_separator =&gt; &quot; - &quot;, :include_seconds =&gt; true })
+  end
+
   def test_date_select_with_zero_value_and_no_start_year
     expected =  %(&lt;select id=&quot;date_first_year&quot; name=&quot;date[first][year]&quot;&gt;\n)
     (Date.today.year-5).upto(Date.today.year+1) { |y| expected &lt;&lt; %(&lt;option value=&quot;#{y}&quot;&gt;#{y}&lt;/option&gt;\n) }
@@ -1814,26 +1888,151 @@ class DateHelperTest &lt; ActionView::TestCase
     assert_dom_equal expected, datetime_select(&quot;post&quot;, &quot;updated_at&quot;, {}, :class =&gt; 'selector')
   end
 
-  uses_mocha 'TestInstanceTagDefaultTimeFromOptions' do
-    def test_instance_tag_default_time_from_options_uses_time_current_as_default_when_hash_passed_as_arg
-      dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
-      Time.expects(:current).returns Time.now
-      dummy_instance_tag.send!(:default_time_from_options, :hour =&gt; 2)
-    end
-
-    def test_instance_tag_default_time_from_options_respects_hash_arg_settings_when_time_falls_in_system_local_dst_spring_gap
-      with_env_tz('US/Central') do
-        dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
-        Time.stubs(:now).returns Time.local(2006, 4, 2, 1)
-        assert_equal 2, dummy_instance_tag.send!(:default_time_from_options, :hour =&gt; 2).hour
-      end
-    end
-
-    def test_instance_tag_default_time_from_options_handles_far_future_date
-      dummy_instance_tag = ActionView::Helpers::InstanceTag.new(1,2,3)
-      time = dummy_instance_tag.send!(:default_time_from_options, :year =&gt; 2050, :month =&gt; 2, :day =&gt; 10, :hour =&gt; 15, :min =&gt; 30, :sec =&gt; 45)
-      assert_equal 2050, time.year
-    end
+  def test_date_select_should_not_change_passed_options_hash
+    @post = Post.new
+    @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    date_select(@post, :updated_at, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
+  end
+
+  def test_datetime_select_should_not_change_passed_options_hash
+    @post = Post.new
+    @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    datetime_select(@post, :updated_at, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
+  end
+
+  def test_time_select_should_not_change_passed_options_hash
+    @post = Post.new
+    @post.updated_at = Time.local(2008, 7, 16, 23, 30)
+
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    time_select(@post, :updated_at, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
+  end
+
+  def test_select_date_should_not_change_passed_options_hash
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    select_date(Date.today, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
+  end
+
+  def test_select_datetime_should_not_change_passed_options_hash
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    select_datetime(Time.now, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
+  end
+
+  def test_select_time_should_not_change_passed_options_hash
+    options = { 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }
+    select_time(Time.now, options)
+
+    # note: the literal hash is intentional to show that the actual options hash isn't modified
+    #       don't change this!
+    assert_equal({ 
+      :order =&gt; [ :year, :month, :day ],
+      :default =&gt; { :year =&gt; 2008, :month =&gt; 7, :day =&gt; 16, :hour =&gt; 23, :minute =&gt; 30, :second =&gt; 1 },
+      :discard_type =&gt; false,
+      :include_blank =&gt; false,
+      :ignore_date =&gt; false,
+      :include_seconds =&gt; true
+    }, options)
   end
 
   protected</diff>
      <filename>actionpack/test/template/date_helper_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>be0d235a3b82e72de49592913753a1f291a98f86</id>
    </parent>
  </parents>
  <author>
    <name>Clemens Kofler</name>
    <email>clemens@railway.at</email>
  </author>
  <url>http://github.com/rails/rails/commit/105093f90728f81268367bd52581fccfa165f170</url>
  <id>105093f90728f81268367bd52581fccfa165f170</id>
  <committed-date>2008-08-07T11:13:47-07:00</committed-date>
  <authored-date>2008-08-07T11:13:47-07:00</authored-date>
  <message>Refactor DateHelper to use DateTimeSelector presenter pattern
Signed-off-by: Joshua Peek &lt;josh@joshpeek.com&gt;</message>
  <tree>3ca826186b5fdcce8708445eb9283743f645034d</tree>
  <committer>
    <name>Joshua Peek</name>
    <email>josh@joshpeek.com</email>
  </committer>
</commit>
