Class: CocinaDisplay::Dates::Iso8601Format

Inherits:
Date
  • Object
show all
Defined in:
lib/cocina_display/dates/date.rb

Overview

Strict ISO8601-encoded date parser.

Constant Summary

Constants inherited from Date

Date::BCE_CHAR_SORT_MAP, Date::UNPARSABLE_VALUES

Instance Attribute Summary

Attributes inherited from Date

#cocina, #date, #encoding, #type

Class Method Summary collapse

Methods inherited from Date

#<=>, #approximate?, #as_range, #base_value, #decoded_value, #earliest_date, #encoding?, #end?, format_date, from_cocina, #inferred?, #initialize, #known?, #label, #latest_date, notifier, #parsable?, #parsed_date?, #precision, #primary?, #qualified?, #qualified_value, #qualifier, #questionable?, #sort_key, #start?, #to_a, #to_s, #value

Constructor Details

This class inherits a constructor from CocinaDisplay::Dates::Date

Class Method Details

.normalize_to_edtf(value) ⇒ Object



496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/cocina_display/dates/date.rb', line 496

def self.normalize_to_edtf(value)
  # Remove time component if there is one
  value = value.split("T").first if value.include?("T")

  # Datetime without "T" was valid until 2019, but iso8601 gem rejects it.
  # YYYYMMDD is valid but EDTF needs dashes to parse it.
  if /^\d{14}$/.match?(value) || /^\d{8}$/.match?(value)
    "#{value[0..3]}-#{value[4..5]}-#{value[6..7]}"
  else
    super
  end
end

.parse_date(value) ⇒ Object



509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/cocina_display/dates/date.rb', line 509

def self.parse_date(value)
  value = normalize_to_edtf(value)

  # Bail out if ISO8601 gem doesn't validate it
  begin
    date = ISO8601::Date.new(value)
  rescue ISO8601::Errors::UnknownPattern
    notifier&.notify("Invalid date value \"#{value}\" for iso8601 encoding")
    return nil
  end

  case value
  # Calendar dates already match EDTF format
  when /^\d{4}-\d{2}-\d{2}$/, /^\d{4}-\d{2}$/, /^\d{4}$/
    super
  # Weeks with no day become a 7-day range
  when /^\d{4}-W\d{2}$/, /^\d{4}W\d{2}$/
    week_end = date + 6
    ::Date.edtf("#{date}/#{week_end}")
  # Weeks with day become a single day
  when /^\d{4}-W\d{2}-\d$/, /^\d{4}W\d{3}$/
    ::Date.edtf(date.to_s)
  # Ordinal dates become a single day
  when /^\d{4}-\d{3}$/, /^\d{7}$/
    ::Date.edtf(date.to_s)
  else
    notifier&.notify("Unhandled date value \"#{value}\" for iso8601 encoding")
    nil
  end
end