Repository: PebbleTemplates/pebble
Pull request #251 (2017-02-03 17:14:06)

implemented Java8 Date API support on date filter
added LocalDate, LocalTime, LocalDateTime and ZonedDateTime support for date filter. added fallback to ISO_DATE_TIME pattern, if no pattern was defined. an exception will be thrown, if the pattern can not applied to date object. example LocalTime object with a time pattern.


Patch:
diff --git a/src/main/java/com/mitchellbosecke/pebble/extension/core/DateFilter.java b/src/main/java/com/mitchellbosecke/pebble/extension/core/DateFilter.java
index e7dc3f4a..d940788e 100644
--- a/src/main/java/com/mitchellbosecke/pebble/extension/core/DateFilter.java
+++ b/src/main/java/com/mitchellbosecke/pebble/extension/core/DateFilter.java
@@ -17,6 +17,10 @@ import com.mitchellbosecke.pebble.template.PebbleTemplate;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
 import java.util.*;
 
 public class DateFilter implements Filter {
@@ -38,27 +42,46 @@ public class DateFilter implements Filter {
         if (input == null) {
             return null;
         }
-        Date date = null;
+        final Locale locale = context.getLocale();
+        final String format = (String) args.get("format");
+
+        if(TemporalAccessor.class.isAssignableFrom(input.getClass())) {
+            return applyTemporal((TemporalAccessor)input, self, locale, lineNumber, format);
+        }
+        return applyDate(input, self, locale, lineNumber, format, (String) args.get("existingFormat"));
+     }
 
+    private Object applyDate(Object dateOrString, final PebbleTemplate self, final Locale locale,
+        int lineNumber, final String format, final String existingFormatString) throws PebbleException {
+        Date date = null;
         DateFormat existingFormat = null;
         DateFormat intendedFormat = null;
-
-        Locale locale = context.getLocale();
-
-        intendedFormat = new SimpleDateFormat((String) args.get("format"), locale);
-
-        if (args.get("existingFormat") != null) {
-            existingFormat = new SimpleDateFormat((String) args.get("existingFormat"), locale);
+        if (existingFormatString != null) {
+            existingFormat = new SimpleDateFormat(existingFormatString, locale);
             try {
-                date = existingFormat.parse(input.toString());
+                date = existingFormat.parse(dateOrString.toString());
             } catch (ParseException e) {
                 throw new PebbleException(e, String.format("Could not parse the string '%1' into a date.",
-                        input.toString()), lineNumber, self.getName());
+                    dateOrString.toString()), lineNumber, self.getName());
             }
         } else {
-            date = (Date) input;
+            date = (Date) dateOrString;
         }
-
+        intendedFormat = new SimpleDateFormat(format, locale);
         return new SafeString(intendedFormat.format(date));
     }
+
+    private Object applyTemporal(final TemporalAccessor input, PebbleTemplate self, final Locale locale,
+        int lineNumber, final String format) throws PebbleException {
+        final DateTimeFormatter formatter = format != null
+            ? DateTimeFormatter.ofPattern(format, locale)
+            : DateTimeFormatter.ISO_DATE_TIME;
+        try {
+            return new SafeString(formatter.format(input));
+        } catch (DateTimeException dte) {
+            throw new PebbleException(dte, String.format("Could not parse the string '%1' into a date.",
+                input.toString()), lineNumber, self.getName());
+        }
+    }
+
 }


Test patch:
diff --git a/src/test/java/com/mitchellbosecke/pebble/CoreFiltersTest.java b/src/test/java/com/mitchellbosecke/pebble/CoreFiltersTest.java
index 2a631f0c..1647a9d5 100755
--- a/src/test/java/com/mitchellbosecke/pebble/CoreFiltersTest.java
+++ b/src/test/java/com/mitchellbosecke/pebble/CoreFiltersTest.java
@@ -22,6 +22,11 @@ import java.io.Writer;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.*;
 
 import static org.junit.Assert.assertEquals;
@@ -122,6 +127,42 @@ public class CoreFiltersTest extends AbstractTest {
         assertEquals("07/01/20122012-July-12012/July/1", writer.toString());
     }
 
+    @Test
+    public void testDateJava8() throws ParseException, PebbleException, IOException
+    {
+        PebbleEngine pebble = new PebbleEngine
+            .Builder()
+            .loader(new StringLoader())
+            .strictVariables(false)
+            .defaultLocale(Locale.ENGLISH)
+            .build();
+
+        final LocalDateTime localDateTime = LocalDateTime.of(2017, 6, 30, 13, 30, 35, 0);
+        final ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("GMT+0100"));
+        final LocalDate localDate = localDateTime.toLocalDate();
+        final LocalTime localTime = localDateTime.toLocalTime();
+
+        StringBuilder source = new StringBuilder();
+        source
+            .append("{{ localDateTime | date }}")
+            .append("{{ localDateTime | date('yyyy-MM-dd HH:mm:ss') }}")
+            .append("{{ zonedDateTime | date('yyyy-MM-dd HH:mm:ssXXX') }}")
+            .append("{{ localDate | date('yyyy-MM-dd') }}")
+            .append("{{ localTime | date('HH:mm:ss') }}");
+
+        PebbleTemplate template = pebble.getTemplate(source.toString());
+        Map<String, Object> context = new HashMap<>();
+        context.put("localDateTime", localDateTime);
+        context.put("zonedDateTime", zonedDateTime);
+        context.put("localDate", localDate);
+        context.put("localTime", localTime);
+
+        Writer writer = new StringWriter();
+        template.evaluate(writer, context);
+        assertEquals("2017-06-30T13:30:352017-06-30 13:30:352017-06-30 13:30:35+01:002017-06-3013:30:35", writer.toString());
+    }
+
+
     @Test
     public void testDateWithNamedArguments() throws ParseException, PebbleException, IOException {
         PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false)