Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

DATE_FORMAT function #764

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
fb2ed91
Bug fix, support long type for aggregation (#522)
penghuo Jun 17, 2020
254f2e0
Opendistro Release 1.9.0 (#532)
joshuali925 Jun 24, 2020
33c6d3e
Rename release notes to use 4 digit versions (#547)
joshuali925 Jul 6, 2020
09132da
Revert changes ahead of develop branch in master (#551)
joshuali925 Jul 9, 2020
893cd18
Merge develop branch to master (#553)
joshuali925 Jul 9, 2020
923c96d
Merge all SQL repos and adjust workflows (#549) (#554)
joshuali925 Jul 9, 2020
4b33a2f
add date and time support (#560)
penghuo Jul 13, 2020
af74293
Revert "add date and time support (#560)" (#567)
penghuo Jul 13, 2020
baac103
resolve conflict
joshuali925 Jul 29, 2020
35e37a3
Merge develop to master for ODFE 1.9.0.1 release (#633)
joshuali925 Jul 29, 2020
0ed6594
Merge fixes for github release actions from develop to master (#638)
joshuali925 Jul 29, 2020
e4981e3
Fix odbc win32 release workflow for master (#642)
joshuali925 Jul 30, 2020
c11125d
add error details for all server communication errors (#645)
jordanw-bq Jul 31, 2020
34b979e
Revert "add error details for all server communication errors (#645)"…
chloe-zh Aug 4, 2020
5ab1bc8
Merge pull request #698 from opendistro-for-elasticsearch/develop
chloe-zh Aug 20, 2020
8735723
Merge develop branch into master for od1.10 release (#701)
chloe-zh Aug 20, 2020
332ee9c
Merge branch 'develop' of github.com:opendistro-for-elasticsearch/sql
chloe-zh Aug 20, 2020
2939081
Merge workflow fix to master for od1.10 release (#704)
chloe-zh Aug 20, 2020
9e82a91
Fix download link in package description (#729)
gaiksaya Sep 4, 2020
89c6e05
Merge develop to master for ODFE 1.10.1.0 release (#733)
joshuali925 Sep 8, 2020
db82e29
add functions day, month, quarter, year
Sep 9, 2020
e46da70
fix build error
Sep 9, 2020
88a878b
fix doctest error
Sep 9, 2020
63ea788
fix doctest build error
Sep 9, 2020
7551dc8
fix doctest
Sep 9, 2020
a673fe2
add dayofmonth()
Sep 9, 2020
7c70c33
add dayofyear()
Sep 9, 2020
d87f8f4
add dayofweek()
Sep 9, 2020
242403c
fix dayofweek logic & add unit test
Sep 9, 2020
be7051d
fix doctest for dayofweek()
Sep 9, 2020
6834c10
add dayname
Sep 9, 2020
ee02527
add monthname
Sep 10, 2020
8ab2f63
fix checkstyle build error
Sep 10, 2020
458c34a
fix build error
Sep 10, 2020
e42aac1
fix doctest for monthname
Sep 10, 2020
960783b
add hour()
Sep 10, 2020
4d355b2
add minute()
Sep 10, 2020
0881f24
add second
Sep 11, 2020
d199d54
add microsecond
Sep 14, 2020
c88a6dd
fix datetime & timestamp issue for microsecond
Sep 15, 2020
4dd0db0
add time_to_sec
Sep 15, 2020
988d177
add subdate & date_sub
Sep 15, 2020
9c1d96b
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 15, 2020
693211a
fix doctest error
Sep 15, 2020
36449f7
fix build error
Sep 15, 2020
048d5d6
add KeywordsCanBeId for dayofweek
Sep 15, 2020
c0593d9
add to_days
Sep 16, 2020
7ee0dbc
add from_days()
Sep 16, 2020
7764a0d
arrange by alphabetical order
Sep 17, 2020
18a6a84
add manual IT
Sep 17, 2020
7054a4b
add string input for date functions
Sep 17, 2020
7e4c726
fix microsecond
Sep 18, 2020
f0a16ce
update doc
Sep 18, 2020
b757335
add date_add
Sep 18, 2020
a41aaad
add week
Sep 19, 2020
1a44c36
address PR comments
Sep 19, 2020
20acde3
update tests & doc
Sep 23, 2020
a51f2f7
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 23, 2020
42c7222
fix doc format
Sep 23, 2020
0f3894a
update tests for adddate
Sep 23, 2020
a73a8e9
move string conversion to ExprStringValue
Sep 24, 2020
ea9b190
add string type in doc
Sep 24, 2020
7f57158
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 24, 2020
498bdf0
edge case
Sep 24, 2020
61ac4e5
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 24, 2020
365b000
fix case 5 & 7
Sep 24, 2020
7840b12
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 24, 2020
0814004
add IT
Sep 25, 2020
8567662
update doc
Sep 25, 2020
9d51b9c
fix table
Sep 25, 2020
c869ff0
rename
Sep 25, 2020
6d19513
add string type
Sep 25, 2020
5ab8631
nit: add newline
Sep 25, 2020
ce4473b
fix type in comment
Sep 25, 2020
829fa06
Merge branch 'develop' of https://github.com/opendistro-for-elasticse…
lyndonbauto Sep 25, 2020
6dc155c
nit
Sep 28, 2020
dc70cd6
add test cases for datetime function in ExpeStringValue
Sep 28, 2020
d93f02b
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 28, 2020
c001615
removing implicit def for keyword in parser
Sep 29, 2020
104e6b9
add dayofweek
Sep 29, 2020
0f8d8bc
Merge branch 'develop' of https://github.com/opendistro-for-elasticse…
lyndonbauto Sep 29, 2020
6a8434f
Merge branch 'date-time-function-week' of https://github.com/rupal-bq…
lyndonbauto Sep 29, 2020
84a111e
[1] Merged rupals week branch in
lyndonbauto Sep 29, 2020
126890b
Merge branch 'develop' of https://github.com/rupal-bq/sql into date-t…
Sep 29, 2020
38e875d
Merge branch 'date-time-functions' of https://github.com/rupal-bq/sql…
lyndonbauto Sep 29, 2020
c73e430
add unit tests for null, missing values
Sep 29, 2020
4d3eff0
nit
Sep 29, 2020
e573d32
[1] Added integration tests.
lyndonbauto Sep 30, 2020
9e68366
[1] Working on ppl integration tests.
lyndonbauto Sep 30, 2020
e6942e4
[1] Updated for integration tests
lyndonbauto Sep 30, 2020
a57014e
[1] Fixed schema verification
lyndonbauto Sep 30, 2020
18820c6
[1] Adding documentation.
lyndonbauto Sep 30, 2020
e6bdab5
[1] Fixing documentation
lyndonbauto Sep 30, 2020
c72d100
Merge branch 'develop' of https://github.com/opendistro-for-elasticse…
lyndonbauto Sep 30, 2020
568667f
[1] Simplified a bunch of logic
lyndonbauto Sep 30, 2020
cf69bbc
[1] Reducing changes that are from spacing
lyndonbauto Sep 30, 2020
8d41f33
[1] Removed extra merge line
lyndonbauto Sep 30, 2020
76cd45b
address PR comment
Sep 30, 2020
6267a24
[1] Updates
lyndonbauto Sep 30, 2020
e9793f3
no message
lyndonbauto Sep 30, 2020
c9b68db
[1] Pulling develop
lyndonbauto Sep 30, 2020
8ee52f7
[1] Removed some unwanted changes.
lyndonbauto Sep 30, 2020
1656d75
[1] Minor whitespace adjustements
lyndonbauto Sep 30, 2020
21c5fc5
[1] Updating based on code review
lyndonbauto Oct 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeParseException;
import java.util.Objects;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ public FunctionExpression timestamp(Expression... expressions) {
return function(BuiltinFunctionName.TIMESTAMP, expressions);
}

public FunctionExpression date_format(Expression... expressions) {
return function(BuiltinFunctionName.DATE_FORMAT, expressions);
}

public FunctionExpression to_days(Expression... expressions) {
return function(BuiltinFunctionName.TO_DAYS, expressions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ private static Calendar getCalendar(int mode, LocalDate date) {

/**
* Set first day of week, minimal days in first week and date in calendar.
* @param firstDayOfWeek the given first day of the week.
* @param firstDayOfWeek the given first day of the week.
* @param minimalDaysInWeek the given minimal days required in the first week of the year.
* @param date the given date.
* @param date the given date.
*/
private static Calendar getCalendar(int firstDayOfWeek, int minimalDaysInWeek, LocalDate date) {
Calendar calendar = Calendar.getInstance();
Expand All @@ -74,4 +74,19 @@ static int getWeekNumber(int mode, LocalDate date) {
}
return weekNumber;
}
}

/**
* Returns year for date according to mode.
* @param mode Integer for mode. Valid mode values are 0 to 7.
* @param date LocalDate for date.
*/
static int getYearNumber(int mode, LocalDate date) {
Calendar calendar = getCalendar(mode, date);
int weekNumber = getWeekNumber(mode, date);
int yearNumber = calendar.get(Calendar.YEAR);
if ((weekNumber > 51) && (calendar.get(Calendar.DAY_OF_MONTH) < 7)) {
yearNumber--;
}
return yearNumber;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.amazon.opendistroforelasticsearch.sql.expression.datetime;

import com.amazon.opendistroforelasticsearch.sql.data.model.ExprStringValue;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue;
import com.google.common.collect.ImmutableMap;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* This class converts a SQL style DATE_FORMAT format specifier and converts it to a
* Java SimpleDateTime format.
*/
class DateTimeFormatterUtil {
private static final int SUFFIX_SPECIAL_START_TH = 11;
private static final int SUFFIX_SPECIAL_END_TH = 13;
private static final String SUFFIX_SPECIAL_TH = "th";
private static final Map<Integer, String> SUFFIX_CONVERTER =
ImmutableMap.<Integer, String>builder()
.put(1, "st").put(2, "nd").put(3, "rd").build();

// The following have special cases that need handling outside of the format options provided
// by the DateTimeFormatter class.
interface DateTimeFormatHandler {
String getFormat(LocalDateTime date);
}

private static final Map<String, DateTimeFormatHandler> HANDLERS =
ImmutableMap.<String, DateTimeFormatHandler>builder()
.put("%a", (date) -> "EEE") // %a => EEE - Abbreviated weekday name (Sun..Sat)
.put("%b", (date) -> "LLL") // %b => LLL - Abbreviated month name (Jan..Dec)
.put("%c", (date) -> "MM") // %c => MM - Month, numeric (0..12)
.put("%d", (date) -> "dd") // %d => dd - Day of the month, numeric (00..31)
.put("%e", (date) -> "d") // %e => d - Day of the month, numeric (0..31)
.put("%H", (date) -> "HH") // %H => HH - (00..23)
.put("%h", (date) -> "hh") // %h => hh - (01..12)
.put("%I", (date) -> "hh") // %I => hh - (01..12)
.put("%i", (date) -> "mm") // %i => mm - Minutes, numeric (00..59)
.put("%j", (date) -> "DDD") // %j => DDD - (001..366)
.put("%k", (date) -> "H") // %k => H - (0..23)
.put("%l", (date) -> "h") // %l => h - (1..12)
.put("%p", (date) -> "a") // %p => a - AM or PM
.put("%M", (date) -> "LLLL") // %M => LLLL - Month name (January..December)
.put("%m", (date) -> "MM") // %m => MM - Month, numeric (00..12)
.put("%r", (date) -> "hh:mm:ss a") // %r => hh:mm:ss a - hh:mm:ss followed by AM or PM
.put("%S", (date) -> "ss") // %S => ss - Seconds (00..59)
.put("%s", (date) -> "ss") // %s => ss - Seconds (00..59)
.put("%T", (date) -> "HH:mm:ss") // %T => HH:mm:ss
.put("%W", (date) -> "EEEE") // %W => EEEE - Weekday name (Sunday..Saturday)
.put("%Y", (date) -> "yyyy") // %Y => yyyy - Year, numeric, 4 digits
.put("%y", (date) -> "yy") // %y => yy - Year, numeric, 2 digits
// The following are not directly supported by DateTimeFormatter.
.put("%D", (date) -> // %w - Day of month with English suffix
String.format("'%d%s'", date.getDayOfMonth(), getSuffix(date.getDayOfMonth())))
.put("%f", (date) -> // %f - Microseconds
String.format("'%d'", (date.getNano() / 1000)))
.put("%w", (date) -> // %w - Day of week (0 indexed)
String.format("'%d'", date.getDayOfWeek().getValue()))
.put("%U", (date) -> // %U Week where Sunday is the first day - WEEK() mode 0
String.format("'%d'", CalendarLookup.getWeekNumber(0, date.toLocalDate())))
.put("%u", (date) -> // %u Week where Monday is the first day - WEEK() mode 1
String.format("'%d'", CalendarLookup.getWeekNumber(1, date.toLocalDate())))
.put("%V", (date) -> // %V Week where Sunday is the first day - WEEK() mode 2 used with %X
String.format("'%d'", CalendarLookup.getWeekNumber(2, date.toLocalDate())))
.put("%v", (date) -> // %v Week where Monday is the first day - WEEK() mode 3 used with %x
String.format("'%d'", CalendarLookup.getWeekNumber(3, date.toLocalDate())))
.put("%X", (date) -> // %X Year for week where Sunday is the first day, 4 digits used with %V
String.format("'%d'", CalendarLookup.getYearNumber(2, date.toLocalDate())))
.put("%x", (date) -> // %x Year for week where Monday is the first day, 4 digits used with %v
String.format("'%d'", CalendarLookup.getYearNumber(3, date.toLocalDate())))
.build();

private static final Pattern pattern = Pattern.compile("%.");
private static final String MOD_LITERAL = "%";

private DateTimeFormatterUtil() {
}

/**
* Format the date using the date format String.
* @param dateExpr the date ExprValue of Date/Datetime/Timestamp/String type.
* @param formatExpr the format ExprValue of String type.
* @return Date formatted using format and returned as a String.
*/
static ExprValue getFormattedDate(ExprValue dateExpr, ExprValue formatExpr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the use case. Do you try to do something like this format.replace("%\W", () -> replace).
If so, i recommended to consider the https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html#appendReplacement(java.lang.StringBuffer,%20java.lang.String)
which provide the more clean code structure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize I could do this, tahnks for the suggestion! I have updated with this change.

final LocalDateTime date = dateExpr.datetimeValue();
final Matcher matcher = pattern.matcher(formatExpr.stringValue());
final StringBuffer format = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(format,
HANDLERS.getOrDefault(matcher.group(), (d) ->
String.format("'%s'", matcher.group().replaceFirst(MOD_LITERAL, "")))
.getFormat(date));
}
matcher.appendTail(format);

// English Locale matches SQL requirements.
// 'AM'/'PM' instead of 'a.m.'/'p.m.'
// 'Sat' instead of 'Sat.' etc
return new ExprStringValue(date.format(
DateTimeFormatter.ofPattern(format.toString(), Locale.ENGLISH)));
}

/**
* Returns English suffix of incoming value.
* @param val Incoming value.
* @return English suffix as String (st, nd, rd, th)
*/
private static String getSuffix(int val) {
// The numbers 11, 12, and 13 do not follow general suffix rules.
if ((SUFFIX_SPECIAL_START_TH <= val) && (val <= SUFFIX_SPECIAL_END_TH)) {
return SUFFIX_SPECIAL_TH;
}
return SUFFIX_CONVERTER.getOrDefault(val % 10, SUFFIX_SPECIAL_TH);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(time());
repository.register(time_to_sec());
repository.register(timestamp());
repository.register(date_format());
repository.register(to_days());
repository.register(week());
repository.register(year());
Expand Down Expand Up @@ -400,6 +401,27 @@ private FunctionResolver year() {
);
}

/**
* Formats date according to format specifier. First argument is date, second is format.
* Detailed supported signatures:
* (STRING, STRING) -> STRING
* (DATE, STRING) -> STRING
* (DATETIME, STRING) -> STRING
* (TIMESTAMP, STRING) -> STRING
*/
private FunctionResolver date_format() {
return define(BuiltinFunctionName.DATE_FORMAT.getName(),
impl(nullMissingHandling(DateTimeFormatterUtil::getFormattedDate),
STRING, STRING, STRING),
impl(nullMissingHandling(DateTimeFormatterUtil::getFormattedDate),
STRING, DATE, STRING),
impl(nullMissingHandling(DateTimeFormatterUtil::getFormattedDate),
STRING, DATETIME, STRING),
impl(nullMissingHandling(DateTimeFormatterUtil::getFormattedDate),
STRING, TIMESTAMP, STRING)
);
}

/**
* ADDDATE function implementation for ExprValue.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public enum BuiltinFunctionName {
TIME(FunctionName.of("time")),
TIME_TO_SEC(FunctionName.of("time_to_sec")),
TIMESTAMP(FunctionName.of("timestamp")),
DATE_FORMAT(FunctionName.of("date_format")),
TO_DAYS(FunctionName.of("to_days")),
WEEK(FunctionName.of("week")),
YEAR(FunctionName.of("year")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
import com.amazon.opendistroforelasticsearch.sql.expression.ExpressionTestBase;
import com.amazon.opendistroforelasticsearch.sql.expression.FunctionExpression;
import com.amazon.opendistroforelasticsearch.sql.expression.env.Environment;
import com.google.common.collect.ImmutableList;
import java.util.List;
import lombok.AllArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -71,6 +74,89 @@ public void setup() {
when(missingRef.valueOf(env)).thenReturn(missingValue());
}

final List<DateFormatTester> dateFormatTesters = ImmutableList.of(
new DateFormatTester("1998-01-31 13:14:15.012345",
ImmutableList.of("%H","%I","%k","%l","%i","%p","%r","%S","%T"," %M",
"%W","%D","%Y","%y","%a","%b","%j","%m","%d","%h","%s","%w","%f",
"%q","%"),
ImmutableList.of("13","01","13","1","14","PM","01:14:15 PM","15","13:14:15"," January",
"Saturday","31st","1998","98","Sat","Jan","031","01","31","01","15","6","12345",
"q","%")
),
new DateFormatTester("1999-12-01",
ImmutableList.of("%D"),
ImmutableList.of("1st")
),
new DateFormatTester("1999-12-02",
ImmutableList.of("%D"),
ImmutableList.of("2nd")
),
new DateFormatTester("1999-12-03",
ImmutableList.of("%D"),
ImmutableList.of("3rd")
),
new DateFormatTester("1999-12-04",
ImmutableList.of("%D"),
ImmutableList.of("4th")
),
new DateFormatTester("1999-12-11",
ImmutableList.of("%D"),
ImmutableList.of("11th")
),
new DateFormatTester("1999-12-12",
ImmutableList.of("%D"),
ImmutableList.of("12th")
),
new DateFormatTester("1999-12-13",
ImmutableList.of("%D"),
ImmutableList.of("13th")
),
new DateFormatTester("1999-12-31",
ImmutableList.of("%x","%v","%X","%V","%u","%U"),
ImmutableList.of("1999", "52", "1999", "52", "52", "52")
),
new DateFormatTester("2000-01-01",
ImmutableList.of("%x","%v","%X","%V","%u","%U"),
ImmutableList.of("1999", "52", "1999", "52", "0", "0")
),
new DateFormatTester("1998-12-31",
ImmutableList.of("%x","%v","%X","%V","%u","%U"),
ImmutableList.of("1998", "52", "1998", "52", "52", "52")
),
new DateFormatTester("1999-01-01",
ImmutableList.of("%x","%v","%X","%V","%u","%U"),
ImmutableList.of("1998", "52", "1998", "52", "0", "0")
),
new DateFormatTester("2020-01-04",
ImmutableList.of("%x","%X"),
ImmutableList.of("2020", "2019")
),
new DateFormatTester("2008-12-31",
ImmutableList.of("%v","%V","%u","%U"),
ImmutableList.of("53","52","53","52")
)
);

@AllArgsConstructor
private class DateFormatTester {
private final String date;
private final List<String> formatterList;
private final List<String> formattedList;
private static final String DELIMITER = "|";

String getFormatter() {
return String.join(DELIMITER, formatterList);
}

String getFormatted() {
return String.join(DELIMITER, formattedList);
}

FunctionExpression getDateFormatExpression() {
return dsl.date_format(DSL.literal(date), DSL.literal(getFormatter()));
}
}

@Test
public void adddate() {
FunctionExpression expr = dsl.adddate(dsl.date(DSL.literal("2020-08-26")), DSL.literal(7));
Expand Down Expand Up @@ -872,6 +958,48 @@ public void year() {
assertEquals(integerValue(2020), eval(expression));
}

@Test
public void date_format() {
dateFormatTesters.forEach(this::testDateFormat);
String timestamp = "1998-01-31 13:14:15.012345";
String timestampFormat = "%a %b %c %D %d %e %f %H %h %I %i %j %k %l %M "
+ "%m %p %r %S %s %T %% %P";
String timestampFormatted = "Sat Jan 01 31st 31 31 12345 13 01 01 14 031 13 1 "
+ "January 01 PM 01:14:15 PM 15 15 13:14:15 % P";

FunctionExpression expr = dsl.date_format(DSL.literal(timestamp), DSL.literal(timestampFormat));
assertEquals(STRING, expr.type());
assertEquals(timestampFormatted, eval(expr).stringValue());

when(nullRef.type()).thenReturn(DATE);
when(missingRef.type()).thenReturn(DATE);
assertEquals(nullValue(), eval(dsl.date_format(nullRef, DSL.literal(""))));
assertEquals(missingValue(), eval(dsl.date_format(missingRef, DSL.literal(""))));

when(nullRef.type()).thenReturn(DATETIME);
when(missingRef.type()).thenReturn(DATETIME);
assertEquals(nullValue(), eval(dsl.date_format(nullRef, DSL.literal(""))));
assertEquals(missingValue(), eval(dsl.date_format(missingRef, DSL.literal(""))));

when(nullRef.type()).thenReturn(TIMESTAMP);
when(missingRef.type()).thenReturn(TIMESTAMP);
assertEquals(nullValue(), eval(dsl.date_format(nullRef, DSL.literal(""))));
assertEquals(missingValue(), eval(dsl.date_format(missingRef, DSL.literal(""))));

when(nullRef.type()).thenReturn(STRING);
when(missingRef.type()).thenReturn(STRING);
assertEquals(nullValue(), eval(dsl.date_format(nullRef, DSL.literal(""))));
assertEquals(missingValue(), eval(dsl.date_format(missingRef, DSL.literal(""))));
assertEquals(nullValue(), eval(dsl.date_format(DSL.literal(""), nullRef)));
assertEquals(missingValue(), eval(dsl.date_format(DSL.literal(""), missingRef)));
}

void testDateFormat(DateFormatTester dft) {
FunctionExpression expr = dft.getDateFormatExpression();
assertEquals(STRING, expr.type());
assertEquals(dft.getFormatted(), eval(expr).stringValue());
}

private ExprValue eval(Expression expression) {
return expression.valueOf(env);
}
Expand Down
Loading