require 'chronic' module ByStar def self.included(base) base.extend ClassMethods end module ClassMethods # Examples: # by_year(2010) # # 2-digit year: # by_year(10) # # Time or Date object: # by_year(time) # # String: # by_year("2010") def by_year(time=Time.zone.now.year, options={}, &block) year = work_out_year(time) start_time = Time.utc(year, 1, 1) end_time = start_time.end_of_year by_star(start_time, end_time, options, &block) rescue ArgumentError raise ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039). This is no longer a problem on Ruby versions > 1.8.7, so we recommend you upgrade to at least 1.8.7." end # Examples: # by_month(1) # by_month("January") # by_month("January", :year => 2008) # by_month(time) def by_month(time=Time.zone.now.month, options={}, &block) time = Time.zone.now.month if time.nil? year = options[:year] ||= Time.zone.now.year # Work out what actual month is. month = if time.is_a?(Numeric) && (1..12).include?(time) time elsif valid_time_or_date?(time) year = time.year time.month elsif time.is_a?(String) && Date::MONTHNAMES.include?(time) Date::MONTHNAMES.index(time) else raise ParseError, "Value is not an integer (between 1 and 12), time object or string (make sure you typed the name right)." end start_time = Time.utc(year, month, 1) end_time = start_time.end_of_month by_star(start_time, end_time, options, &block) end # Examples: # # 18th fortnight of 2004 # Post.by_fortnight(18, :year => 2004) def by_fortnight(time=Time.zone.now, options = {}, &block) time = parse(time) # If options[:year] is passed in, use that year regardless. year = work_out_year(options[:year]) if options[:year] # If the first argument is a date or time, ask it for the year year ||= time.year unless time.is_a?(Numeric) # If the first argument is a fixnum, assume this year. year ||= Time.zone.now.year # Dodgy! # Surely there's a method in Rails to do this. start_time = if valid_time_or_date?(time) time.beginning_of_year + (time.strftime("%U").to_i).weeks elsif time.is_a?(Numeric) && time <= 26 Time.utc(year, 1, 1) + ((time.to_i) * 2).weeks else raise ParseError, "by_fortnight takes only a Time or Date object, a Fixnum (less than or equal to 26) or a Chronicable string." end start_time = start_time.beginning_of_week end_time = start_time + 2.weeks by_star(start_time, end_time, options, &block) end # Examples: # # 36th week # Post.by_week(36) # Post.by_week(36.54) # Post.by_week(36, :year => 2004) # Post.by_week(