Class: DtTools

Inherits:
Object
  • Object
show all
Defined in:
lib/gloo/objs/dt/dt_tools.rb

Constant Summary collapse

INCOMPATIBLE_DT_KINDS =

Kind pairings that can never be compared, even though both sides look like date/time values (eg. a time can't be compared to a date).

[
  [ :date, :time ], [ :time, :date ],
  [ :time, :datetime ], [ :datetime, :time ]
].freeze

Class Method Summary collapse

Class Method Details

.add(date, modifier = "1 day") ⇒ Object

Given a date, add the modifier to it. The modifier takes the form of "1 day" or "2 weeks".



33
34
35
36
37
38
39
40
# File 'lib/gloo/objs/dt/dt_tools.rb', line 33

def self.add date, modifier="1 day"
  # Split out amount and unit
  amount, unit = modifier.split(' ')  

  # converts "1 day" to 1.day
  duration = amount.to_i.send( unit )
  return date + duration
end

.beginning_of_weekObject

Get the beginning of the week.



63
64
65
# File 'lib/gloo/objs/dt/dt_tools.rb', line 63

def self.beginning_of_week
  return Time.now.beginning_of_week( start_day = :sunday )
end

.compare_dt(left, right) ⇒ Object

Compare two raw values with date/time/datetime semantics. Returns :not_dt if neither value looks like a date, time, or datetime, so the caller can fall back to its normal comparison logic. Otherwise returns -1, 0, or 1 (as with <=>), or nil if the two values can't be meaningfully compared.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/gloo/objs/dt/dt_tools.rb', line 208

def self.compare_dt( left, right )
  l_kind = dt_kind( left )
  r_kind = dt_kind( right )
  return :not_dt if l_kind.nil? && r_kind.nil?

  if l_kind && r_kind
    return nil if INCOMPATIBLE_DT_KINDS.include?( [ l_kind, r_kind ] )

    l = strict_dt_parse( l_kind, left )
    r = strict_dt_parse( r_kind, right )
    return nil if l.nil? || r.nil?

    return l <=> r
  end

  # Only one side looks like a date/time/datetime value. Try to parse
  # the other side as that same kind (eg. a date compared to a string).
  kind = l_kind || r_kind
  known, other = l_kind ? [ left, right ] : [ right, left ]
  return nil unless other.is_a? String

  k = strict_dt_parse( kind, known )
  return nil if k.nil?

  o = loose_dt_parse( kind, other )
  return nil if o.nil?

  result = normalize_dt( kind, k ) <=> o
  return l_kind ? result : -result
end

.dt_kind(value) ⇒ Object

What kind of date/time value does this string look like? Returns :date, :time, :datetime, or nil if it doesn't match the exact format that gloo date/time/datetime objects use.



150
151
152
153
154
155
156
157
# File 'lib/gloo/objs/dt/dt_tools.rb', line 150

def self.dt_kind( value )
  return nil unless value.is_a? String
  return :datetime if value =~ /\A\d{4}\.\d{2}\.\d{2}\s\d{2}:\d{2}:\d{2}\s(am|pm)\z/i
  return :date if value =~ /\A\d{4}\.\d{2}\.\d{2}\z/
  return :time if value =~ /\A\d{2}:\d{2}:\d{2}\s(am|pm)\z/i

  return nil
end

.in_next_ten_days?(dt) ⇒ Boolean

Is the date in the next 10 days?

Returns:

  • (Boolean)


70
71
72
73
# File 'lib/gloo/objs/dt/dt_tools.rb', line 70

def self.in_next_ten_days?( dt )
  return false if DtTools.is_past?( dt )
  dt < 10.days.from_now.end_of_day
end

.is_dt_type?(obj) ⇒ Boolean

Is the given object a base Date Time object? True for DateTime and Time

Returns:

  • (Boolean)


18
19
20
21
22
# File 'lib/gloo/objs/dt/dt_tools.rb', line 18

def self.is_dt_type? obj
  return true if obj.is_a? ::DateTime
  return true if obj.is_a? ::Time
  return false
end

.is_future?(dt) ⇒ Boolean

Is the date in the future?

Returns:

  • (Boolean)


85
86
87
# File 'lib/gloo/objs/dt/dt_tools.rb', line 85

def self.is_future?( dt )
  dt > Time.now.end_of_day
end

.is_past?(dt) ⇒ Boolean

Is the date in the past?

Returns:

  • (Boolean)


78
79
80
# File 'lib/gloo/objs/dt/dt_tools.rb', line 78

def self.is_past?( dt )
  dt < Time.now.beginning_of_day
end

.is_this_week?(dt) ⇒ Boolean

Is the given date this week?

Returns:

  • (Boolean)


125
126
127
128
129
130
131
# File 'lib/gloo/objs/dt/dt_tools.rb', line 125

def self.is_this_week?( dt )
  return false if dt.blank?
  dt = Chronic.parse( dt ) if dt.is_a?( String )
  return false if dt <= ::Time.now.beginning_of_week( start_day = :sunday )
  return false if dt >= ::Time.now.end_of_week( start_day = :sunday )
  return true
end

.is_today?(dt) ⇒ Boolean

Is the given date today?

Returns:

  • (Boolean)


92
93
94
95
96
97
98
# File 'lib/gloo/objs/dt/dt_tools.rb', line 92

def self.is_today?( dt )
  return false if dt.blank?
  dt = Chronic.parse( dt ) if dt.is_a? String
  return false if dt <= ::Time.now.beginning_of_day
  return false if dt >= ::Time.now.end_of_day
  return true
end

.is_tomorrow?(dt) ⇒ Boolean

Is the given date tomorrow?

Returns:

  • (Boolean)


103
104
105
106
107
108
109
# File 'lib/gloo/objs/dt/dt_tools.rb', line 103

def self.is_tomorrow?( dt )
  return false if dt.blank?
  dt = Chronic.parse( dt ) if dt.is_a? String
  return false if dt <= ( ::Time.now.beginning_of_day + 1.day )
  return false if dt >= ( ::Time.now.end_of_day + 1.day )
  return true
end

.is_yesterday?(dt) ⇒ Boolean

Is the given date yesterday?

Returns:

  • (Boolean)


114
115
116
117
118
119
120
# File 'lib/gloo/objs/dt/dt_tools.rb', line 114

def self.is_yesterday?( dt )
  return false if dt.blank?
  dt = Chronic.parse( dt ) if dt.is_a? String
  return false if dt <= ( ::Time.now.beginning_of_day - 1.day )
  return false if dt >= ( ::Time.now.end_of_day - 1.day )
  return true
end

.loose_dt_parse(kind, str) ⇒ Object

Loosely parse an arbitrary string (eg. "3 days from now") and reduce it to the granularity of the given kind for comparison.

Bare numbers (eg. "11", "2026") are rejected even though Chronic can parse them - it treats them as an hour or day-of-month relative to today, which is misleading rather than a genuine date/time value.



190
191
192
193
194
195
196
197
198
199
# File 'lib/gloo/objs/dt/dt_tools.rb', line 190

def self.loose_dt_parse( kind, str )
  return nil if str =~ /\A\s*\d+\s*\z/

  dt = Chronic.parse( str )
  return nil if dt.nil?

  return normalize_dt( kind, dt.to_datetime )
rescue StandardError
  return nil
end

.normalize_dt(kind, dt) ⇒ Object

Reduce a parsed value down to the granularity of the given kind, so a strictly-parsed value and a loosely-parsed value can be compared.



175
176
177
178
179
180
# File 'lib/gloo/objs/dt/dt_tools.rb', line 175

def self.normalize_dt( kind, dt )
  return dt.to_date if kind == :date
  return [ dt.hour, dt.min, dt.sec ] if kind == :time

  return dt
end

.strict_dt_parse(kind, str) ⇒ Object

Strictly parse a string using the exact format for the given kind.



162
163
164
165
166
167
168
169
# File 'lib/gloo/objs/dt/dt_tools.rb', line 162

def self.strict_dt_parse( kind, str )
  format = { date: Gloo::Objs::Date::DEFAULT_FORMAT,
             time: Gloo::Objs::Time::DEFAULT_FORMAT,
             datetime: Gloo::Objs::Datetime::DEFAULT_FORMAT }[ kind ]
  return ::DateTime.strptime( str, format )
rescue StandardError
  return nil
end

.sub(dt, modifier = "1 day") ⇒ Object

Given a date, subtract the modifier from it. The modifier takes the form of "1 day" or "2 weeks".



46
47
48
49
50
51
52
53
# File 'lib/gloo/objs/dt/dt_tools.rb', line 46

def self.sub dt, modifier="1 day"
  # Split out amount and unit
  amount, unit = modifier.split(' ')  

  # converts "1 day" to 1.day
  duration = amount.to_i.send( unit )  
  return dt - duration
end