Skip to content

Commit

Permalink
[Feature #21] Implementation of spif:parseDate
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew-Kulich committed Feb 4, 2022
1 parent 26a90be commit 96eadbe
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package cz.cvut.spipes.exception;

public class ParseException extends RuntimeException {

public ParseException() {
super("Could not parse input string");
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
package cz.cvut.spipes.function.spif;

import cz.cvut.spipes.constants.SPIF;
import cz.cvut.spipes.exception.ParseException;
import cz.cvut.spipes.function.ValueFunction;
import org.apache.jena.datatypes.RDFDatatype;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.expr.NodeValue;
import org.apache.jena.sparql.function.FunctionEnv;
import org.topbraid.spin.arq.AbstractFunction3;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

/**
* Converts a string in a semi-structured format into a xsd:date, xsd:dateTime or xsd:time literal.
* The input string must be in a given template format, e.g. \"dd.MM.yyyy\" for strings such as 4.2.2022."
*/
public class ParseDate extends AbstractFunction3 implements ValueFunction {


private static final String TYPE_IRI = SPIF.getURI() + "parseDate";

@Override
Expand All @@ -21,15 +30,46 @@ public String getTypeURI() {
}

@Override
protected NodeValue exec(Node text, Node pattern, Node patternLanguage, FunctionEnv env) {
public NodeValue exec(Node text, Node pattern, Node patternLanguage, FunctionEnv env) {

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

It would be nice to javadoc this as well and say that patternLanguage is optional.


String textValue = text.getLiteralValue().toString();
String patternValue = pattern.getLiteralValue().toString();
String patternLanguageValue = patternLanguage.getLiteralValue().toString();
Locale locale = new Locale(patternLanguageValue);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(patternValue).withLocale(locale);

try{
LocalDateTime localDateTime = LocalDateTime.parse(textValue,formatter);
return getDateTimeNode(String.valueOf(localDateTime));
}catch(Exception ignored){}

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern.getLiteralValue().toString());
try{
LocalDate localDate = LocalDate.parse(textValue,formatter);
return getDateNode(String.valueOf(localDate));
}catch(Exception ignored){}

LocalDate date
= LocalDate.parse(text.getLiteralValue().toString(), formatter);
try{
LocalTime localTime = LocalTime.parse(textValue,formatter);
return getTimeNode(String.valueOf(localTime));
}catch(Exception e){
throw new ParseException();
}
}

private NodeValue getDateNode(String date){
return getNode(date, XSDDatatype.XSDdate);
}
private NodeValue getTimeNode(String date){
return getNode(date, XSDDatatype.XSDtime);
}
private NodeValue getDateTimeNode(String date){return getNode(date, XSDDatatype.XSDdateTime);}

return null;
private NodeValue getNode(String date,XSDDatatype type) {
return NodeValue.makeNode(
date,
null,
((RDFDatatype) type).getURI()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package cz.cvut.spipes.function.date;

import cz.cvut.spipes.exception.ParseException;
import cz.cvut.spipes.function.spif.ParseDate;
import org.apache.jena.datatypes.RDFDatatype;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.expr.NodeValue;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import org.junit.rules.ExpectedException;

import static org.apache.jena.graph.NodeFactory.createLiteral;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class ParseDateTest {

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

could we have test where patternLanguage is null as well ? We should definitely support it.


@Rule
public final ExpectedException exception = ExpectedException.none();

@Test
public void execReturnsDate_ItalianLocale() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("02.11.2021");
Node pattern = createLiteral("dd.MM.yyyy");
Node patternLanguage = createLiteral("de");

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

do not know why there is "de" ..

This comment has been minimized.

Copy link
@blcham

blcham Feb 7, 2022

Contributor

@Matthew-Kulich wrote: ""de" stands for Germany."

🤣 🤣 🤣

I meant method is called "execReturnsDate_ItalianLocale", so that is why i do not understand why you use "de". Should not be "it" ? :)

This comment has been minimized.

Copy link
@Matthew-Kulich

Matthew-Kulich Feb 8, 2022

Author Collaborator

Oh, my bad 😆 😆 I overlooked it


NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);
NodeValue expectedDate = getDateNode("2021-11-02");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsDate_EnglishLocale() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("2010-09-21");
Node pattern = createLiteral("yyyy-MM-dd");
Node patternLanguage = createLiteral("de");

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

do not know why there is "de"


NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);
NodeValue expectedDate = getDateNode("2010-09-21");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsDate_FrenchLocale() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("19/12/2016");
Node pattern = createLiteral("dd/MM/yyyy");
Node patternLanguage = createLiteral("de");

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

do not know why there is "de"

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

If there is "de" and it works ... what is the purpose of having it anyway ?

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

So do you know of any useful example of when patternLanguage makes sense ?

This comment has been minimized.

Copy link
@blcham

blcham Feb 7, 2022

Contributor

@Matthew-Kulich wrote:

In this state It is useless, but i can think of one usecase which would be useful. It is that user give us pattern or pattern > language because thereafter we can decide which pattern it is. [Date formats based on country]>(https://docs.oracle.com/cd/E19455-01/806-0169/overview-7/index.html)

So if it makes sense i would put it into one test but not put it to all tests if for them it is not relevant.

This comment has been minimized.

Copy link
@blcham

blcham Feb 7, 2022

Contributor

So to summarize, i just want to say that tests are at least miss-leading :

  • If method is saying execReturnsDate_FrenchLocale, why it does not return an error if "de" is used instead of "fr".
  • if "de" is irrelevant for the test why do we have it ? (it is little confusing and gives an expression that test was written incorrectly)

This comment has been minimized.

Copy link
@Matthew-Kulich

Matthew-Kulich Feb 8, 2022

Author Collaborator
  • It is my mistake with bad locale. It should have been "fr" for sure.

  • I thought that Date somehow checks if the locale corresponds with the pattern but i was wrong.


NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);
NodeValue expectedDate = getDateNode("2016-12-19");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsTimeWithSeconds() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("09:10:10");
Node pattern = createLiteral("k:m:s");
Node patternLanguage = createLiteral("de");
NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);

NodeValue expectedDate = getTimeNode("09:10:10");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsTimeWithoutSeconds() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("23:59");
Node pattern = createLiteral("k:m");
Node patternLanguage = createLiteral("de");
NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);

NodeValue expectedDate = getTimeNode("23:59");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsDateTime() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("2001.07.04 12:08:56");
Node pattern = createLiteral("yyyy.MM.dd HH:mm:ss");
Node patternLanguage = createLiteral("en");
NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);

NodeValue expectedDate = getDateTimeNode("2001-07-04T12:08:56");
assertEquals(expectedDate, returnedDate);
}

@Test
public void execReturnsDateTxime() {

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

Txime ?

This comment has been minimized.

Copy link
@blcham

blcham Feb 7, 2022

Contributor

@Matthew-Kulich here it is :)

public void execReturnsDateTxime() {

This comment has been minimized.

Copy link
@Matthew-Kulich

Matthew-Kulich Feb 8, 2022

Author Collaborator

I see, thanks.

ParseDate parseDate = new ParseDate();
Node text = createLiteral("2001.07.04 AD 12:08:56 PDT");
Node pattern = createLiteral("yyyy.MM.dd G HH:mm:ss z");
Node patternLanguage = createLiteral("dxxxe");

This comment has been minimized.

Copy link
@blcham

blcham Feb 5, 2022

Contributor

what is this language ?

This comment has been minimized.

Copy link
@blcham

blcham Feb 7, 2022

Contributor
NodeValue returnedDate = parseDate.exec(text, pattern, patternLanguage, null);

NodeValue expectedDate = getDateTimeNode("2001-07-04T12:08:56");
assertEquals(expectedDate, returnedDate);
}


@Test
public void execThrowsException_badInput() {
ParseDate parseDate = new ParseDate();
Node text = createLiteral("2001.07.04 12:08:56exception");
Node pattern = createLiteral("yyyy.MM.dd HH:mm:ss");
Node patternLanguage = createLiteral("de");

assertThrows(ParseException.class, () -> parseDate.exec(text, pattern, patternLanguage, null));
}

private NodeValue getDateNode(String date){
return getNode(date, XSDDatatype.XSDdate);
}
private NodeValue getTimeNode(String time){
return getNode(time, XSDDatatype.XSDtime);
}
private NodeValue getDateTimeNode(String dateTime){
return getNode(dateTime, XSDDatatype.XSDdateTime);
}

private NodeValue getNode(String text, XSDDatatype type) {
return NodeValue.makeNode(
text,
null,
((RDFDatatype) type).getURI()
);
}
}

0 comments on commit 96eadbe

Please sign in to comment.