Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

METRON-1816: Date format Stellar function #1233

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions metron-stellar/stellar-common/README.md
Expand Up @@ -169,6 +169,7 @@ Where:
| [ `CHOP`](#chop) |
| [ `CHOMP`](#chomp) |
| [ `COUNT_MATCHES`](#count_matches) |
| [ `DATE_FORMAT`](#date_format)
| [ `DAY_OF_MONTH`](#day_of_month) |
| [ `DAY_OF_WEEK`](#day_of_week) |
| [ `DAY_OF_YEAR`](#day_of_year) |
Expand Down Expand Up @@ -379,6 +380,14 @@ Where:
* substring/character - the substring or character to count, may be null.
* Returns: the number of non-overlapping occurrences, 0 if either CharSequence is null.

### `DATE_FORMAT`
* Description: Takes an epoch timestamp and converts it to a date format.
* Input:
* format - DateTime format as a String.
* timestampField - Optional epoch time in Long format. Defaults to now.
* timezone - Optional timezone in String format.
* Returns: Formatted date.

### `DAY_OF_MONTH`
* Description: The numbered day within the month. The first day within the month has a value of 1.
* Input:
Expand Down
Expand Up @@ -28,6 +28,7 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.TimeZone;
Expand Down Expand Up @@ -109,6 +110,13 @@ public static long getEpochTime(String date, String format, Optional<String> tim
return sdf.parse(date).getTime();
}

public static String getDateFormat(String format, Optional<Long> epochTime, Optional<String> timezone) {
Long time = epochTime.orElseGet(System::currentTimeMillis);
TimezonedFormat fmt = timezone.map(s -> new TimezonedFormat(format, s)).orElseGet(() -> new TimezonedFormat(format));
SimpleDateFormat sdf = formatCache.get(fmt).get();
Copy link
Contributor

Choose a reason for hiding this comment

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

are there any errors we need to wrap here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are no exceptions thrown by any calls in this method. What are you thinking we should do?

return sdf.format(new Date(time));
}


/**
* Stellar Function: TO_EPOCH_TIMESTAMP
Expand Down Expand Up @@ -144,6 +152,40 @@ public Object apply(List<Object> objects) {
}
}

@Stellar( name="DATE_FORMAT",
description = "Takes an epoch timestamp and converts it to a date format.",
params = {"format - DateTime format as a String."
, "timestampField - Optional epoch time in Long format. Defaults to now."
, "timezone - Optional timezone in String format."},
returns="Formatted date."
)
public static class DateFormat extends BaseStellarFunction {

public Object apply(List<Object> objects) {
int size = objects.size();
Optional<Object> formatObj = Optional.ofNullable(objects.get(0));
Optional<Long> epochObj = Optional.empty();
Optional<String> tzObj = Optional.empty();
if (size > 1) {
if (size == 2) {
if (objects.get(1) == null) {
return null;
}
epochObj = objects.get(1) instanceof Long ? Optional.of((Long) objects.get(1)) : Optional.empty();
tzObj = objects.get(1) instanceof String ? Optional.of((String) objects.get(1)) : Optional.empty();
} else {
epochObj = Optional.ofNullable((Long) objects.get(1));
tzObj = Optional.ofNullable((String) objects.get(2));
}
}
if(formatObj.isPresent()) {
return getDateFormat(formatObj.get().toString(), epochObj, tzObj);
} else {
return null;
}
}
}

/**
* Gets the value from a list of arguments.
*
Expand Down
Expand Up @@ -31,6 +31,7 @@
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -225,4 +226,36 @@ public void testDayOfYearNow() {
public void testDayOfYearNull() {
Object result = run("DAY_OF_YEAR(nada)");
}

@Test
public void testDateFormat() {
Object result = run("DATE_FORMAT('EEE MMM dd yyyy hh:mm:ss zzz', epoch, 'EST')");
assertEquals("Thu Aug 25 2016 08:27:10 EST", result);
}

@Test
public void testDateFormatDefault() {
Object result = run("DATE_FORMAT('EEE MMM dd yyyy hh:mm:ss zzzz')");
assertTrue(result.toString().endsWith(TimeZone.getDefault().getDisplayName(true, 1)));
}

@Test
public void testDateFormatNow() {
Object result = run("DATE_FORMAT('EEE MMM dd yyyy hh:mm:ss zzz', 'GMT')");
assertTrue(result.toString().endsWith("GMT"));
}

@Test
public void testDateFormatDefaultTimezone() {
Object result = run("DATE_FORMAT('EEE MMM dd yyyy hh:mm:ss zzzz', epoch)");
assertTrue(result.toString().endsWith(TimeZone.getDefault().getDisplayName(true, 1)));
}

/**
* If refer to variable that does not exist, expect ParseException.
*/
@Test(expected = ParseException.class)
public void testDateFormatNull() {
Object result = run("DATE_FORMAT('EEE MMM dd yyyy hh:mm:ss zzz', nada, 'EST')");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we have a test for an invalid format

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}