2016-10-10 54 views
0

我有兩個變量的時間段,從start_dateend_date。是否有一種簡單的方法將它分成較小的時期,將價值四捨五入。如何將時間段分成多個時間段

下面是一個例子:

我從15.01.201610.06.2016時期。我想把它分成個月,所以我將有六個時期:

01.01.2016 - 31.01.2016 
01.02.2016 - 31.02.2016 
01.03.2016 - 31.03.2016 
01.04.2016 - 31.04.2016 
01.05.2016 - 31.05.2016 
01.06.2016 - 31.06.2016 

我想包括01.01.201615.01.2016之間的時間不管事實是不是在原來的時期。

我一直在尋找一些想法,但在這個時候,似乎唯一的辦法是使用的開始日期和使用DateAndTime ::計算,確定區間的邊界進行迭代,直到打到結束日期。

+0

請閱讀「[問]」和「[mcve]」。當問及證明你的努力很重要時。那就是你搜索的頁面,爲什麼那些沒有回答你的問題,或者是顯示問題的最低代碼,以及爲什麼它不能做你想要的。沒有它,看起來你要求我們爲你寫代碼,這不是Stack Overflow的目的。此外,請花時間格式化您的問題以提高可讀性。它可以幫助我們幫助你,並幫助那些尋找類似解決方案的人。 –

+0

也許我沒有在問題中說清楚自己,但我不想要代碼。我有想法如何解決(這是在問題),但是是如此原始,我很確定有人會有一個更好的(如使用group_by)。 – ZebThan

回答

3
from = Date.parse('15.01.2016') 
to = Date.parse('10.06.2016') 
(from..to).group_by(&:month).map do |group| 
    group.last.first.beginning_of_month..group.last.last.end_of_month 
end 
# => [Fri, 01 Jan 2016..Sun, 31 Jan 2016, 
# Mon, 01 Feb 2016..Mon, 29 Feb 2016, 
# Tue, 01 Mar 2016..Thu, 31 Mar 2016, 
# Fri, 01 Apr 2016..Sat, 30 Apr 2016, 
# Sun, 01 May 2016..Tue, 31 May 2016, 
# Wed, 01 Jun 2016..Thu, 30 Jun 2016] 

或者,地圖日期字符串,如果你需要的字符串表示:

(from..to).group_by(&:month).map do |group| 
    "#{group.last.first.beginning_of_month} - #{group.last.last.end_of_month}" 
end 

# => ["2016-01-01 - 2016-01-31", 
#  "2016-02-01 - 2016-02-29", 
#  "2016-03-01 - 2016-03-31", 
#  "2016-04-01 - 2016-04-30", 
#  "2016-05-01 - 2016-05-31", 
#  "2016-06-01 - 2016-06-30"] 

要獲得正是你想要的東西,你可以格式化日期的字符串表示:

(from..to).group_by(&:month).map do |group| 
    "#{group.last.first.beginning_of_month.strftime('%d-%m-%Y')} - #{group.last.last.end_of_month.strftime('%d-%m-%Y')}" 
end 
#=> ["01-01-2016 - 31-01-2016", 
# "01-02-2016 - 29-02-2016", 
# "01-03-2016 - 31-03-2016", 
# "01-04-2016 - 30-04-2016", 
# "01-05-2016 - 31-05-2016", 
# "01-06-2016 - 30-06-2016"] 

編輯

爲了確保範圍不因年份不同而混雜在一起,與一個月沿平:

from = Date.parse('15.01.2016') 
to = Date.parse('10.02.2017') 
(from..to).group_by {|a| [a.year, a.month]}.map do |group| 
    "#{group.last.first.beginning_of_month.strftime('%d-%m-%Y')} - #{group.last.last.end_of_month.strftime('%d-%m-%Y')}" 
end 
# => ["01-01-2016 - 31-01-2016", 
# "01-02-2016 - 29-02-2016", 
# "01-03-2016 - 31-03-2016", 
# "01-04-2016 - 30-04-2016", 
# "01-05-2016 - 31-05-2016", 
# "01-06-2016 - 30-06-2016", 
# "01-07-2016 - 31-07-2016", 
# "01-08-2016 - 31-08-2016", 
# "01-09-2016 - 30-09-2016", 
# "01-10-2016 - 31-10-2016", 
# "01-11-2016 - 30-11-2016", 
# "01-12-2016 - 31-12-2016", 
# "01-01-2017 - 31-01-2017", 
# "01-02-2017 - 28-02-2017"] 
+0

好的,它可以在幾個月內完美地工作,並且這使得答案正確,所以我將它標記爲它。但是有可能將它按季而不是幾個月分組嗎? – ZebThan

+1

@ZebThan是啊,我想你將不得不定義一個方法來識別日期的季度,並基於它的組。谷歌它,你可能會找到一些解決方案。否則,你總是可以問一個新的問題:) –

+1

@ZebThan標準宿舍將會像'(month-1).divmod(3).first + 1'一樣簡單。例如。 'Date.today.quarter = 4'因爲'(10-1).divmod(3)= [3,0]'然後'_.first = 3'並加1,因爲第0季不是問題。 – engineersmnky

1

這種方法避免了需要每天檢查的日期範圍,並返回所需格式字符串數組。

Date#>>將日期向前移動參數給定的月數。在這裏,我將日期轉移了一個月(例如,Date.parse("14-01-2016") >> 1 #=> #<Date: 2016-02-14...>)。如果下個月的最後一天大於給定月份的最後一天,則返回下個月的最後一天(例如,Date.parse("30-01-2016") >> 1 #=> #<Date: 2016-02-29...>)。

代碼

require 'datetime' 

def convert(sdate, edate) 
    dfirst = Date.strptime(sdate, "%d.%m.%Y") 
    dlast = Date.strptime(edate, "%d.%m.%Y") 
    nmonths = 12*dlast.year + dlast.month - 12*dfirst.year - dfirst.month + 1 
    dlast = dfirst.end_of_month 
    nmonths.times.map { |i|  
    "%s - %s" % [(dfirst >> i).strftime("01.%m.%Y"), (dlast >> i).strftime("%d.%m.%Y")]} 
end 

convert "15.01.2016", "10.06.2016" 
    #=> ["01.01.2016 - 31.01.2016", "01.02.2016 - 29.02.2016", 
    # "01.03.2016 - 31.03.2016", "01.04.2016 - 30.04.2016", 
    # "01.05.2016 - 31.05.2016", "01.06.2016 - 30.06.2016"] 

說明

的步驟如下。

sdate = "15.01.2016" 
edate = "10.06.2016" 

dfirst = Date.strptime(sdate, "%d.%m.%Y") 
    #=> #<Date: 2016-01-15 ((2457403j,0s,0n),+0s,2299161j)> 
dlast = Date.strptime(edate, "%d.%m.%Y") 
    #=> #<Date: 2016-06-10 ((2457550j,0s,0n),+0s,2299161j)> 
nmonths = 12*dlast.year + dlast.month - 12*dfirst.year - dfirst.month + 1 
    #=>  12*24192 +  6  - 12*24192  -  1  + 1 
    #=> 6 

變化dlast到第一個月的最後一天。

dlast = d.first.end_of_month 
    #=> #<Date: 2016-01-31 ((2457419j,0s,0n),+0s,2299161j)> 

將每個月映射到所需的格式。

nmonths.times.map { |i|  
    "%s - %s" % [(dfirst >> i).strftime("01.%m.%Y"), (dlast >> i).strftime("%d.%m.%Y")]} 
    #=> ["01.01.2016 - 31.01.2016", "01.02.2016 - 29.02.2016", 
    # "01.03.2016 - 31.03.2016", "01.04.2016 - 30.04.2016", 
    # "01.05.2016 - 31.05.2016", "01.06.2016 - 30.06.2016"] 
+0

'nmonths'的計算是純Ruby。可能有一種更簡單的方法來計算在Rails中,但我不知道Rails(除了像'beginning_of_month'和'end_of_month'這樣的一些東西。 –