Created
January 24, 2010 20:43
-
-
Save brianjlandau/285431 to your computer and use it in GitHub Desktop.
A Time Duration object that is meant to primarily be used inside a Rails app (as it requires i18n and ActiveSupport). It aslo uses chronic_duration to parse a time period/duration word phrase..
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| en: | |
| datetime: | |
| distance_in_words: | |
| x_weeks: | |
| one: '1 week' | |
| other: "{{count}} weeks" | |
| x_hours: | |
| one: "1 hour" | |
| other: "{{count}} hours" | |
| x_years: | |
| one: "1 year" | |
| other: "{{count}} years" | |
| x_seconds: | |
| one: "1 second" | |
| other: "{{count}} seconds" | |
| x_minutes: | |
| one: "1 minute" | |
| other: "{{count}} minutes" | |
| x_days: | |
| one: "1 day" | |
| other: "{{count}} days" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'i18n' | |
| require 'active_support/memoizable' | |
| gem 'brianjlandau-chronic_duration' | |
| require 'chronic_duration' | |
| ChronicDuration.raise_exceptions = true | |
| class TimeDuration | |
| include Comparable | |
| extend ActiveSupport::Memoizable | |
| SECOND = 1 | |
| MINUTE = 60 * SECOND | |
| HOUR = 60 * MINUTE | |
| DAY = 24 * HOUR | |
| WEEK = 7 * DAY | |
| YEAR = (365.25 * DAY).to_i | |
| attr_reader :total_seconds | |
| def self.parse(duration) | |
| new(ChronicDuration.parse(duration)) | |
| end | |
| def self.[](seconds) | |
| new(seconds) | |
| end | |
| def initialize(seconds) | |
| @total_seconds = seconds.to_i | |
| end | |
| def <=>(other) | |
| total_seconds <=> other.to_i | |
| end | |
| def +(other) | |
| self.class.new(total_seconds + other.to_i) | |
| end | |
| def -(other) | |
| self.class.new(total_seconds - other.to_i) | |
| end | |
| def -@ | |
| self.class.new(-total_seconds) | |
| end | |
| def +@ | |
| self.class.new(+total_seconds) | |
| end | |
| def self.===(other) | |
| other.is_a?(TimeDuration) rescue super | |
| end | |
| def years ; to_h[:years] ; end | |
| memoize :years | |
| def weeks ; to_h[:weeks] ; end | |
| memoize :weeks | |
| def days ; to_h[:days] ; end | |
| memoize :days | |
| def hours ; to_h[:hours] ; end | |
| memoize :hours | |
| def minutes ; to_h[:minutes] ; end | |
| memoize :minutes | |
| def seconds ; to_h[:seconds] ; end | |
| memoize :seconds | |
| def inspect | |
| date_parts = [] | |
| %w(years weeks days).each do |date_segment| | |
| if self.send(date_segment) > 0 | |
| date_parts << "#{self.send(date_segment)} #{date_segment}" | |
| end | |
| end | |
| date_string = date_parts.join(' ') | |
| time_string = '%02d:%02d:%02d' % [hours, minutes, seconds] | |
| "#<#{self.class.name}: #{[date_string, time_string].join(' ').strip}>" | |
| end | |
| def to_i | |
| total_seconds | |
| end | |
| def to_f | |
| total_seconds.to_f | |
| end | |
| def to_h | |
| h, s = {}, total_seconds | |
| h[:years], s = *s.divmod(YEAR) | |
| h[:weeks], s = *s.divmod(WEEK) | |
| h[:days], s = *s.divmod(DAY) | |
| h[:hours], s = *s.divmod(HOUR) | |
| h[:minutes], s = *s.divmod(MINUTE) | |
| h[:seconds], s = *s.divmod(SECOND) | |
| h | |
| end | |
| memoize :to_h | |
| def strftime(fmt) | |
| hx = { | |
| 'y' => to_h[:years] , | |
| 'w' => to_h[:weeks] , | |
| 'd' => to_h[:days] , | |
| 'h' => to_h[:hours] , | |
| 'm' => to_h[:minutes], | |
| 's' => to_h[:seconds], | |
| 't' => total_seconds | |
| } | |
| fmt.gsub(/%?%(y|w|d|h|m|s|t)/) do |match| | |
| hx[match[1..1]] | |
| end.gsub('%%', '%') | |
| end | |
| def distance_of_time_in_words(options = {}) | |
| words = [] | |
| I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale| | |
| if years > 0 | |
| words << locale.t(:x_years, :count => years) | |
| end | |
| if weeks > 0 | |
| words << locale.t(:x_weeks, :count => weeks) | |
| end | |
| if days > 0 | |
| words << locale.t(:x_days, :count => days) | |
| end | |
| if hours > 0 | |
| words << locale.t(:x_hours, :count => hours) | |
| end | |
| if minutes > 0 | |
| words << locale.t(:x_minutes, :count => minutes) | |
| end | |
| if seconds > 0 | |
| words << locale.t(:x_seconds, :count => seconds) | |
| end | |
| end | |
| return words.to_sentence(:words_connector => ' ', :last_word_connector => ' and ') | |
| end | |
| alias to_s distance_of_time_in_words | |
| private | |
| def method_missing(method, *args, &block) | |
| total_seconds.send(method, *args) | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment