Class: CiteProc::Date

Inherits:
Variable show all
Includes:
Attributes
Defined in:
lib/citeproc/date.rb

Overview

Represents a Variable wrapping a date value. A date value is a hybrid object in that it can represent either an atomic date or a date range, depending on whether or not the ‘date-parts’ attribute contains one or two lists of date parts.

Dates can be constructed from a wide range of input values, including Ruby date objects, integers, date ranges, ISO 8601 and CiteProc JSON strings or hashes, and - provided you have the respective gems installed - EDTF strings all strings supported by Chronic.

Date instances are typically manipulated by a cite processor. Therefore, the API is optimized for easy information extraction and formatting. Additionally, Dates can be serialized as CiteProc JSON data.

Examples:

Initialization

CiteProc::Date.new
#-> #<CiteProc::Date "[]">

CiteProc::Date.today
#-> #<CiteProc::Date "[2012, 6, 10]">

CiteProc::Date.new('Yesterday')
#-> #<CiteProc::Date "[[2012, 6, 9]]">

CiteProc::Date.new(1966)
#-> #<CiteProc::Date "[1966]">

CiteProc::Date.new(1999..2003)
#-> #<CiteProc::Date "[[1999], [2003]]">

CiteProc::Date.new(Date.new(1900)...Date.new(2000))
#-> #<CiteProc::Date "[[1900, 1, 1], [1999, 12, 31]]">

CiteProc::Date.new('2009-03?')
#-> #<CiteProc::Date "[[2009, 3]]">

CiteProc::Date.new('2001-02/2007')
#-> #<CiteProc::Date "[[2001, 2, 1], [2007, 12, 31]]">

Serialization

CiteProc::Date.new('2009-03?').to_citeproc
#-> {"date-parts"=>[[2009, 3]], "circa"=>true}

CiteProc::Date.new(1999..2003).to_json
#-> '{"date-parts":[[1999],[2003]]}'

Defined Under Namespace

Classes: DateParts

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Variable

#value

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Attributes

#attribute?, #eql?, #hash, #read_attribute, #reverse_merge, #to_hash, #to_json, #write_attribute

Methods inherited from Variable

create, create!, #inspect, #romanize, #strip_markup, #strip_markup!, #to_f, #to_i, #to_json, #tokenize, #type

Constructor Details

#initialize(value = {}) {|_self| ... } ⇒ Date

Returns a new instance of Date.

Yields:

  • (_self)

Yield Parameters:



286
287
288
289
# File 'lib/citeproc/date.rb', line 286

def initialize(value = {})
  super
  yield self if block_given?
end

Class Attribute Details

.parsersArray (readonly)

A list of available date parsers. Each parser must respond to a #parse method that converts a date string into a Ruby date object. By default, the list will include Ruby’s date parser from the standard library, as well as the parsers of the Chronic and EDTF gems if they are available; to install the latter on your system make sure to ‘gem install chronic edtf`.

Returns:

  • (Array)

    the available date parsers



237
238
239
# File 'lib/citeproc/date.rb', line 237

def parsers
  @parsers
end

Instance Attribute Details

#dayFixnum

Returns the day (of the start date for ranges).

Returns:

  • (Fixnum)

    the day (of the start date for ranges)



380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/citeproc/date.rb', line 380

[:year, :month, :day].each do |reader|
  writer = "#{reader}="

  define_method(reader) do
    d = parts[0] and d.send(reader)
  end

  define_method(writer) do |v|
    parts[0] ||= DateParts.new
    parts[0].send(writer, v.to_i)
  end
end

#monthFixnum

Returns the month (of the start date for ranges).

Returns:

  • (Fixnum)

    the month (of the start date for ranges)



# File 'lib/citeproc/date.rb', line 375

#yearFixnum

Returns the year (of the start date for ranges).

Returns:

  • (Fixnum)

    the year (of the start date for ranges)



# File 'lib/citeproc/date.rb', line 372

Class Method Details

.parse(date_string) ⇒ CiteProc::Date?

Parses the passed-in string with all available date parsers. Creates a new CiteProc Date from the first valid date returned by a parser; returns nil if no parser was able to parse the string successfully.

For an equivalent method that raises an error on invalid input

Parameters:

  • date_string (String)

    the date to be parsed

Returns:

See Also:

  • #parse!


248
249
250
251
252
# File 'lib/citeproc/date.rb', line 248

def parse(date_string)
  parse!(date_string)
rescue ParseError
  nil
end

.parse!(date_string) ⇒ CiteProc::Date

Like #parse but raises a ParseError if the input failed to be parsed.

Parameters:

  • date_string (String)

    the date to be parsed

Returns:

Raises:

  • (ParseError)

    when the string cannot be parsed



260
261
262
263
264
265
266
267
268
# File 'lib/citeproc/date.rb', line 260

def parse!(date_string)
  @parsers.each do |p|
    date = p.parse(date_string) rescue nil
    return new(date) unless date.nil?
  end

  # Subtle: if we get here it means all parsers failed to create a date
  raise ParseError, "failed to parse #{date_string.inspect}"
end

.todayCiteProc::Date Also known as: now

Returns a date object for the current day.

Returns:



271
272
273
# File 'lib/citeproc/date.rb', line 271

def today
  new(::Date.today)
end

Instance Method Details

#-@Date

Returns a copy of the date with an inverted year.

Returns:

  • (Date)

    a copy of the date with an inverted year



394
395
396
397
398
# File 'lib/citeproc/date.rb', line 394

def -@
  d = dup
  d.year = -1 * year
  d
end

#<=>(other) ⇒ Object



516
517
518
519
520
521
522
523
524
525
526
# File 'lib/citeproc/date.rb', line 516

def <=>(other)
  case other
  when CiteProc::Date
    return nil if season? || other.season?
    parts <=> other.parts
  when ::Date
    parts <=> [other]
  else
    nil
  end
end

#ad?Boolean?

A date is said to be AD when it is in the first millennium, i.e., between 1 and 1000 AD

Returns:

  • (Boolean, nil)

    whether or not the date is AD; nil if there is no start date set



486
487
488
# File 'lib/citeproc/date.rb', line 486

def ad?
  date = parts[0] and date.ad?
end

#bc?Boolean?

A date is said to be BC when the year is defined and less than zero.

Returns:

  • (Boolean, nil)

    whether or not the date is BC; nil if there is no start date set



478
479
480
# File 'lib/citeproc/date.rb', line 478

def bc?
  date = parts[0] and date.bc?
end

#certain!self

Marks the date as a certain date

Returns:

  • (self)


461
462
463
464
# File 'lib/citeproc/date.rb', line 461

def certain!
  value[:circa] = false
  self
end

#certain?Boolean

Returns:

  • (Boolean)


466
467
468
# File 'lib/citeproc/date.rb', line 466

def certain?
  !uncertain?
end

#closed_range?Boolean Also known as: closed?

Returns whether or not this date is a closed range.

Returns:

  • (Boolean)

    whether or not this date is a closed range



444
445
446
# File 'lib/citeproc/date.rb', line 444

def closed_range?
  range? && !open_range?
end

#date?true

Returns dates are dates.

Returns:

  • (true)

    dates are dates



368
369
370
# File 'lib/citeproc/date.rb', line 368

def date?
  true
end

#date_partsArray<DateParts> Also known as: parts

Returns:



354
355
356
# File 'lib/citeproc/date.rb', line 354

def date_parts
  value[:'date-parts'] ||= []
end

#empty?Boolean

Returns whether or not the date parts’ are empty and the date is neither literal nor a season.

Returns:

  • (Boolean)

    whether or not the date parts’ are empty and the date is neither literal nor a season



363
364
365
# File 'lib/citeproc/date.rb', line 363

def empty?
  parts.all?(&:empty?) && !literal? && !season?
end

#end_date::Date?

Returns the range’s end date; or nil.

Returns:

  • (::Date, nil)

    the range’s end date; or nil



424
425
426
# File 'lib/citeproc/date.rb', line 424

def end_date
  d = parts[1] and d.to_date
end

#end_date=(date) ⇒ Object



409
410
411
# File 'lib/citeproc/date.rb', line 409

def end_date=(date)
  parts[1] = DateParts.new(date.nil? ? 0 : date.strftime('%Y-%m-%d').split(/-/))
end

#has_end_date?Boolean Also known as: range?, plural?

Returns whether or not the date-parts contain an end date.

Returns:

  • (Boolean)

    whether or not the date-parts contain an end date



429
430
431
# File 'lib/citeproc/date.rb', line 429

def has_end_date?
  parts[1] && !parts[1].empty?
end

#initialize_copy(other) ⇒ Object



291
292
293
# File 'lib/citeproc/date.rb', line 291

def initialize_copy(other)
  @value = other.value.deep_copy
end

#marshal_dumpObject



295
296
297
# File 'lib/citeproc/date.rb', line 295

def marshal_dump
  to_citeproc
end

#marshal_load(value) ⇒ Object



299
300
301
# File 'lib/citeproc/date.rb', line 299

def marshal_load(value)
  replace(value)
end

#merge(other) ⇒ Object



303
304
305
306
# File 'lib/citeproc/date.rb', line 303

def merge(other)
  super
  convert_parts!
end

#numeric?Boolean

Returns false.

Returns:

  • (Boolean)

    false



471
472
473
# File 'lib/citeproc/date.rb', line 471

def numeric?
  false
end

#open_range?Boolean Also known as: open?

Returns whether or not this date is an open range.

Returns:

  • (Boolean)

    whether or not this date is an open range



437
438
439
# File 'lib/citeproc/date.rb', line 437

def open_range?
  range? && parts[1].open?
end

#replace(value) ⇒ Object

Replaces the date’s value. Typically called by the constructor, this method intelligently converts various input values.



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/citeproc/date.rb', line 310

def replace(value)
  case
  when value.is_a?(CiteProc::Date)
    initialize_copy(value)
  when value.is_a?(::Date) && Object.const_defined?(:EDTF)
    @value = { :'date-parts' => [DateParts.new(*value.values)] }
    uncertain! if value.uncertain?
  when value.respond_to?(:strftime)
    @value = { :'date-parts' => [DateParts.new(*value.strftime('%Y-%m-%d').split(/-/))] }
  when value.is_a?(Numeric)
    @value = { :'date-parts' => [DateParts.new(value)] }
  when value.is_a?(Hash)
    attributes = value.symbolize_keys

    if attributes.has_key?(:raw)
      @value = Date.parse(attributes.delete(:raw)).value
      @value.merge!(attributes)
    else
      @value = attributes.deep_copy
    end
    convert_parts!

  when value.is_a?(Array)
    @value = { :'date-parts' => value[0].is_a?(Array) ? value : [value] }
    convert_parts!
  when !value.is_a?(String) && value.respond_to?(:min) && value.respond_to?(:max)
    @value = { :'date-parts' => [
        DateParts.new(value.min),
        DateParts.new(value.max)
      ]}
  when value.is_a?(String) && /^\s*\{/ =~ value
    return replace(::JSON.parse(value, :symbolize_names => true))
  when value.respond_to?(:to_s)
    @value = Date.parse!(value.to_s).value
  else
    raise TypeError, "failed to create date from #{value.inspect}"
  end

  self
end

#start_date::Date?

Returns the date (start date if this instance is a range); or nil.

Returns:

  • (::Date, nil)

    the date (start date if this instance is a range); or nil



401
402
403
# File 'lib/citeproc/date.rb', line 401

def start_date
  d = parts[0] and d.to_date
end

#start_date=(date) ⇒ Object



405
406
407
# File 'lib/citeproc/date.rb', line 405

def start_date=(date)
  parts[0] = DateParts.new(date.strftime('%Y-%m-%d').split(/-/))
end

#to_citeprocHash

Returns a hash representation of the date.

Returns:

  • (Hash)

    a hash representation of the date.



491
492
493
494
495
496
497
498
499
500
501
502
# File 'lib/citeproc/date.rb', line 491

def to_citeproc
  cp = value.stringify_keys

  # Convert (or suppress empty) date-parts
  if parts.all?(&:empty?)
    cp.delete('date-parts')
  else
    cp['date-parts'] = cp['date-parts'].map(&:to_citeproc)
  end

  cp
end

#to_rubyDate, Range

Returns the date as a Ruby date object or as a Range if this instance is closed range.

Returns:

  • (Date, Range)

    the date as a Ruby date object or as a Range if this instance is closed range



415
416
417
418
419
420
421
# File 'lib/citeproc/date.rb', line 415

def to_ruby
  if closed_range?
    start_date..end_date
  else
    start_date
  end
end

#to_sString

Returns the date as a string.

Returns:

  • (String)

    the date as a string



505
506
507
508
509
510
511
512
513
514
# File 'lib/citeproc/date.rb', line 505

def to_s
  case
  when literal?
    literal
  when season?
    season
  else
    parts.map(&:to_citeproc).inspect
  end
end

#uncertain!self

Marks the date as uncertain

Returns:

  • (self)


454
455
456
457
# File 'lib/citeproc/date.rb', line 454

def uncertain!
  value[:circa] = true
  self
end