Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions src/main/java/com/hubspot/jinjava/JinjavaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.hubspot.jinjava.interpret.JinjavaInterpreterFactory;
import com.hubspot.jinjava.mode.DefaultExecutionMode;
import com.hubspot.jinjava.mode.ExecutionMode;
import com.hubspot.jinjava.objects.date.CurrentDateTimeProvider;
import com.hubspot.jinjava.objects.date.DateTimeProvider;
import com.hubspot.jinjava.random.RandomNumberGeneratorStrategy;
import com.hubspot.jinjava.tree.parse.DefaultTokenScannerSymbols;
import com.hubspot.jinjava.tree.parse.TokenScannerSymbols;
Expand Down Expand Up @@ -62,6 +64,7 @@ public class JinjavaConfig {
private final int rangeLimit;
private final int maxNumDeferredTokens;
private final InterpreterFactory interpreterFactory;
private final DateTimeProvider dateTimeProvider;
private TokenScannerSymbols tokenScannerSymbols;
private final ELResolver elResolver;
private final ExecutionMode executionMode;
Expand Down Expand Up @@ -121,6 +124,7 @@ private JinjavaConfig(Builder builder) {
elResolver = builder.elResolver;
executionMode = builder.executionMode;
legacyOverrides = builder.legacyOverrides;
dateTimeProvider = builder.dateTimeProvider;
enablePreciseDivideFilter = builder.enablePreciseDivideFilter;
objectMapper = builder.objectMapper;
}
Expand Down Expand Up @@ -241,6 +245,10 @@ public boolean getEnablePreciseDivideFilter() {
return enablePreciseDivideFilter;
}

public DateTimeProvider getDateTimeProvider() {
return dateTimeProvider;
}

public static class Builder {
private Charset charset = StandardCharsets.UTF_8;
private Locale locale = Locale.ENGLISH;
Expand All @@ -258,6 +266,7 @@ public static class Builder {
private boolean nestedInterpretationEnabled = true;
private RandomNumberGeneratorStrategy randomNumberGeneratorStrategy =
RandomNumberGeneratorStrategy.THREAD_LOCAL;
private DateTimeProvider dateTimeProvider = new CurrentDateTimeProvider();
private boolean validationMode = false;
private long maxStringLength = 0;
private int rangeLimit = DEFAULT_RANGE_LIMIT;
Expand Down Expand Up @@ -306,6 +315,11 @@ public Builder withRandomNumberGeneratorStrategy(
return this;
}

public Builder withDateTimeProvider(DateTimeProvider dateTimeProvider) {
this.dateTimeProvider = dateTimeProvider;
return this;
}

public Builder withTrimBlocks(boolean trimBlocks) {
this.trimBlocks = trimBlocks;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ public void addBlock(String name, BlockInfo blockInfo) {
/**
* Creates a new variable scope, extending from the current scope. Allows you to create a nested
* contextual scope which can override variables from higher levels.
*
* <p>
* Should be used in a try/finally context, similar to lock-use patterns:
*
* <p>
* <code>
* interpreter.enterScope();
* try (interpreter.enterScope()) {
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/hubspot/jinjava/lib/fn/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.hubspot.jinjava.interpret.TemplateError;
import com.hubspot.jinjava.mode.ExecutionMode;
import com.hubspot.jinjava.objects.Namespace;
import com.hubspot.jinjava.objects.date.DateTimeProvider;
import com.hubspot.jinjava.objects.date.PyishDate;
import com.hubspot.jinjava.objects.date.StrftimeFormatter;
import com.hubspot.jinjava.tree.Node;
Expand Down Expand Up @@ -245,7 +246,14 @@ public static ZonedDateTime getDateTimeArg(Object var, ZoneId zoneOffset) {
JinjavaInterpreter.getCurrent().getPosition()
);
}
d = ZonedDateTime.now(zoneOffset);
long currentMillis = JinjavaInterpreter
.getCurrentMaybe()
.map(JinjavaInterpreter::getConfig)
.map(JinjavaConfig::getDateTimeProvider)
.map(DateTimeProvider::getCurrentTimeMillis)
.orElse(System.currentTimeMillis());

d = ZonedDateTime.ofInstant(Instant.ofEpochMilli(currentMillis), zoneOffset);
} else if (var instanceof Number) {
d =
ZonedDateTime.ofInstant(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.hubspot.jinjava.objects.date;

public class CurrentDateTimeProvider implements DateTimeProvider {

@Override
public long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.hubspot.jinjava.objects.date;

public interface DateTimeProvider {
long getCurrentTimeMillis();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.hubspot.jinjava.objects.date;

public class FixedDateTimeProvider implements DateTimeProvider {
private long currentTimeMillis;

public FixedDateTimeProvider(long currentTimeMillis) {
this.currentTimeMillis = currentTimeMillis;
}

@Override
public long getCurrentTimeMillis() {
return currentTimeMillis;
}
}
13 changes: 12 additions & 1 deletion src/main/java/com/hubspot/jinjava/objects/date/PyishDate.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hubspot.jinjava.objects.date;

import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.objects.PyWrapper;
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
Expand Down Expand Up @@ -50,7 +51,17 @@ public PyishDate(Long epochMillis) {
this(
ZonedDateTime.ofInstant(
Instant.ofEpochMilli(
Optional.ofNullable(epochMillis).orElseGet(System::currentTimeMillis)
Optional
.ofNullable(epochMillis)
.orElseGet(
() ->
JinjavaInterpreter
.getCurrentMaybe()
.map(JinjavaInterpreter::getConfig)
.map(JinjavaConfig::getDateTimeProvider)
.map(DateTimeProvider::getCurrentTimeMillis)
.orElseGet(System::currentTimeMillis)
)
),
ZoneOffset.UTC
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ public void setup() {
}

@After
public void tearDown() throws Exception {
public void tearDown() {
assertThat(interpreter.getErrorsCopy()).isEmpty();
}

@Test
public void itRendersFromDate() throws Exception {
public void itRendersFromDate() {
assertThat(interpreter.renderFlat("{{ d|unixtimestamp }}")).isEqualTo(timestamp);
}
}
31 changes: 28 additions & 3 deletions src/test/java/com/hubspot/jinjava/lib/fn/TodayFunctionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,48 @@
import com.hubspot.jinjava.interpret.InvalidArgumentException;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.mode.EagerExecutionMode;
import com.hubspot.jinjava.objects.date.FixedDateTimeProvider;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import org.junit.Test;

public class TodayFunctionTest extends BaseInterpretingTest {
private static final String ZONE_NAME = "America/New_York";
private static final ZoneId ZONE_ID = ZoneId.of(ZONE_NAME);

@Test
public void itDefaultsToUtcTimezone() {
ZonedDateTime zonedDateTime = Functions.today();
assertThat(zonedDateTime.getZone()).isEqualTo(ZoneOffset.UTC);
}

@Test
public void itUsesFixedDateTimeProvider() {
long ts = 1233333414223L;

JinjavaInterpreter.pushCurrent(
new JinjavaInterpreter(
new Jinjava(),
new Context(),
JinjavaConfig
.newBuilder()
.withDateTimeProvider(new FixedDateTimeProvider(ts))
.build()
)
);
try {
assertThat(Functions.today(ZONE_NAME))
.isEqualTo(ZonedDateTime.of(2009, 1, 30, 0, 0, 0, 0, ZONE_ID));
} finally {
JinjavaInterpreter.popCurrent();
}
}

@Test
public void itParsesTimezones() {
ZonedDateTime zonedDateTime = Functions.today("America/New_York");
assertThat(zonedDateTime.getZone()).isEqualTo(ZoneId.of("America/New_York"));
ZonedDateTime zonedDateTime = Functions.today(ZONE_NAME);
assertThat(zonedDateTime.getZone()).isEqualTo(ZONE_ID);
}

@Test(expected = InvalidArgumentException.class)
Expand All @@ -52,7 +77,7 @@ public void itDefersWhenExecutingEagerly() {
)
);
try {
Functions.today("America/New_York");
Functions.today(ZONE_NAME);
} finally {
JinjavaInterpreter.popCurrent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.hubspot.jinjava.interpret.DeferredValueException;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.mode.EagerExecutionMode;
import com.hubspot.jinjava.objects.date.FixedDateTimeProvider;
import java.time.ZonedDateTime;
import org.assertj.core.data.Offset;
import org.junit.Test;

public class UnixTimestampFunctionTest {
Expand All @@ -24,14 +26,29 @@ public void itGetsUnixTimestamps() {
.isLessThanOrEqualTo(System.currentTimeMillis());
assertThat(Functions.unixtimestamp(epochMilliseconds)).isEqualTo(epochMilliseconds);
assertThat(Functions.unixtimestamp(d)).isEqualTo(epochMilliseconds);
assertThat(
Math.abs(
Functions.unixtimestamp((Object) null) -
ZonedDateTime.now().toEpochSecond() *
1000
)
assertThat(Functions.unixtimestamp((Object) null))
.isCloseTo(System.currentTimeMillis(), Offset.offset(1000L));
}

@Test
public void itUsesFixedDateTimeProvider() {
long ts = 1233333414223L;

JinjavaInterpreter.pushCurrent(
new JinjavaInterpreter(
new Jinjava(),
new Context(),
JinjavaConfig
.newBuilder()
.withDateTimeProvider(new FixedDateTimeProvider(ts))
.build()
)
.isLessThan(1000);
);
try {
assertThat(Functions.unixtimestamp((Object) null)).isEqualTo(ts);
} finally {
JinjavaInterpreter.popCurrent();
}
}

@Test(expected = DeferredValueException.class)
Expand Down
25 changes: 25 additions & 0 deletions src/test/java/com/hubspot/jinjava/objects/date/PyishDateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import static org.assertj.core.api.Assertions.assertThat;

import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.interpret.Context;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
Expand All @@ -18,6 +21,28 @@ public void itUsesCurrentTimeWhenNoneProvided() {
assertThat(d.toDate()).isCloseTo(new Date(), 10000);
}

@Test
public void itUsesDateTimeProviderWhenNoTimeProvided() {
long ts = 123345414223L;

JinjavaInterpreter.pushCurrent(
new JinjavaInterpreter(
new Jinjava(),
new Context(),
JinjavaConfig
.newBuilder()
.withDateTimeProvider(new FixedDateTimeProvider(ts))
.build()
)
);
try {
PyishDate d = new PyishDate((Long) null);
assertThat(d.toDate()).isEqualTo(Date.from(Instant.ofEpochMilli(ts)));
} finally {
JinjavaInterpreter.popCurrent();
}
}

@Test
public void testStrfmt() {
PyishDate d = new PyishDate(ZonedDateTime.parse("2013-11-12T14:15:00+00:00"));
Expand Down