class RuboCop::Cop::Rails::Date
date.to_time
# bad
@example AllowToTime: false
date.to_time
# good
@example AllowToTime: true (default)
Time.zone.today - 1.day
Time.zone.today
# good
Date.today
Date.yesterday
Date.current
# bad
@example EnforcedStyle: strict
date.in_time_zone
Date.yesterday
Date.current
Time.zone.today - 1.day
Time.zone.today
# good
Date.today
# bad
@example EnforcedStyle: flexible (default)
This cop’s autocorrection is unsafe because it may change handling time.
@safety
`AllowToTime` is ‘true` by default to prevent false positive on `DateTime` object.
And you can set a warning for `to_time` with `AllowToTime: false`.
When `EnforcedStyle` is `flexible` then only `Date.today` is prohibited.
and `to_time_in_current_zone` are reported as warning.
are prohibited and the usage of both `to_time`
then the Date methods `today`, `current`, `yesterday`, and `tomorrow`
Two styles are supported for this cop. When `EnforcedStyle` is `strict`
because it doesn’t know about Rails time zone either.
The cop also reports warnings when you are using ‘to_time` method,
Rails time zone. You must use `Time.zone.today` instead.
Using `Date.today` is dangerous, because it doesn’t know anything about
such as Date.today, Date.current etc.
Checks for the correct use of Date methods,
def allow_to_time?
def allow_to_time? cop_config.fetch('AllowToTime', true) end
def bad_days
def bad_days BAD_DAYS - good_days end
def bad_methods
def bad_methods %i[to_time to_time_in_current_zone] end
def check_date_node(node)
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' message = format(MSG, method_called: method_name, day: day) add_offense(node.loc.selector, message: message) do |corrector| corrector.replace(node.receiver.loc.name, 'Time.zone') end end
def check_deprecated_methods(node)
def check_deprecated_methods(node) DEPRECATED_METHODS.each do |method| next unless node.method?(method[:deprecated].to_sym) message = format(DEPRECATED_MSG, deprecated: method[:deprecated], relevant: method[:relevant]) add_offense(node.loc.selector, message: message) do |corrector| corrector.replace(node.loc.selector, method[:relevant].to_s) end end end
def extract_method_chain(node)
def extract_method_chain(node) [node, *node.each_ancestor(:send)].map(&:method_name) end
def good_days
def good_days style == :strict ? [] : %i[current yesterday tomorrow] end
def good_methods
def good_methods style == :strict ? [] : TimeZone::ACCEPTED_METHODS end
def method_send?(node)
checks that parent node of send_type
def method_send?(node) return false unless node.parent&.send_type? node.parent.receiver == node end
def on_const(node)
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
def on_send(node)
def on_send(node) return unless node.receiver && bad_methods.include?(node.method_name) return if allow_to_time? && node.method?(:to_time) return if safe_chain?(node) || safe_to_time?(node) check_deprecated_methods(node) add_offense(node.loc.selector, message: format(MSG_SEND, method: node.method_name)) end
def safe_chain?(node)
def safe_chain?(node) chain = extract_method_chain(node) (chain & bad_methods).empty? || !(chain & good_methods).empty? end
def safe_to_time?(node)
def safe_to_time?(node) return false 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