Module: DateUtils

Defined in:
lib/date_utils.rb

Constant Summary collapse

BUSINESS_DAYS =

Mon-Fri

[1, 2, 3, 4, 5].freeze
EFFECTIVE_TZ =

Allow the caller to override the active timezone via environment variable. This is commonly needed in CI pipelines where TZ may differ from production. Defaults to UTC when DATE_UTILS_TZ is unset or blank.

(ENV['DATE_UTILS_TZ'].to_s.strip.empty? ? 'UTC' : ENV['DATE_UTILS_TZ']).freeze
HOLIDAYS_URL =

Optional remote holiday-calendar feed. When set, business_day? will load the calendar on first use and cache it for the process lifetime. Example: DATE_UTILS_HOLIDAYS_URL=calendarific.com/api/v2/holidays?…

ENV.fetch('DATE_UTILS_HOLIDAYS_URL', nil)
CACHE_FILE =

Persistent disk cache for the holiday calendar (survives process restarts).

File.join(Dir.tmpdir, "date_utils_holidays_#{Process.uid}.json").freeze

Class Method Summary collapse

Class Method Details

.add_business_days(date, n) ⇒ Object



63
64
65
66
67
# File 'lib/date_utils.rb', line 63

def self.add_business_days(date, n)
  d = date
  n.times { d = next_business_day(d) }
  d
end

.age_in_years(birth_date, as_of: Date.today) ⇒ Object



89
90
91
92
93
# File 'lib/date_utils.rb', line 89

def self.age_in_years(birth_date, as_of: Date.today)
  years = as_of.year - birth_date.year
  years -= 1 if as_of < birth_date.next_year(years)
  years
end

.beginning_of_month(date) ⇒ Object



77
78
79
# File 'lib/date_utils.rb', line 77

def self.beginning_of_month(date)
  Date.new(date.year, date.month, 1)
end

.business_day?(date) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/date_utils.rb', line 53

def self.business_day?(date)
  BUSINESS_DAYS.include?(date.wday)
end

.business_days_between(start_date, end_date) ⇒ Object



69
70
71
# File 'lib/date_utils.rb', line 69

def self.business_days_between(start_date, end_date)
  (start_date..end_date).count { |d| business_day?(d) }
end

.end_of_month(date) ⇒ Object



81
82
83
# File 'lib/date_utils.rb', line 81

def self.end_of_month(date)
  Date.new(date.year, date.month, -1)
end

.format(date, fmt = '%Y-%m-%d') ⇒ Object



73
74
75
# File 'lib/date_utils.rb', line 73

def self.format(date, fmt = '%Y-%m-%d')
  date.strftime(fmt)
end

.next_business_day(date) ⇒ Object



57
58
59
60
61
# File 'lib/date_utils.rb', line 57

def self.next_business_day(date)
  d = date + 1
  d += 1 until business_day?(d)
  d
end

.parse(str, formats: ['%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%Y%m%d']) ⇒ Object

Raises:

  • (ArgumentError)


44
45
46
47
48
49
50
51
# File 'lib/date_utils.rb', line 44

def self.parse(str, formats: ['%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%Y%m%d'])
  formats.each do |fmt|
    return Date.strptime(str, fmt)
  rescue ArgumentError
    next
  end
  raise ArgumentError, "Cannot parse date: #{str}"
end

.quarter(date) ⇒ Object



85
86
87
# File 'lib/date_utils.rb', line 85

def self.quarter(date)
  ((date.month - 1) / 3) + 1
end