Ruby/Rails: Converting datetime to natural language (e.g. 3/23/2012 to “this Friday”)

后端 未结 3 1850
臣服心动
臣服心动 2020-12-15 13:04

Is anyone aware of a gem, method, or code snippet that will convert datetime values into sometime more human-friendly without having to create a series of rules or put a bun

相关标签:
3条回答
  • 2020-12-15 13:41

    The goal of the Hublot gem is to solve this problem — to be a "reverse Chronic".

    https://github.com/brettshollenberger/hublot

    Related question: Ruby/Rails - Convert Date/Time back into Natural Language (2011-02-17 => February 17th, 2011)

    0 讨论(0)
  • 2020-12-15 13:50

    I modified Tom’s answer to suit my needs and be usable as a standalone module without having to include it anywhere. I placed the file human_date.rb inside my lib directory. I also fixed a tricky issue with the days_difference calculation.

    module HumanDate
      include ActionView::Helpers::DateHelper
      extend self
    
      def date_distance(from, to, long_form = true)
        seconds_in_day = 60 * 60 * 24
        days_difference = ((to.beginning_of_day.to_datetime - from.beginning_of_day.to_datetime)).floor
        case days_difference
          when -2
            "day before yesterday"
          when -1
            "yesterday"
          when 0
            "today"
          when 1
            "tomorrow"
          when 2..6
            "this #{day_name(days_difference)}"
          when 7..13
            "next #{to.strftime("%a")} (#{short_date(days_difference)})"
          else
            if days_difference > 0
              "in #{distance_of_time_in_words(from, to)} (#{short_date(days_difference, long_form)})"
            else
              "#{distance_of_time_in_words(from, to)} ago (#{short_date(days_difference, long_form)})"
            end
        end
      end
    
      def short_date(this_many, include_day=false)
        format_string = "%-b %-d"
        format_string = "%a, #{format_string}" if include_day
        this_many.days.from_now.strftime(format_string)
      end
    
      def day_name(this_many)
        this_many.days.from_now.strftime("%A")
      end
    
      def days_left_in_month
        Time.now.end_of_month.day - Time.now.day
      end
    
      def days_left_in_week
        Time.now.end_of_week.day - Time.now.day
      end
    end
    

    Usage:

    1.9.3-p392 :001 > HumanDate. date_distance(Time.now, 2.day.ago)
     => "day before yesterday" 
    1.9.3-p392 :002 > HumanDate. date_distance(Time.now, 3.days.from_now)
     => "this Tuesday" 
    1.9.3-p392 :003 > HumanDate. date_distance(Time.now, 12.days.from_now)
     => "next Thursday (Aug 1)" 
    1.9.3-p392 :004 > HumanDate. date_distance(Time.now, 122.days.from_now)
     => "in 4 months (Tue, Nov 19)" 
    1.9.3-p392 :005 > HumanDate. date_distance(Time.now, 122.days.ago)
     => "4 months ago (Wed, Mar 20)" 
    
    0 讨论(0)
  • 2020-12-15 13:52

    This is a little hack, totally unfinished and inelegant. But Ruby/Rails is so awesome with dates, and ranges are so perfect, maybe if you don't find the gem, something like this will get you started:

    module HumanDate
      def date_difference_for_people (from, to)
        seconds_in_day = 24 * 60 * 60
        days_difference = ((to - from)/seconds_in_day).round
        case days_difference
          when -1
            "yesterday"
          when 0
            "today"
          when 1
            "tomorrow"
          when 2..days_left_in_week
            "this #{day_name(difference)}"
          when (days_left_in_week + 1)..(days_left_in_week + 7)
            "next week"
          when (days_left_in_week + 8)..days_left_in_month
            "later this month"
          else
            "later -- how much left to you :-)"
        end
      end
    
      def day_name(days_from_now)
        days_from_now.days_from_now.strftime("%A")
      end
    
      def days_left_in_month
        Time.now.end_of_month.day - Time.now.day
      end
    
      def days_left_in_week
        Time.now.end_of_week.day - Time.now.day
      end
    end
    
    0 讨论(0)
提交回复
热议问题