【问题标题】:How to calculate how many years passed since a given date in Ruby?如何计算Ruby中给定日期以来已经过去了多少年?
【发布时间】:2010-12-26 14:55:03
【问题描述】:

这个问题是针对其他语言的,所以这里是针对 Ruby 的一个问题。

如何计算从给定日期过去的完整年数?正如您可能已经猜到的那样,这是自动计算人的年龄。最接近的是distance_of_time_in_words Rails helper,所以下面的模板

Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old.

产量

Jack is over 59 years old.

但我需要更精确的函数,只产生数字。有吗?

如果为此存在某种 Ruby on Rails 辅助函数,这没关系,尽管纯 Ruby 解决方案会更好。

编辑:问题的要点是需要一个非近似解决方案。三月 2nd,杰克应该是 59 岁,第二天他应该是 60 岁。应考虑闰年等。

【问题讨论】:

    标签: ruby-on-rails ruby datetime


    【解决方案1】:

    为了计算两个日期之间的年数和月数,我使用了这个函数

      def calculate_year_month(from_date, to_date)
        num_days = (from_date - to_date).to_i
        num_months = (num_days / 30) 
        num_years = (num_months / 12) 
        num_months = (num_months % 12) 
        return num_years.to_s + " year(s) and " + num_months.to_s + " month(s)" 
      end 
    

    【讨论】:

      【解决方案2】:

      基于与@FMc 类似的推理,我想出了以下内容 首先,计算今天年份和生日年份之间的差异。然后,将其与生日相加并检查结果日期:如果大于今天,则将 diff 减 1。 用于 Rails 应用程序,因为它依赖于 ActiveSupportyears 方法

      def age(birthday, today)
        diff = today.year - birthday.year
        (birthday + diff.years > today ) ? (diff - 1) : diff
      end
      

      【讨论】:

        【解决方案3】:

        d2.year - d1.year - (d2.month &gt; d1.month || (d2.month == d1.month &amp;&amp; d2.day &gt;= d1.day) ? 0 : 1)

        【讨论】:

        • 欢迎来到 SO!请尝试在您的答案中提供一些解释。
        【解决方案4】:

        您可以使用 ruby​​ gem adroit-age

        它也适用于闰年..

        age = AdroitAge.find_age("23/01/1990")
        

        更新

        require 'adroit-age'
        
        dob =  Date.new(1990,1,23)
        or
        dob = "23/01/1990".to_date
        
        age = dob.find_age
        #=> 23
        

        【讨论】:

          【解决方案5】:

          这个怎么样:

          def age_in_years(date)
            # Difference in years, less one if you have not had a birthday this year.
            today = Date.today
            age = today.year - date.year
            age = age - 1 if [date.day, date.month, today.year].join('/').to_date > Date.today
          end
          

          【讨论】:

            【解决方案6】:

            处理闰年的方法

            每当您计算某个日期以来经过的年数时,您必须决定如何处理闰年。这是我的方法,我认为它非常易读,并且能够在不使用任何“特殊情况”逻辑的情况下从容应对闰年。

            def years_completed_since(start_date, end_date)
            
              if end_date < start_date
                raise ArgumentError.new(
                  "End date supplied (#{end_date}) is before start date (#{start_date})"
                )
              end
            
              years_completed = end_date.year - start_date.year
            
              unless reached_anniversary_in_year_of(start_date, end_date)
                years_completed -= 1
              end
            
              years_completed
            end
            
            # No special logic required for leap day; its anniversary in a non-leap
            # year is considered to have been reached on March 1.
            def reached_anniversary_in_year_of(original_date, new_date)
              if new_date.month == original_date.month
                new_date.day >= original_date.day
              else
                new_date.month > original_date.month
              end
            end
            

            【讨论】:

              【解决方案7】:

              http://github.com/radar/dotiw

              Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old.
              

              生产

              Jack is 60 years old
              

              【讨论】:

                【解决方案8】:

                我认为这将始终有效,即使对于生日临近闰日的人:

                require 'date'
                
                def calculate_age(start_date, end_date)
                  end_date.year - start_date.year - ((end_date.month > start_date.month || (end_date.month == start_date.month && end_date.day >= start_date.day)) ? 0 : 1)
                end
                
                puts calculate_age( Date.strptime('03/02/1968', '%m/%d/%Y'), Date.strptime('03/02/2010', '%m/%d/%Y'))
                

                在上面的示例调用中使用此方法计算的年龄是 42,尽管 1968 年是闰年并且生日接近闰日,但这是正确的。

                另外,这样就不需要创建局部变量了。

                【讨论】:

                  【解决方案9】:

                  与 FM 的想法相同,但使用了简化的 if 语句。显然,您可以添加第二个参数而不是使用当前时间。

                  def age(birthdate)
                    now = DateTime.now
                    age = now.year - birthdate.year
                    age -= 1 if(now.yday < birthdate.yday)
                    age
                  end
                  

                  【讨论】:

                  • yday 是一个很酷的功能,谢谢。不幸的是,如果这个人的出生时间晚于二月,它将以不同的方式处理闰年。
                  • 同意帕维尔。由于闰年,yday 对于比较跨年份的日期没有用处。
                  【解决方案10】:

                  您想要人们通常理解的年龄,还是想要精确测量经过的时间?如果是前者,则无需担心闰年和其他并发症。如果这个人今年还没有过生日,你只需要计算年差并减少它。如果是后者,您可以按照其他答案的建议将经过的秒数转换为年数。

                  def age_in_completed_years (bd, d)
                      # Difference in years, less one if you have not had a birthday this year.
                      a = d.year - bd.year
                      a = a - 1 if (
                           bd.month >  d.month or 
                          (bd.month >= d.month and bd.day > d.day)
                      )
                      a
                  end
                  
                  birthdate = Date.new(2000, 12, 15)
                  today     = Date.new(2009, 12, 14)
                  
                  puts age_in_completed_years(birthdate, today)
                  

                  【讨论】:

                  • 看来你不仅回答了问题,还把问题表述得更好:-)
                  • +1,但是如果我出生在 Date.new(1980, 2, 29) 上呢? ;-)
                  • @Mike Bummer -- 你没有生日。好点子。修复了代码。
                  • 不知何故你知道 &*^$@ 闰年问题并没有那么平静地消失......
                  • @Telemachus 确实!闰年老人是个顽固的混蛋。
                  【解决方案11】:

                  我有一个名为 dotiw 的 gem/插件,它有一个 distance_of_time_in_words_hash,它将返回一个哈希值,例如:{ :years =&gt; 59, :months =&gt; 11, :days =&gt; 27 }。从中您可以计算出它是否接近某个限制。

                  【讨论】:

                    【解决方案12】:

                    比如:

                    def years_diff(from_time,to_time)
                      (((to_time - from_time).abs)/ (365 * 24 * 60 * 60)).to_i
                    end
                    
                    years_diff(Time.now,Time.local(1950,03,22)) #=> 59
                    years_diff(Time.now,Time.local(2009,03,22)) #=> 0
                    years_diff(Time.now,Time.local(2008,03,22)) #=> 1
                    

                    【讨论】:

                    • 当当前日期接近生日(闰年!)时,这将不起作用,并且对于超过 1460 岁的人来说,它会产生越来越多的错误。
                    【解决方案13】:
                    require 'date'
                    
                    def years_since(dt)
                        delta = (Date.today - Date.parse(dt)) / 365
                        delta.to_i
                    end
                    

                    【讨论】:

                      猜你喜欢
                      • 2016-05-20
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-05-07
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多