Class: Date

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/edtf/date.rb

Constant Summary collapse

PRECISION =
[:year, :month, :day].freeze
PRECISIONS =
Hash[*PRECISION.map { |p| [p, "#{p}s".to_sym] }.flatten].freeze
FORMATS =
%w{ %04d %02d %02d }.freeze
SYMBOLS =
{
  :uncertain   => '?',
  :approximate => '~',
  :calendar    => '^',
  :unspecified => 'X'
}.freeze
EXTENDED_ATTRIBUTES =
%w{
  calendar precision uncertain approximate unspecified skip_timezone
}.map(&:to_sym).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#approximateObject



97
98
99
# File 'lib/edtf/date.rb', line 97

def approximate
  @approximate ||= EDTF::Uncertainty.new(nil, nil, nil, 8)
end

#calendarObject

Returns the value of attribute calendar.



34
35
36
# File 'lib/edtf/date.rb', line 34

def calendar
  @calendar
end

#skip_timezoneObject

Returns the value of attribute skip_timezone.



34
35
36
# File 'lib/edtf/date.rb', line 34

def skip_timezone
  @skip_timezone
end

#uncertainObject



93
94
95
# File 'lib/edtf/date.rb', line 93

def uncertain
  @uncertain ||= EDTF::Uncertainty.new
end

#unspecifiedObject



101
102
103
# File 'lib/edtf/date.rb', line 101

def unspecified
  @unspecified ||= EDTF::Unspecified.new
end

Class Method Details

.edtf(input, options = {}) ⇒ Object



23
24
25
26
27
# File 'lib/edtf/date.rb', line 23

def edtf(input, options = {})
  edtf!(input, options)
rescue
  nil
end

.edtf!(input, options = {}) ⇒ Object



29
30
31
# File 'lib/edtf/date.rb', line 29

def edtf!(input, options = {})
  ::EDTF::Parser.new(options).parse!(input)
end

Instance Method Details

#<=>(other) ⇒ Object



258
259
260
261
262
263
264
265
266
267
# File 'lib/edtf/date.rb', line 258

def <=>(other)
  case other
  when ::Date
    values <=> other.values
  when EDTF::Interval, EDTF::Season, EDTF::Epoch
    other.cover?(self) ? other.min <=> self : 0
  else
    nil
  end
end

#advance(options) ⇒ Object

Provides precise Date calculations for years, months, and days. The options parameter takes a hash with any of these keys: :years, :months, :weeks, :days.



63
64
65
# File 'lib/edtf/date.rb', line 63

def advance(options)
  original_advance(options).copy_extended_attributes(self)
end

#approximate!(arguments = precision_filter) ⇒ Object Also known as: approximately!



123
124
125
126
# File 'lib/edtf/date.rb', line 123

def approximate!(arguments = precision_filter)
  approximate.uncertain!(arguments)
  self
end

#approximate?(arguments = precision_filter) ⇒ Boolean Also known as: approximately?

Returns:

  • (Boolean)


117
118
119
# File 'lib/edtf/date.rb', line 117

def approximate?(arguments = precision_filter)
  approximate.uncertain?(arguments)
end

#calendar?Boolean

Returns true if the Date has an EDTF calendar string attached.

Returns:

  • (Boolean)


163
# File 'lib/edtf/date.rb', line 163

def calendar?; !!@calendar; end

#certain!(arguments = precision_filter) ⇒ Object



107
108
109
110
# File 'lib/edtf/date.rb', line 107

def certain!(arguments = precision_filter)
  uncertain.certain!(arguments)
  self
end

#change(options) ⇒ Object

Returns a new Date where one or more of the elements have been changed according to the options parameter.



71
72
73
74
75
76
77
# File 'lib/edtf/date.rb', line 71

def change(options)
  d = original_change(options)
  EXTENDED_ATTRIBUTES.each do |attribute|
    d.send("#{attribute}=", options[attribute] || send(attribute))
  end
  d
end

#edtfObject Also known as: to_edtf

Returns the Date’s EDTF string.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/edtf/date.rb', line 174

def edtf
  return "Y#{year}" if long_year?

  v = values
  s = FORMATS.take(v.length).zip(v).map { |f,d| f % d.abs }
  s[0] = "-#{s[0]}" if year < 0
  s = unspecified.mask(s)

  unless (h = ua_hash).zero?
    #
    # To efficiently calculate the uncertain/approximate state we use
    # the bitmask. The primary flags are:
    #
    # Uncertain:    1 - year,  2 - month,  4 - day
    # Approximate:  8 - year, 16 - month, 32 - day
    #
    # Invariant: assumes that uncertain/approximate are not set for values
    # not covered by precision!
    #
    y, m, d = s

    # ?/~ if true-false or true-true and other false-true
    y << SYMBOLS[:uncertain]   if  3&h==1 || 27&h==19
    y << SYMBOLS[:approximate] if 24&h==8 || 27&h==26


    # combine if false-true-true and other m == d
    if 7&h==6 && (48&h==48 || 48&h==0)  || 56&h==48 && (6&h==6 || 6&h==0)
      m[0,0] = '('
      d << ')'
    else
      case
      # false-true
      when 3&h==2 || 24&h==16
        m[0,0] = '('
        m << ')'

      # *-false-true
      when 6&h==4 || 48&h==32
        d[0,0] = '('
        d << ')'
      end

      # ?/~ if *-true-false or *-true-true and other m != d
      m << SYMBOLS[:uncertain]   if h!=31 && (6&h==2  ||  6&h==6  && (48&h==16 || 48&h==32))
      m << SYMBOLS[:approximate] if h!=59 && (48&h==16 || 48&h==48 && (6&h==2 || 6&h==4))
    end

    # ?/~ if *-*-true
    d << SYMBOLS[:uncertain]   if  4&h==4
    d << SYMBOLS[:approximate] if 32&h==32
  end

  s = s.join('-')
  s << SYMBOLS[:calendar] << calendar if calendar?
  s
end

#initialize_copy(other) ⇒ Object



52
53
54
55
# File 'lib/edtf/date.rb', line 52

def initialize_copy(other)
  original_initialize_copy(other)
  copy_extended_attributes(other)
end

#long_year?Boolean

Returns true if this Date/Time has year precision and the year exceeds four digits.

Returns:

  • (Boolean)


284
285
286
# File 'lib/edtf/date.rb', line 284

def long_year?
  year_precision? && year.abs > 9999
end

#negateObject Also known as: -@

Returns the same date but with negated year.



277
278
279
# File 'lib/edtf/date.rb', line 277

def negate
  change(:year => year * -1)
end

#next(n = 1) ⇒ Object

Returns an array of the next n days, months, or years depending on the current Date/Time’s precision.



238
239
240
# File 'lib/edtf/date.rb', line 238

def next(n = 1)
  1.upto(n).map { |by| advance(PRECISIONS[precision] => by) }
end

#original_advanceObject

Alias advance method from Active Support.



59
# File 'lib/edtf/date.rb', line 59

alias original_advance advance

#original_changeObject

Alias change method from Active Support.



68
# File 'lib/edtf/date.rb', line 68

alias original_change change

#original_initialize_copyObject



50
# File 'lib/edtf/date.rb', line 50

alias original_initialize_copy initialize_copy

#precise!(arguments = precision_filter) ⇒ Object Also known as: precisely!



136
137
138
139
# File 'lib/edtf/date.rb', line 136

def precise!(arguments = precision_filter)
  approximate.certain!(arguments)
  self
end

#precise?(arguments = precision_filter) ⇒ Boolean Also known as: precisely?

Returns:

  • (Boolean)


130
131
132
# File 'lib/edtf/date.rb', line 130

def precise?(arguments = precision_filter)
  !approximate?(arguments)
end

#precisionObject

Returns this Date’s precision.



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

def precision
  @precision ||= :day
end

#precision=(precision) ⇒ Object

Sets this Date/Time’s precision to the passed-in value.

Raises:

  • (ArgumentError)


86
87
88
89
90
91
# File 'lib/edtf/date.rb', line 86

def precision=(precision)
  precision = precision.to_sym
  raise ArgumentError, "invalid precision #{precision.inspect}" unless PRECISION.include?(precision)
  @precision = precision
  update_precision_filter[-1]
end

#prev(n = 1) ⇒ Object

Returns the Date of the previous day, month, or year depending on the current Date/Time’s precision.



250
251
252
253
254
255
256
# File 'lib/edtf/date.rb', line 250

def prev(n = 1)
  if n > 1
    1.upto(n).map { |by| advance(PRECISIONS[precision] => -by) }
  else
    advance(PRECISIONS[precision] => -1)
  end
end

#seasonObject

Converts the Date into a season.



169
170
171
# File 'lib/edtf/date.rb', line 169

def season
  Season.new(self)
end

#season?Boolean

Returns false for Dates.

Returns:

  • (Boolean)


160
# File 'lib/edtf/date.rb', line 160

def season?; false; end

#skip_timezone?Boolean

Returns true if the Date’s EDTF string should be printed without timezone.

Returns:

  • (Boolean)


166
# File 'lib/edtf/date.rb', line 166

def skip_timezone?; !!@skip_timezone; end

#specified!(arguments = precision_filter) ⇒ Object Also known as: specific!



152
153
154
155
# File 'lib/edtf/date.rb', line 152

def specified!(arguments = precision_filter)
  unspecified.specified!(arguments)
  self
end

#succObject



244
245
246
# File 'lib/edtf/date.rb', line 244

def succ
  advance(PRECISIONS[precision] => 1)
end

#uncertain!(arguments = precision_filter) ⇒ Object



112
113
114
115
# File 'lib/edtf/date.rb', line 112

def uncertain!(arguments = precision_filter)
  uncertain.uncertain!(arguments)
  self
end

#unspecified!(arguments = precision_filter) ⇒ Object Also known as: unspecific!



145
146
147
148
# File 'lib/edtf/date.rb', line 145

def unspecified!(arguments = precision_filter)
  unspecified.unspecified!(arguments)
  self
end

#valuesObject

Returns an array of the current year, month, and day values filtered by the Date/Time’s precision.



272
273
274
# File 'lib/edtf/date.rb', line 272

def values
  precision_filter.map { |p| send(p) }
end