Ruby - Calculate time duration into percentages of a whole month
I want to calculate the duration of time from a specific start and end time and output it in hours/minuts/seconds and how long that duration is compared to the whole month in percent.
Sometimes the total duration during a month is 开发者_运维百科in multiple duration blocks. Here is an example:
Thinking out load with Ruby:
Start = Date.new(2011-09-01 00:00:00) #24h clock - start of month
End = Date.new(2011-09-31 24:00:00) # end of month
Duration1 = Date.new(2011-09-03 12:30:00) Date.new(2011-09-11 12:30:00) #From - to
Duration2 = Date.new(2011-09-13 12:30:00) Date.new(2011-09-18 12:30:00) #From - to
Duration = Duration 1 + Duration2 #Might be even more durations during a month
Puts Duration.to_s
Total = Start + End
Percentage = (Duration / Total) * 100
Any idea how I could create a method out of the above code? It would be awesome if I could run something like or something even simpler:
Duration1 = Timedifference "2011-09-03 12:30:00", "2011-09-11 12:30:00" # Specify duration like this
Duration2 = Timedifference "2011-09-13 12:30:00", "2011-09-18 12:30:00" # Specify duration like this
Duration = Duration1 + Duration2
puts Duration
puts Percentage.Duration
Thanks in advance for your help.
There are quite a few ways to go about solving this problem. Assuming one wants to avoid dependencies on anything but the standard libraries, this is how I would do it:
require 'time'
# Calculate difference between two given Time objects
# and output as hours, minutes and seconds
def duration(time_start, time_end)
secs = (time_end - time_start).to_i
hours = secs / 3600;
secs -= hours * 3600
mins = secs / 60;
secs -= mins * 60
puts "#{hours}h #{mins}m #{secs}s"
end
# EDIT: Simpler and more elegant method (thanks to @knut)
def duration2(time_start, time_end)
puts Time.at(time_end - time_start).gmtime.strftime('%dd %Hh %Mm %Ss')
end
# Calculate the difference between two given Time objects,
# and the duration of the month the latter is in, then
# output the ratio as a percentage with 2 decimal places
def percentage_of_month(time_start, time_end)
time_secs = time_end - time_start
month_this = Date.civil(time_end.year, time_end.month, 1)
month_next = month_this.next_month
month_secs = (month_next - month_this) * 24 * 3600
percentage = (time_secs * 100.0 / month_secs)
puts '%2.2f%%' % percentage
end
time1a = Time.parse '2011-09-03 12:30:00'
time1b = Time.parse '2011-09-11 12:30:00'
duration time1a, time1b # => 192h 0m 0s
percentage_of_month time1a, time1b # => 26.67%
time2a = Time.parse '2011-09-13 12:30:00'
time2b = Time.parse '2011-09-18 12:30:00'
duration time2a, time2b # => 120h 0m 0s
percentage_of_month time2a, time2b # => 16.67%
time3a = Time.parse '2011-08-30 11:03:18'
time3b = Time.parse '2011-08-30 23:31:54'
duration time3a, time3b # => 12h 28m 36s
percentage_of_month time3a, time3b # => 1.68%
The output in hours/minuts/seconds is quite easy:
Time.at(duration).gmtime.strftime("%R:%S")
Details see http://www.ruby-forum.com/topic/48877
For the percentage I would need a more detailed specification.
- What's the base of your month? February has 28 days (but do not forget leap years), other months have 30 or 31 days.
- May your durations span different months?
- Could you give some test data and your expected result?
Below one solution with some assumptions.
require 'date'
=begin rdoc
Calculate seconds for a given month
=end
def seconds_of_month( year, month )
raise ArgumentError if month > 12
month_start = DateTime.new(year, month, 1, 0) #24h clock , start of month
if month == 12
month_end = DateTime.new(year + 1, 1, 1, 0) # jan 1st of following year
else
month_end = DateTime.new(year, month+1, 1) # start of next month
end
days = month_end - month_start
#~ puts "%i-%i has %i days (%s-%s)" % [year, month, days, month_start, month_end ]
days * 24 * 60 * 60 #convert month in second --- no check for leap seconds
end
=begin rdoc
Calculate percentage of duration in seconds per month.
=end
def percentage_of_month( duration, year, month )
(duration / seconds_of_month(year,month)) * 100
end
duration = #=> 1123200s
( Time.local(2011, 9, 11, 12, 30, 00) - Time.local(2011, 9, 03, 12, 30, 00) ) +
( Time.local(2011, 9, 18, 12, 30, 00) - Time.local(2011, 9, 13, 12, 30, 00) )
1.upto(12){|mon|
puts '%is is %.2f%% of 2011/%i (%is)' % [ duration, percentage_of_month( duration, 2011,mon), mon, seconds_of_month( 2011, mon ) ]
}
Result:
1123200s is 41.94% of 2011/1 (2678400s)
1123200s is 46.43% of 2011/2 (2419200s)
1123200s is 41.94% of 2011/3 (2678400s)
1123200s is 43.33% of 2011/4 (2592000s)
1123200s is 41.94% of 2011/5 (2678400s)
1123200s is 43.33% of 2011/6 (2592000s)
1123200s is 41.94% of 2011/7 (2678400s)
1123200s is 41.94% of 2011/8 (2678400s)
1123200s is 43.33% of 2011/9 (2592000s)
1123200s is 41.94% of 2011/10 (2678400s)
1123200s is 43.33% of 2011/11 (2592000s)
1123200s is 41.94% of 2011/12 (2678400s)
Or the very easy version:
days_in_month = Date.today.end_of_month.day.to_f
day_of_month = Date.today.strftime('%-d').to_f
percentage_of_way_through_month = day_of_month/days_in_month
or the reverse if you need remainder of the month:
days_in_month = Date.today.end_of_month.day.to_f
day_of_month = Date.today.strftime('%-d').to_f
percentage_of_month_to_go = 1-(day_of_month/days_in_month)
精彩评论