class Date
Extension for Date
to calculate a forward date with compressed syntax
Copyright 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Public Instance Methods
calculate time adjustmentfor pos in epoch (_F_irst, _M_id, _L_ast, _W_orking day) epoch: D - day: W - Monday epoch: W - week: F - Monday, M - Wednesday, L - Friday, W - Monday epoch: M - month: F - 1st, M - 15th, L - last, W - Monday epoch: Y - year: F - 01/01, M - 06/30, L - 12/31, W - Monday epoch: q - quarter: W - Monday
# File lib/date_helper/date.rb, line 169 def adjust( epoch, pos, ref=self ) case epoch when "D" case pos when "W" # if saturday or sunday, fall back to last monday, then add one week for monday coming up (wday % 6) != 0 ? self : monday.advance(:days => 7) else self end #case when "W", "C" # week case pos when "F" # Monday monday < ref ? advance( :weeks => 1).monday : monday when "M" # Wednesday = Monday + 2 days monday.advance(:days => 2) < ref ? advance( :weeks => 1).monday.advance(:days => 2) : monday.advance(:days => 2) when "L" # Friday = Monday + 4 days monday.advance(:days => 4) < ref ? advance( :weeks => 1).monday.advance(:days => 4) : monday.advance(:days => 4) when "W" # if saturday or sunday, fall back to last monday, then add one week for monday coming up (wday % 6) != 0 ? self : monday.advance(:days => 7) else self end #case when "M" # month case pos when "F" # 1st change(:day => 1) < ref ? advance( :months => 1).beginning_of_month.change(:day => 1) : change(:day => 1) when "M" # 15th change(:day => 15) < ref ? advance( :months => 1).beginning_of_month.change(:day => 15) : change(:day => 15) when "L" # last day end_of_month when "W" # if saturday or sunday, fall back to last monday, then add one week for monday coming up (wday % 6) != 0 ? self : monday.advance(:days => 7) else self end #case when "Y" # year case pos when "F" # Jan. 1st beginning_of_year < ref ? advanve(:years => 1).beginning_of_year : beginning_of_year when "M" # Jun. 30th change(:month => 5, :day => 30) < ref ? advance(:years => 1).change(:month => 5, :day => 30) : change(:month => 5, :day => 30) when "L" # Dec. 31st change(:month => 12, :day => 31) when "W" # if saturday or sunday, fall back to last monday, then add one week for monday coming up (wday % 6) != 0 ? self : monday.advance(:days => 7) else self end #case when "q" case pos when "F" # Jan. 1st beginning_of_quarter < ref ? advance( :months => 3).beginning_of_quarter : beginning_of_quarter when "M" # mid quarter beginning_of_quarter.advance(:months => 1).advance(:days => 14) < ref ? advance(:quarters => 1).beginning_of_quarter.advance(:months => 1).advance(:days => 14) : beginning_of_quarter.advance(:months => 1).advance(:days => 14) when "L" # end quarter end_of_quarter when "W" # if saturday or sunday, fall back to last monday, then add one week for monday coming up (wday % 6) != 0 ? self : monday.advance(:days => 7) else self end #case else self end #case epoch end
calc
# File lib/date_helper/date.rb, line 84 def calc( rule ) new_date = nil new_rule = nil if rule.present? m = parse_rule( rule ) if m['mockswitch'] # mockswitch does not calculate anything # mockswitch is removed from new_rule, however new_rule = unmock( rule, m ) elsif self <= Date.today || m['force'] if( m['epoch'] && m['num'] ) new_date = move( m['epoch'], m['num'] ) new_date = new_date.adjust( m['epoch'], m['pos'], self ) new_date = new_date.adjust("D", "W", new_date) if m["workingday"] # adjust working day if m['killswitch'] new_rule = "" else new_rule = rule end end #if end #if end #if [new_date, new_rule] end
forward
# File lib/date_helper/date.rb, line 124 def forward( rule ) calc( rule ).first end
calculate num times advance of epoch epoch: D - n days epoch: W - n weeks epoch: M - n months epoch: Y - n years
epoch: C - n calendar weeks (absolute, within this year, not relative) epoch: m - n mondays epoch: q - q quarters
# File lib/date_helper/date.rb, line 139 def move( epoch, num ) case epoch when "D" self + num.to_i when "W" self + num.to_i * 7 when "M" self >> num.to_i when "Y" self >> num.to_i * 12 when "m" (self + num.to_i * 7).monday when "q" (self >> num.to_i * 3).beginning_of_quarter when "C" # calendar week 1 is the week containing Jan. 4th change(:month => 1, :day => 4).advance( :weeks => (num.to_i - 1)) else self end #case end
Private Instance Methods
# File lib/date_helper/date.rb, line 283 def parse_rule(rule) m = {} matches = /(?<epoch>[DWMYCmq])(?<num>[0-9]+)(?<pos>[XFMLW]?)(?<kfmw>[-!W\*]*)(?<trailing_rest>.*)/.match(rule) if matches.present? m.merge!(Hash[ matches.names.zip( matches.captures ) ]) m.merge!('killswitch' => m['kfmw'].match(/-/).to_s.presence) m.merge!('force' => m['kfmw'].match(/!/).to_s.presence) m.merge!('mockswitch' => m['kfmw'].match(/\*/).to_s.presence) m.merge!('workingday' => m['kfmw'].match(/W/).to_s.presence) end m.compact end
# File lib/date_helper/date.rb, line 301 def unmock( rule, m=nil ) m = parse_rule( rule ) unless m if m['mockswitch'].present? "#{m['epoch']}#{m['num']}#{m['pos']}#{m['killswitch']}#{m['force']}#{m['trailing_rest']}" else nil end end