Skip to content

Commit

Permalink
Add function and filter to convert string to date (#608)
Browse files Browse the repository at this point in the history
* Add strtodate function and filter

* Register function, add tests

* Add jinjava doc

* prettier

* convert to string

Co-authored-by: Liam Harwood <[email protected]>
  • Loading branch information
liamrharwood and lh-hubs-test authored Mar 4, 2021
1 parent 0578ea9 commit 7cc0e6b
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ protected void registerDefaults() {
MinusTimeFilter.class,
BetweenTimesFilter.class,
StringToTimeFilter.class,
StringToDateFilter.class,
UnionFilter.class,
IntersectFilter.class,
DifferenceFilter.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.hubspot.jinjava.lib.filter;

import com.hubspot.jinjava.doc.annotations.JinjavaDoc;
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
import com.hubspot.jinjava.doc.annotations.JinjavaSnippet;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.interpret.TemplateSyntaxException;
import com.hubspot.jinjava.lib.fn.Functions;

@JinjavaDoc(
value = "Converts a date string and date format to a date object",
input = @JinjavaParam(value = "dateString", desc = "Date string", required = true),
params = {
@JinjavaParam(
value = "dateFormat",
desc = "Format of the date string",
required = true
)
},
snippets = { @JinjavaSnippet(code = "{{ '3/3/21'|strtodate('M/d/yy') }}") }
)
public class StringToDateFilter implements Filter {

@Override
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
if (args.length < 1) {
throw new TemplateSyntaxException(
interpreter,
getName(),
"requires 1 argument (date format string)"
);
}

if (var == null) {
return null;
}

if (!(var instanceof String)) {
var = String.valueOf(var);
}

return Functions.stringToDate((String) var, args[0]);
}

@Override
public String getName() {
return "strtodate";
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/hubspot/jinjava/lib/fn/FunctionLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ protected void registerDefaults() {
String.class
)
);
register(
new ELFunctionDefinition(
"",
"strtodate",
Functions.class,
Functions.STRING_TO_DATE_FUNCTION,
String.class,
String.class
)
);

register(new ELFunctionDefinition("", "super", Functions.class, "renderSuperBlock"));

Expand Down
52 changes: 52 additions & 0 deletions src/main/java/com/hubspot/jinjava/lib/fn/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.hubspot.jinjava.util.LengthLimitingStringBuilder;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
Expand All @@ -31,6 +32,7 @@

public class Functions {
public static final String STRING_TO_TIME_FUNCTION = "stringToTime";
public static final String STRING_TO_DATE_FUNCTION = "stringToDate";

public static final int RANGE_LIMIT = 1000;

Expand Down Expand Up @@ -241,6 +243,56 @@ public static PyishDate stringToTime(String datetimeString, String datetimeForma
}
}

@JinjavaDoc(
value = "converts a string and date format into a date object",
params = {
@JinjavaParam(value = "dateString", type = "string", desc = "date as string"),
@JinjavaParam(
value = "dateFormat",
type = "string",
desc = "format of the date string"
)
}
)
public static PyishDate stringToDate(String dateString, String dateFormat) {
if (dateString == null) {
return null;
}

if (dateFormat == null) {
throw new InterpretException(
String.format("%s() requires non-null date format", STRING_TO_DATE_FUNCTION)
);
}

try {
String convertedFormat = StrftimeFormatter.toJavaDateTimeFormat(dateFormat);
return new PyishDate(
LocalDate
.parse(dateString, DateTimeFormatter.ofPattern(convertedFormat))
.atTime(0, 0)
.toInstant(ZoneOffset.UTC)
);
} catch (DateTimeParseException e) {
throw new InterpretException(
String.format(
"%s() could not match date input %s with date format %s",
STRING_TO_DATE_FUNCTION,
dateString,
dateFormat
)
);
} catch (IllegalArgumentException e) {
throw new InterpretException(
String.format(
"%s() requires valid date format, was %s",
STRING_TO_DATE_FUNCTION,
dateFormat
)
);
}
}

private static final int DEFAULT_TRUNCATE_LENGTH = 255;
private static final String DEFAULT_END = "...";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.hubspot.jinjava.lib.fn;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.hubspot.jinjava.interpret.InterpretException;
import com.hubspot.jinjava.objects.date.PyishDate;
import java.time.LocalDate;
import java.time.ZoneOffset;
import org.junit.Test;

public class StringToDateFunctionTest {

@Test
public void itConvertsStringToDate() {
String dateString = "3/4/21";
String format = "M/d/yy";
PyishDate expected = new PyishDate(
LocalDate.of(2021, 3, 4).atTime(0, 0).toInstant(ZoneOffset.UTC)
);
assertThat(Functions.stringToDate(dateString, format)).isEqualTo(expected);
}

@Test
public void itFailsOnInvalidFormat() {
String dateString = "3/4/21";
String format = "blah blah";

assertThatThrownBy(() -> Functions.stringToDate(dateString, format))
.isInstanceOf(InterpretException.class);
}

@Test
public void itFailsOnTimeFormatMismatch() {
String dateString = "3/4/21";
String format = "M/d/yyyy";

assertThatThrownBy(() -> Functions.stringToDate(dateString, format))
.isInstanceOf(InterpretException.class);
}

@Test
public void itFailsOnNullDatetimeFormat() {
String dateString = "3/4/21";
String format = null;

assertThatThrownBy(() -> Functions.stringToDate(dateString, format))
.isInstanceOf(InterpretException.class);
}
}

0 comments on commit 7cc0e6b

Please sign in to comment.