diff --git a/lib/tess/rdf/extraction.rb b/lib/tess/rdf/extraction.rb index 18b6253..dc37ace 100644 --- a/lib/tess/rdf/extraction.rb +++ b/lib/tess/rdf/extraction.rb @@ -1,6 +1,8 @@ module Tess module Rdf module Extraction + DURATION_REGEX = /\AP(?:(?\d+)Y)?(?:(?\d+)M)?(?:(?\d+)W)?(?:(?\d+)D)?(?:T(?:(?\d+)H)?(?:(?\d+)M)?(?:(?\d+(?:\.\d+)?)S)?)?\z/ + RDF::Reader # Workaround for https://github.com/ruby-rdf/rdf-rdfa/issues/32 class DummyReader @@ -312,35 +314,34 @@ def parse_value(value) end def modify_date(date, duration) + match = duration.match(DURATION_REGEX) + return date unless match + + d = match.named_captures + d.each do |k, v| + d[k] = if v.nil? + 0 + elsif k == 'seconds' && v.include?('.') + v.to_f + else + v.to_i + end + end + if date.is_a?(String) - date = Date.parse(date) + date = date.include?('T') ? DateTime.parse(date) : Date.parse(date) end - matches = duration.match(/P([^T]+)T?(.*)/) - date_period = matches[1] - - date_period.scan(/(\d+)([YMWD])/).each do |match| - value = match[0].to_i - case match[1] - when 'Y' - date = date >> (12 * value) - when 'M' - date = date >> value - when 'W' - date = date + (7 * value) - when 'D' - date = date + value - end + + # Years/months need to shift by calendar units (via >>), not fixed day counts + date = date >> (d['years'] * 12 + d['months']).to_i + + # Days/weeks/hours/minutes/seconds are fixed durations + total_days = d['weeks'] * 7 + d['days'] + if date.is_a?(DateTime) + date + total_days + Rational(d['hours'], 24) + Rational(d['minutes'], 24 * 60) + Rational(d['seconds'], 86400) + else + date + total_days end - # time_period = matches[2] - # - # time_period.scan(/(\d+)([HMS])/).each do |match| - # case match[1] - # when 'H' - # when 'M' - # when 'S' - # end - # end - date end def markdownify_link(name, url = nil) diff --git a/test/field_test.rb b/test/field_test.rb index fe8074b..56caa02 100644 --- a/test/field_test.rb +++ b/test/field_test.rb @@ -197,6 +197,27 @@ class FieldTest < Test::Unit::TestCase assert_equal '2023-10-02', course_instance_extractor(json).extract_params[:end].to_s end + test 'infer end datetime from start datetime and duration' do + json = %( +[{ + "@context": "https://schema.org/", + "@type": "CourseInstance", + "name": "Advanced Statistics: Statistical Modelling", + "description": "**This course is now full.", + "url": "https://webapp2.vital-it.ch/courseadmin/website/course/20220822_XXXX3", + "@id": "https://webapp2.vital-it.ch/courseadmin/website/course/20220822_XXXX3", + "http://purl.org/dc/terms/conformsTo": { + "@id": "https://bioschemas.org/profiles/CourseInstance/0.8-DRAFT-2020_10_06", + "@type": "CreativeWork" + }, + "keywords": "training,biostatistics,raphael gottardo group", + "location": "Lausanne", + "startDate": "2022-08-22T09:00:00", + "duration": "PT8H" +}]) + assert_equal '2022-08-22T17:00:00+00:00', course_instance_extractor(json).extract_params[:end].to_s + end + test 'extract tools from mentions' do json = %( [{