class RuboCop::Cop::Rails::Date

This cop checks for the correct use of Date methods, such as Date.today, Date.current etc.

Using Date.today is dangerous, because it doesn't know anything about Rails time zone. You must use Time.zone.today instead.

The cop also reports warnings when you are using 'to_time' method, because it doesn't know about Rails time zone either.

Two styles are supported for this cop. When EnforcedStyle is 'strict' then the Date methods (today, current, yesterday, tomorrow) are prohibited and the usage of both 'to_time' and 'to_time_in_current_zone' is reported as warning.

When EnforcedStyle is 'flexible' then only 'Date.today' is prohibited and only 'to_time' is reported as warning.

@example

# no offense
Time.zone.today
Time.zone.today - 1.day

# acceptable
Date.current
Date.yesterday

# always reports offense
Date.today
date.to_time

# reports offense only when style is 'strict'
date.to_time_in_current_zone

Constants

BAD_DAYS
MSG
MSG_SEND

Public Instance Methods

on_const(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 48
def on_const(node)
  mod, klass = *node.children
  # we should only check core Date class (`Date` or `::Date`)
  return unless (mod.nil? || mod.cbase_type?) && method_send?(node)

  check_date_node(node.parent) if klass == :Date
end
on_send(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 56
def on_send(node)
  receiver, method_name, *args = *node
  return unless receiver && bad_methods.include?(method_name)

  chain = extract_method_chain(node)
  return if safe_chain?(chain)

  return if method_name == :to_time && args.length == 1

  add_offense(node, :selector,
              format(MSG_SEND,
                     method_name
                    )
             )
end

Private Instance Methods

bad_days() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 119
def bad_days
  BAD_DAYS - good_days
end
bad_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 123
def bad_methods
  style == :strict ? [:to_time, :to_time_in_current_zone] : [:to_time]
end
check_date_node(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 74
def check_date_node(node)
  chain = extract_method_chain(node)
  return if (chain & bad_days).empty?

  method_name = (chain & bad_days).join('.')

  add_offense(node, :selector,
              format(MSG,
                     "Date.#{method_name}",
                     "Time.zone.#{method_name}")
             )
end
extract_method(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 96
def extract_method(node)
  _receiver, method_name, *_args = *node
  method_name
end
extract_method_chain(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 87
def extract_method_chain(node)
  chain = []
  while !node.nil? && node.send_type?
    chain << extract_method(node)
    node = node.parent
  end
  chain
end
good_days() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 115
def good_days
  style == :strict ? [] : [:current, :yesterday, :tomorrow]
end
good_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 127
def good_methods
  style == :strict ? [] : TimeZone::ACCEPTED_METHODS
end
method_send?(node) click to toggle source

checks that parent node of send_type and receiver is the given node

# File lib/rubocop/cop/rails/date.rb, line 103
def method_send?(node)
  return false unless node.parent && node.parent.send_type?

  receiver, _method_name, *_args = *node.parent

  receiver == node
end
safe_chain?(chain) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 111
def safe_chain?(chain)
  (chain & bad_methods).empty? || !(chain & good_methods).empty?
end