Class: Daterange

Inherits:
Object
  • Object
show all
Defined in:
lib/ndr_support/daterange.rb

Overview

Our “vague date” class, which can represent a single date or a date range.

Defined Under Namespace

Classes: WrongDateOrderError

Constant Summary collapse

OKYEARS =
1880..2030

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x1 = nil, x2 = nil, do_not_sort_dates: false) ⇒ Daterange

Returns a new instance of Daterange.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/ndr_support/daterange.rb', line 23

def initialize(x1 = nil, x2 = nil, do_not_sort_dates: false)
  x1 = x1.to_datetime if x1.is_a?(Date) || x1.is_a?(Time)
  x2 = x2.to_datetime if x2.is_a?(Date) || x2.is_a?(Time)

  if x1.is_a?(DateTime) && x2.is_a?(DateTime)
    @date1 = do_not_sort_dates ? x1 : [x1, x2].min
    @date2 = do_not_sort_dates ? x2 : [x1, x2].max
    @source = nil
  elsif x1.is_a?(Daterange) && x2.nil? # Patient model line 645
    @date1 = x1.date1
    @date2 = x1.date2
    @source = x1.source
  elsif x1.is_a?(DateTime) && x2.nil?
    @date1 = x1
    @date2 = x1
    @source = nil
  elsif x1.is_a?(String) && x2.nil?
    self.send(:source=, x1, do_not_sort_dates)
  else
    @date1 = nil
    @date2 = nil
    @source = nil
  end
  raise WrongDateOrderError, 'Invalid date range order' if wrong_date_order?(do_not_sort_dates)

  self.freeze
end

Instance Attribute Details

#date1Object

Returns the value of attribute date1.



7
8
9
# File 'lib/ndr_support/daterange.rb', line 7

def date1
  @date1
end

#date2Object

Returns the value of attribute date2.



7
8
9
# File 'lib/ndr_support/daterange.rb', line 7

def date2
  @date2
end

#sourceObject

Returns the value of attribute source.



7
8
9
# File 'lib/ndr_support/daterange.rb', line 7

def source
  @source
end

Class Method Details

.extract(dates_string) ⇒ Object



14
15
16
# File 'lib/ndr_support/daterange.rb', line 14

def self.extract(dates_string)
  dates_string.to_s.split(',').map { |str| new(str) }
end

.merge(dates_string) ⇒ Object



18
19
20
21
# File 'lib/ndr_support/daterange.rb', line 18

def self.merge(dates_string)
  ranges = extract(dates_string)
  new(ranges.map(&:date1).compact.min, ranges.map(&:date2).compact.max)
end

Instance Method Details

#<=>(other) ⇒ Object



110
111
112
# File 'lib/ndr_support/daterange.rb', line 110

def <=>(other)
  self.date1 <=> other.date1
end

#==(other) ⇒ Object



114
115
116
117
118
# File 'lib/ndr_support/daterange.rb', line 114

def ==(other)
  date1 == other.date1 && date2 == other.date2
rescue NoMethodError # Comparing to things that don't work like Dateranges, e.g. nil, integer
  false
end

#empty?Boolean

Returns:

  • (Boolean)


124
125
126
127
# File 'lib/ndr_support/daterange.rb', line 124

def empty?
  # An unspecified date will be empty. A valid or invalid date will not.
  @date1.nil? && @source.blank?
end

#exact?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/ndr_support/daterange.rb', line 129

def exact?
  @date1 == @date2
end

#intersects?(other) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/ndr_support/daterange.rb', line 120

def intersects?(other)
  !(self.empty? || other.empty?) && self.date1 <= other.date2 && self.date2 >= other.date1
end

#to_isoObject

used in Address model to_iso output must be SQL safe for security reasons



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

def to_iso
  date1.is_a?(DateTime) ? date1.to_iso : ''
end

#to_sObject

If we have a valid date range, return a string representation of it TODO: possibly add support for to_formatted_s(format) e.g. to_formatted_s(:short)



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ndr_support/daterange.rb', line 60

def to_s
  return '' unless @date1 && @date2
  if @date1 == @date2 # single date
    tidy_string_if_midnight(@date1)
  elsif tidy_string_if_midnight(@date1) == tidy_string_if_midnight(@date2.at_beginning_of_year) &&
        tidy_string_if_midnight(@date2) == tidy_string_if_midnight(@date1.at_end_of_year.at_beginning_of_day) # whole year
    @date1.strftime('%Y')
  elsif tidy_string_if_midnight(@date1) == tidy_string_if_midnight(@date2.at_beginning_of_month) &&
        tidy_string_if_midnight(@date2) == tidy_string_if_midnight(@date1.at_end_of_month.at_beginning_of_day) # whole month
    @date1.strftime('%m.%Y')
  else # range
    tidy_string_if_midnight(@date1) + ' to ' + tidy_string_if_midnight(@date2)
  end
end

#verboseObject

A long string representation of the date or range



82
83
84
85
86
87
88
89
90
# File 'lib/ndr_support/daterange.rb', line 82

def verbose
  return 'Bad date(s)' unless @date1 && @date2
  if @date1 == @date2 # single date
    _verbose(@date1)
  else # range
    'The period ' + _verbose(@date1) + ' to ' + _verbose(@date2) +
      ' inclusive (' + (@date2 - @date1 + 1).to_i.to_s + ' days)'
  end
end

#wrong_date_order?(do_not_sort_dates) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
54
55
56
# File 'lib/ndr_support/daterange.rb', line 51

def wrong_date_order?(do_not_sort_dates)
  return false unless do_not_sort_dates
  return false unless @date1.present? && @date2.present?

  @date1 > @date2
end