从Time对象获取下一个/上个月

时间:2010-04-23 15:40:00

标签: ruby

我有一个Time对象,想找到下一个/上一个月。添加减去天数不起作用,因为每月的天数会有所不同。

time = Time.parse('21-12-2008 10:51 UTC')
next_month = time + 31 * 24 * 60 * 60

增加月份也会下降,因为人们必须照顾滚动

time = Time.parse('21-12-2008 10:51 UTC')
next_month = Time.utc(time.year, time.month+1)

time = Time.parse('01-12-2008 10:51 UTC')
previous_month = Time.utc(time.year, time.month-1)

我找到的唯一工作是

time = Time.parse('21-12-2008 10:51 UTC')
d = Date.new(time.year, time.month, time.day)
d >>= 1
next_month = Time.utc(d.year, d.month, d.day, time.hour, time.min, time.sec, time.usec)

有没有更优雅的方式做到这一点,我没有看到? 你会怎么做?

12 个答案:

答案 0 :(得分:77)

Ruby on Rails

注意:此仅适用于Rails (感谢Steve!)但我保留此处以防其他人使用Rails并希望使用这些更直观的方法。

超级简单 - 谢谢Ruby on Rails!

Time.now + 1.month

Time.now - 1.month  

或者,如果它与当前时间相关(仅限Rails 3+),则为另一种选择。

1.month.from_now

1.month.ago

JP

答案 1 :(得分:21)

我个人更喜欢使用:

Time.now.beginning_of_month - 1.day      # previous month
Time.now.end_of_month + 1.day            # next month

它始终有效,并且与一个月内的天数无关。

查找更多信息in this API doc

答案 2 :(得分:12)

您可以使用标准类DateTime

require 'date'

dt = Time.new().to_datetime
=> #<DateTime: 2010-04-23T22:31:39+03:00 (424277622199937/172800000,1/8,2299161)>

dt2 = dt >> 1
=> #<DateTime: 2010-05-23T22:31:39+03:00 (424282806199937/172800000,1/8,2299161)>

t = dt2.to_time
=> 2010-05-23 22:31:39 +0200

答案 3 :(得分:10)

Time上没有内置方法可以在Ruby中执行您想要的操作。我建议你在模块中编写方法来完成这项工作,并扩展Time类,使其在其余代码中的使用变得简单。

您可以使用DateTime,但方法(<<>>)的命名方式不会让以前没有使用它们的人明白其目的。< / p>

答案 4 :(得分:6)

下面有效

上个月:

Time.now.months_since(-1)

下个月:

Time.now.months_since(1)

答案 5 :(得分:6)

如果您不想加载和依赖其他库,可以使用以下内容:

module MonthRotator
  def current_month
    self.month
  end

  def month_away
    new_month, new_year = current_month == 12 ? [1, year+1] : [(current_month + 1), year]
    Time.local(new_year, new_month, day, hour, sec)
  end

  def month_ago
    new_month, new_year = current_month == 1 ? [12, year-1] : [(current_month - 1), year]
    Time.local(new_year, new_month, day, hour, sec)
  end
end

class Time
  include MonthRotator
end


require 'minitest/autorun'

class MonthRotatorTest < MiniTest::Unit::TestCase
  describe "A month rotator Time extension" do
    it 'should return a next month' do
      next_month_date = Time.local(2010, 12).month_away
      assert_equal next_month_date.month, 1
      assert_equal next_month_date.year, 2011
    end

    it 'should return previous month' do
      previous_month_date = Time.local(2011, 1).month_ago
      assert_equal previous_month_date.month, 12
      assert_equal previous_month_date.year, 2010
    end
  end
end

答案 6 :(得分:2)

为了完整性,我只想添加我的纯红宝石解决方案 将strftime中的格式替换为所需的输出

DateTime.now.prev_month.strftime("%Y-%m-%d")
DateTime.now.next_month.strftime("%Y-%m-%d")

答案 7 :(得分:1)

您可以尝试转换为日期时间。

时间为您提供当前日期,而DateTime允许您使用。

看看这个:

irb(main):041:0> Time.new.strftime("%d/%m/%Y")
        => "21/05/2015"

irb(main):040:0> Time.new.to_datetime.prev_month.strftime("%d/%m/%Y")
    => "21/04/2015"

答案 8 :(得分:1)

这是一个没有RoR的普通红宝石的解决方案,适用于旧的红宝石版本。

t=Time.local(2000,"jan",1,20,15,1,0);
curmon=t.mon;
prevmon=(Time.local(t.year,t.mon,1,0,0,0,0)-1).mon ;
puts "#{curmon} #{prevmon}"

答案 9 :(得分:0)

一些解决方案假设使用rails。但是,在纯红宝石中,您可以执行以下操作

require 'date'    

d = Date.now
last_month = d<<1

last_month.strftime("%Y-%m-%d")

答案 10 :(得分:0)

我在这个例子中使用了ActiveSupport :: TimeZone,但是如果您使用的是Rails或ActiveSupport,它可能会派上用场。

如果您想要上个月,您可以减去1个月

time = Time.zone.parse('21-12-2008 10:51 UTC')
time.ago(1.month)

答案 11 :(得分:-1)

$ irb
irb(main):001:0> time = Time.now
=> 2016-11-21 10:16:31 -0800
irb(main):002:0> year = time.year
=> 2016
irb(main):003:0> month = time.month
=> 11
irb(main):004:0> last_month = month - 1
=> 10
irb(main):005:0> puts time
2016-11-21 10:16:31 -0800
=> nil
irb(main):006:0> puts year
2016
=> nil
irb(main):007:0> puts month
11
=> nil
irb(main):008:0> puts last_month
10
=> nil