lib/fat_period/period.rb in fat_period-1.0.2 vs lib/fat_period/period.rb in fat_period-1.0.3
- old
+ new
@@ -71,10 +71,68 @@
TO_DATE = Period.new(Date::BOT, Date.current)
# Period from commercial beginning of time to commercial end of time.
FOREVER = Period.new(Date::BOT, Date::EOT)
+ # @group Parsing
+ #
+ # Return a period based on two date specs passed as strings (see
+ # `FatCore::Date.parse_spec`), a 'from' and a 'to' spec. The returned period
+ # begins on the first day of the period given as the `from` spec and ends on
+ # the last day given as the `to` spec. If the to spec is not given or is nil,
+ # the from spec is used for both the from- and to-spec.
+ #
+ # @example
+ # Period.parse('2014-11').inspect #=> Period('2014-11-01..2014-11-30')
+ # Period.parse('2014-11', '2015-3Q').inspect #=> Period('2014-11-01..2015-09-30')
+ # # Assuming this executes in December, 2014
+ # Period.parse('last_month', 'this_month').inspect #=> Period('2014-11-01..2014-12-31')
+ #
+ # @param from [String] spec ala FatCore::Date.parse_spec
+ # @param to [String] spec ala FatCore::Date.parse_spec
+ # @return [Period] from beginning of `from` to end of `to`
+ def self.parse(from, to = nil)
+ raise ArgumentError, 'Period.parse missing argument' unless from
+
+ to ||= from
+ first = Date.parse_spec(from, :from)
+ second = Date.parse_spec(to, :to)
+ Period.new(first, second) if first && second
+ end
+
+ # Return a period as in `Period.parse` from a String phrase in which the from
+ # spec is introduced with 'from' and, optionally, the to spec is introduced
+ # with 'to'. A phrase with only a to spec is treated the same as one with
+ # only a from spec. If neither 'from' nor 'to' appear in phrase, treat the
+ # whole string as a from spec.
+ #
+ # @example
+ # Period.parse_phrase('from 2014-11 to 2015-3Q') #=> Period('2014-11-01..2015-09-30')
+ # Period.parse_phrase('from 2014-11') #=> Period('2014-11-01..2014-11-30')
+ # Period.parse_phrase('from 2015-3Q') #=> Period('2015-09-01..2015-12-31')
+ # Period.parse_phrase('to 2015-3Q') #=> Period('2015-09-01..2015-12-31')
+ # Period.parse_phrase('2015-3Q') #=> Period('2015-09-01..2015-12-31')
+ #
+ # @param phrase [String] with 'from <spec> to <spec>'
+ # @return [Period] translated from phrase
+ def self.parse_phrase(phrase)
+ phrase = phrase.clean
+ if phrase =~ /\Afrom (.*) to (.*)\z/
+ from_phrase = $1
+ to_phrase = $2
+ elsif phrase =~ /\Afrom (.*)\z/
+ from_phrase = $1
+ to_phrase = nil
+ elsif phrase =~ /\Ato (.*)\z/
+ from_phrase = $1
+ else
+ from_phrase = phrase
+ to_phrase = nil
+ end
+ parse(from_phrase, to_phrase)
+ end
+
# @group Conversion
# Convert this Period to a Range.
#
# @return [Range]
@@ -204,68 +262,10 @@
# assumption with a parameter.
def years(days_in_year = 365.2425)
(days / days_in_year.to_f).to_f
end
- # @group Parsing
- #
- # Return a period based on two date specs passed as strings (see
- # `FatCore::Date.parse_spec`), a 'from' and a 'to' spec. The returned period
- # begins on the first day of the period given as the `from` spec and ends on
- # the last day given as the `to` spec. If the to spec is not given or is nil,
- # the from spec is used for both the from- and to-spec.
- #
- # @example
- # Period.parse('2014-11').inspect #=> Period('2014-11-01..2014-11-30')
- # Period.parse('2014-11', '2015-3Q').inspect #=> Period('2014-11-01..2015-09-30')
- # # Assuming this executes in December, 2014
- # Period.parse('last_month', 'this_month').inspect #=> Period('2014-11-01..2014-12-31')
- #
- # @param from [String] spec ala FatCore::Date.parse_spec
- # @param to [String] spec ala FatCore::Date.parse_spec
- # @return [Period] from beginning of `from` to end of `to`
- def self.parse(from, to = nil)
- raise ArgumentError, 'Period.parse missing argument' unless from
-
- to ||= from
- first = Date.parse_spec(from, :from)
- second = Date.parse_spec(to, :to)
- Period.new(first, second) if first && second
- end
-
- # Return a period as in `Period.parse` from a String phrase in which the from
- # spec is introduced with 'from' and, optionally, the to spec is introduced
- # with 'to'. A phrase with only a to spec is treated the same as one with
- # only a from spec. If neither 'from' nor 'to' appear in phrase, treat the
- # whole string as a from spec.
- #
- # @example
- # Period.parse_phrase('from 2014-11 to 2015-3Q') #=> Period('2014-11-01..2015-09-30')
- # Period.parse_phrase('from 2014-11') #=> Period('2014-11-01..2014-11-30')
- # Period.parse_phrase('from 2015-3Q') #=> Period('2015-09-01..2015-12-31')
- # Period.parse_phrase('to 2015-3Q') #=> Period('2015-09-01..2015-12-31')
- # Period.parse_phrase('2015-3Q') #=> Period('2015-09-01..2015-12-31')
- #
- # @param phrase [String] with 'from <spec> to <spec>'
- # @return [Period] translated from phrase
- def self.parse_phrase(phrase)
- phrase = phrase.clean
- if phrase =~ /\Afrom (.*) to (.*)\z/
- from_phrase = $1
- to_phrase = $2
- elsif phrase =~ /\Afrom (.*)\z/
- from_phrase = $1
- to_phrase = nil
- elsif phrase =~ /\Ato (.*)\z/
- from_phrase = $1
- else
- from_phrase = phrase
- to_phrase = nil
- end
- parse(from_phrase, to_phrase)
- end
-
# Possibly useful class method to take an array of periods and join all the
# contiguous ones, then return an array of the disjoint periods not
# contiguous to one another. An array of periods with no gaps should return
# an array of only one period spanning all the given periods.
#
@@ -301,9 +301,83 @@
CHUNK_RANGE = {
day: (1..1), week: (7..7), biweek: (14..14), semimonth: (15..16),
month: (28..31), bimonth: (59..62), quarter: (90..92),
half: (180..183), year: (365..366)
}.freeze
+
+ # Return a period representing a chunk containing a given Date.
+ def self.day_containing(date)
+ Period.new(date, date)
+ end
+
+ def self.week_containing(date)
+ Period.new(date.beginning_of_week, date.end_of_week)
+ end
+
+ def self.biweek_containing(date)
+ Period.new(date.beginning_of_biweek, date.end_of_biweek)
+ end
+
+ def self.semimonth_containing(date)
+ Period.new(date.beginning_of_semimonth, date.end_of_semimonth)
+ end
+
+ def self.month_containing(date)
+ Period.new(date.beginning_of_month, date.end_of_month)
+ end
+
+ def self.bimonth_containing(date)
+ Period.new(date.beginning_of_bimonth, date.end_of_bimonth)
+ end
+
+ def self.quarter_containing(date)
+ Period.new(date.beginning_of_quarter, date.end_of_quarter)
+ end
+
+ def self.half_containing(date)
+ Period.new(date.beginning_of_half, date.end_of_half)
+ end
+
+ def self.year_containing(date)
+ Period.new(date.beginning_of_year, date.end_of_year)
+ end
+
+ # Return a Period representing a chunk containing today.
+ def self.this_day
+ day_containing(Date.current)
+ end
+
+ def self.this_week
+ week_containing(Date.current)
+ end
+
+ def self.this_biweek
+ biweek_containing(Date.current)
+ end
+
+ def self.this_semimonth
+ semimonth_containing(Date.current)
+ end
+
+ def self.this_month
+ month_containing(Date.current)
+ end
+
+ def self.this_bimonth
+ bimonth_containing(Date.current)
+ end
+
+ def self.this_quarter
+ quarter_containing(Date.current)
+ end
+
+ def self.this_half
+ half_containing(Date.current)
+ end
+
+ def self.this_year
+ year_containing(Date.current)
+ end
# Return the chunk symbol represented by this period if it covers a single
# calendar period; otherwise return :irregular.
#
# @example