class CiteProc::Date

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.

{Date 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.

@example 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]]">

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

@example 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]]}'

Constants

DateParts

Represents the individual parts of a date (i.e., year, month, day). There is a sublte difference between CiteProc dates (and date parts) and regular Ruby dates, because a Ruby date will always contain valid year, month and date values, whereas CiteProc dates may leave the month and day parts empty. That is to say, CiteProc distinguishes between the first of May 1955 and the month of May 1955 - a distinction that is not supported by regular Ruby dates.

may_1955 = CiteProc::Date::DateParts.new(1955, 5)
first_of_may_1955 = CiteProc::Date::DateParts.new(1955, 5, 1)

may_1955 < first_of_may_1955
#-> true

Date.new(1955, 5) < Date.new(1955, 5, 1)
#-> false

The above example shows that a month's sort order is less than a day in that month, whereas, with Ruby date's there is no such distinction.

The {DateParts} class encapsulates the year, month and day parts of a date; it is used internally by {Date} variables and not supposed to be used in an external context.

Attributes

parsers[R]

@!attribute [r] parsers

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`.

@return [Array] the available date parsers

Public Class Methods

new(value = {}) { |self| ... } click to toggle source
Calls superclass method
# File lib/citeproc/date.rb, line 286
def initialize(value = {})
  super
  yield self if block_given?
end
now()
Alias for: today
parse(date_string) click to toggle source

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 @see parse!

@param date_string [String] the date to be parsed @return [CiteProc::Date,nil] the parsed date or nil

# File lib/citeproc/date.rb, line 248
def parse(date_string)
  parse!(date_string)
rescue ParseError
  nil
end
parse!(date_string) click to toggle source

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

@param date_string [String] the date to be parsed @return [CiteProc::Date] the parsed date

@raise [ParseError] when the string cannot be parsed

# 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
today() click to toggle source

@return [CiteProc::Date] a date object for the current day

# File lib/citeproc/date.rb, line 271
def today
  new(::Date.today)
end
Also aliased as: now

Public Instance Methods

-@() click to toggle source

@return [Date] a copy of the date with an inverted year

# File lib/citeproc/date.rb, line 394
def -@
  d = dup
  d.year = -1 * year
  d
end
<=>(other) click to toggle source
# 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?() click to toggle source

A date is said to be AD when it is in the first millennium, i.e., between 1 and 1000 AD @return [Boolean, nil] whether or not the date is AD; nil if there is

no start date set
# File lib/citeproc/date.rb, line 486
def ad?
  date = parts[0] and date.ad?
end
bc?() click to toggle source

A date is said to be BC when the year is defined and less than zero. @return [Boolean, nil] whether or not the date is BC; nil if there is

no start date set
# File lib/citeproc/date.rb, line 478
def bc?
  date = parts[0] and date.bc?
end
certain!() click to toggle source

Marks the date as a certain date @return [self]

# File lib/citeproc/date.rb, line 461
def certain!
  value[:circa] = false
  self
end
certain?() click to toggle source
# File lib/citeproc/date.rb, line 466
def certain?
  !uncertain?
end
closed?()
Alias for: closed_range?
closed_range?() click to toggle source

@return [Boolean] whether or not this date is a closed range

# File lib/citeproc/date.rb, line 444
def closed_range?
  range? && !open_range?
end
Also aliased as: closed?
date?() click to toggle source

@return [true] dates are dates

# File lib/citeproc/date.rb, line 368
def date?
  true
end
date_parts() click to toggle source

@return [Array<DateParts>]

# File lib/citeproc/date.rb, line 354
def date_parts
  value[:'date-parts'] ||= []
end
Also aliased as: parts
empty?() click to toggle source

@return [Boolean] whether or not the date parts' are empty and the

date is neither literal nor a season
# File lib/citeproc/date.rb, line 363
def empty?
  parts.all?(&:empty?) && !literal? && !season?
end
end_date() click to toggle source

@return [::Date,nil] the range's end date; or nil

# File lib/citeproc/date.rb, line 424
def end_date
  d = parts[1] and d.to_date
end
end_date=(date) click to toggle source
# 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?() click to toggle source

@return [Boolean] whether or not the date-parts contain an end date

# File lib/citeproc/date.rb, line 429
def has_end_date?
  parts[1] && !parts[1].empty?
end
Also aliased as: range?, plural?
initialize_copy(other) click to toggle source
# File lib/citeproc/date.rb, line 291
def initialize_copy(other)
  @value = other.value.deep_copy
end
marshal_dump() click to toggle source
# File lib/citeproc/date.rb, line 295
def marshal_dump
  to_citeproc
end
marshal_load(value) click to toggle source
# File lib/citeproc/date.rb, line 299
def marshal_load(value)
  replace(value)
end
merge(other) click to toggle source
Calls superclass method CiteProc::Attributes#merge
# File lib/citeproc/date.rb, line 303
def merge(other)
  super
  convert_parts!
end
numeric?() click to toggle source

@return false

# File lib/citeproc/date.rb, line 471
def numeric?
  false
end
open?()
Alias for: open_range?
open_range?() click to toggle source

@return [Boolean] whether or not this date is an open range

# File lib/citeproc/date.rb, line 437
def open_range?
  range? && parts[1].open?
end
Also aliased as: open?
parts()
Alias for: date_parts
plural?()
Alias for: has_end_date?
range?()
Alias for: has_end_date?
replace(value) click to toggle source

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

# 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() click to toggle source

@return [::Date,nil] the date (start date if this instance is a range); or nil

# File lib/citeproc/date.rb, line 401
def start_date
  d = parts[0] and d.to_date
end
start_date=(date) click to toggle source
# File lib/citeproc/date.rb, line 405
def start_date=(date)
  parts[0] = DateParts.new(date.strftime('%Y-%m-%d').split(/-/))
end
to_citeproc() click to toggle source

@return [Hash] a hash representation of the date.

# 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_ruby() click to toggle source

@return [Date,Range] the date as a Ruby date object or as a Range if

this instance is closed range
# File lib/citeproc/date.rb, line 415
def to_ruby
  if closed_range?
    start_date..end_date
  else
    start_date
  end
end
to_s() click to toggle source

@return [String] the date as a string

# 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!() click to toggle source

Marks the date as uncertain @return [self]

# File lib/citeproc/date.rb, line 454
def uncertain!
  value[:circa] = true
  self
end

Private Instance Methods

convert_parts!() click to toggle source
# File lib/citeproc/date.rb, line 530
def convert_parts!
  parts.map! do |part|
    part.is_a?(DateParts) ? part : DateParts.new(*part)
  end

  self
end