Module: Ace::Docs::Atoms::TimestampParser

Defined in:
lib/ace/docs/atoms/timestamp_parser.rb

Overview

Pure timestamp parsing and validation functions Supports ISO 8601 UTC and date-only formats

Timezone Behavior:

- ISO 8601 UTC format (YYYY-MM-DDTHH:MM:SSZ) is the recommended format
- Date-only format (YYYY-MM-DD) remains timezone-agnostic

Return Types:

- Date-only strings → Date objects
- ISO 8601 UTC strings → Time objects (in UTC)
This polymorphic return type preserves the precision of the input format.

Constant Summary collapse

DATE_ONLY_PATTERN =

Regular expression patterns for timestamp validation

/^\d{4}-\d{2}-\d{2}$/
ISO8601_UTC_PATTERN =
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/

Class Method Summary collapse

Class Method Details

.format_timestamp(time_obj) ⇒ String

Format a Date or Time object to string

Parameters:

  • time_obj (Date, Time)

    Object to format

Returns:

  • (String)

    Formatted timestamp in ISO 8601 UTC format (for Time) or date-only (for Date)

Raises:

  • (ArgumentError)

    If object is not Date or Time



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ace/docs/atoms/timestamp_parser.rb', line 69

def self.format_timestamp(time_obj)
  raise ArgumentError, "Cannot format nil timestamp" if time_obj.nil?

  case time_obj
  when Date
    time_obj.strftime("%Y-%m-%d")
  when Time
    time_obj.utc.strftime("%Y-%m-%dT%H:%M:%SZ")  # ISO 8601 UTC format
  else
    raise ArgumentError, "Timestamp must be a Date or Time object"
  end
end

.parse_date(date_str) ⇒ Date

Parse date-only string

Parameters:

  • date_str (String)

    Date string in YYYY-MM-DD format

Returns:

  • (Date)

    Parsed date

Raises:

  • (ArgumentError)

    If date is invalid



88
89
90
91
92
# File 'lib/ace/docs/atoms/timestamp_parser.rb', line 88

def self.parse_date(date_str)
  Date.parse(date_str)
rescue Date::Error => e
  raise ArgumentError, "Invalid date: #{e.message}"
end

.parse_iso8601_utc(iso8601_str) ⇒ Time

Parse ISO 8601 UTC datetime string

Parameters:

  • iso8601_str (String)

    ISO 8601 datetime string in YYYY-MM-DDTHH:MM:SSZ format

Returns:

  • (Time)

    Parsed time in UTC

Raises:

  • (ArgumentError)

    If datetime is invalid



98
99
100
101
102
# File 'lib/ace/docs/atoms/timestamp_parser.rb', line 98

def self.parse_iso8601_utc(iso8601_str)
  Time.parse(iso8601_str).utc  # Ensure UTC
rescue ArgumentError => e
  raise ArgumentError, "Invalid ISO 8601 datetime: #{e.message}"
end

.parse_timestamp(value) ⇒ Date, Time

Parse a timestamp string to Date or Time object

Parameters:

  • value (String, Date, Time)

    Timestamp to parse

Returns:

  • (Date, Time)

    Parsed timestamp

Raises:

  • (ArgumentError)

    If format is invalid



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ace/docs/atoms/timestamp_parser.rb', line 29

def self.parse_timestamp(value)
  raise ArgumentError, "Cannot parse nil timestamp" if value.nil?

  # Return already parsed objects as-is
  return value if value.is_a?(Date) || value.is_a?(Time)

  # Must be a string at this point
  raise ArgumentError, "Timestamp must be a String, Date, or Time" unless value.is_a?(String)

  # Validate format before parsing
  unless validate_format(value)
    raise ArgumentError, "Invalid timestamp format. Use YYYY-MM-DDTHH:MM:SSZ (ISO 8601 UTC) or YYYY-MM-DD"
  end

  # Parse based on format
  if value.match?(ISO8601_UTC_PATTERN)
    parse_iso8601_utc(value)
  elsif value.match?(DATE_ONLY_PATTERN)
    parse_date(value)
  else
    raise ArgumentError, "Invalid timestamp format. Use YYYY-MM-DDTHH:MM:SSZ (ISO 8601 UTC) or YYYY-MM-DD"
  end
rescue Date::Error, ArgumentError => e
  # Improve error message for date parsing errors
  raise ArgumentError, "Invalid timestamp: #{e.message}"
end

.validate_format(value) ⇒ Boolean

Validate timestamp format

Parameters:

  • value (String)

    Timestamp string to validate

Returns:

  • (Boolean)

    true if format is valid



59
60
61
62
63
# File 'lib/ace/docs/atoms/timestamp_parser.rb', line 59

def self.validate_format(value)
  return false if value.nil? || !value.is_a?(String) || value.empty?

  value.match?(DATE_ONLY_PATTERN) || value.match?(ISO8601_UTC_PATTERN)
end