Получить следующий/предыдущий месяц из объекта Time
У меня есть объект 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)
Есть ли более элегантный способ сделать это, чего я не вижу?
Как вы это сделаете?
Ответы
Ответ 1
Нет встроенных методов на Time
, чтобы делать то, что вы хотите в Ruby. Я предлагаю вам написать методы для выполнения этой работы в модуле и расширить класс Time
, чтобы сделать их использование простым в остальной части вашего кода.
Вы можете использовать DateTime
, но методы (<<
и >>
) не называются так, что делает их цель очевидной для тех, кто раньше их не использовал.
Ответ 2
Ruby on Rails
Примечание. Это работает только в Rails (спасибо, Стив!), Но я сохраню его здесь на тот случай, если другие используют Rails и захотят использовать эти более интуитивные методы.
Супер просто - спасибо Ruby on Rails!
Time.now + 1.month
Time.now - 1.month
Или другой вариант, если он связан с текущим временем (только для Rails 3+).
1.month.from_now
1.month.ago
Ответ 3
Лично я предпочитаю использовать:
Time.now.beginning_of_month - 1.day # previous month
Time.now.end_of_month + 1.day # next month
Он всегда работает и не зависит от количества дней в месяце.
Найти дополнительную информацию в этом документе API
Ответ 4
вы можете использовать стандартный класс 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
Ответ 5
ниже он работает
предыдущий месяц:
Time.now.months_since(-1)
в следующем месяце:
Time.now.months_since(1)
Ответ 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
Ответ 7
Я просто хочу добавить свое простое рубиновое решение для полноты
замените формат в strftime на желаемый результат
DateTime.now.prev_month.strftime("%Y-%m-%d")
DateTime.now.next_month.strftime("%Y-%m-%d")
Ответ 8
Вы можете попробовать конвертировать в datetime.
Время дает вам текущую дату, а 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"
Ответ 9
Вот решение на простом рубине без RoR, работает на старых версиях ruby.
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}"
Ответ 10
Некоторые из решений предполагают рельсы. Но в чистом рубине вы можете сделать следующее
require 'date'
d = Date.now
last_month = d<<1
last_month.strftime("%Y-%m-%d")
Ответ 11
Я использую ActiveSupport:: TimeZone для этого примера, но на всякий случай вы используете Rails или ActiveSupport, это может пригодиться.
Если вы хотите, чтобы предыдущий месяц вы могли вычитать 1 месяц
time = Time.zone.parse('21-12-2008 10:51 UTC')
time.ago(1.month)
Ответ 12
$ 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