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`, and `tomorrow` are prohibited and the usage of both `to_time` and 'to_time_in_current_zone' are reported as warning.

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

@example EnforcedStyle: strict

# bad
Date.current
Date.yesterday
Date.today
date.to_time

# good
Time.zone.today
Time.zone.today - 1.day

@example EnforcedStyle: flexible (default)

# bad
Date.today
date.to_time

# good
Time.zone.today
Time.zone.today - 1.day
Date.current
Date.yesterday
date.in_time_zone

Constants

BAD_DAYS
DEPRECATED_METHODS
DEPRECATED_MSG
MSG
MSG_SEND

Public Instance Methods

on_const(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 64
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_csend(node)
Alias for: on_send
on_send(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 72
def on_send(node)
  return unless node.receiver && bad_methods.include?(node.method_name)

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

  check_deprecated_methods(node)

  add_offense(node, location: :selector,
                    message: format(MSG_SEND, method: node.method_name))
end
Also aliased as: on_csend

Private Instance Methods

bad_days() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 147
def bad_days
  BAD_DAYS - good_days
end
bad_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 151
def bad_methods
  %i[to_time to_time_in_current_zone]
end
check_date_node(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 97
def check_date_node(node)
  chain = extract_method_chain(node)

  return if (chain & bad_days).empty?

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

  day = method_name
  day = 'today' if method_name == 'current'

  add_offense(node, location: :selector,
                    message: format(MSG,
                                    method_called: method_name,
                                    day: day))
end
check_deprecated_methods(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 86
def check_deprecated_methods(node)
  DEPRECATED_METHODS.each do |relevant:, deprecated:|
    next unless node.method_name == deprecated.to_sym

    add_offense(node, location: :selector,
                      message: format(DEPRECATED_MSG,
                                      deprecated: deprecated,
                                      relevant: relevant))
  end
end
extract_method_chain(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 113
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 143
def good_days
  style == :strict ? [] : %i[current yesterday tomorrow]
end
good_methods() click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 155
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 119
def method_send?(node)
  return false unless node.parent&.send_type?

  node.parent.receiver == node
end
safe_chain?(node) click to toggle source
# File lib/rubocop/cop/rails/date.rb, line 125
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 131
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