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

# flexible
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 47
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 55
def on_send(node)
  return unless node.receiver && bad_methods.include?(node.method_name)

  return if safe_chain?(node) || safe_to_time?(node)

  add_offense(node, location: :selector,
                    message: format(MSG_SEND, node.method_name))
end

Private Instance Methods

bad_days() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 113
def bad_days
  BAD_DAYS - good_days
end
bad_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 117
def bad_methods
  style == :strict ? %i[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 66
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, location: :selector,
                    message: format(MSG,
                                    "Date.#{method_name}",
                                    "Time.zone.#{method_name}"))
end
extract_method_chain(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 79
def extract_method_chain(node)
  [node, *node.each_ancestor(:send)].map(&:method_name)
end
good_days() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 109
def good_days
  style == :strict ? [] : %i[current yesterday tomorrow]
end
good_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 121
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 85
def method_send?(node)
  return false unless node.parent && node.parent.send_type?

  node.parent.receiver == node
end
safe_chain?(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 91
def safe_chain?(node)
  chain = extract_method_chain(node)

  (chain & bad_methods).empty? || !(chain & good_methods).empty?
end
safe_to_time?(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 97
def safe_to_time?(node)
  return unless node.method?(:to_time)

  if node.receiver.str_type?
    zone_regexp = /([+-][\d:]+|\dZ)\z/

    node.receiver.str_content.match(zone_regexp)
  else
    node.arguments.one?
  end
end