You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/07/13 11:22:19 UTC
[isis] branch master updated: ISIS-3049: value-semantics: fixes time-zone parsing
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new eb825ca277 ISIS-3049: value-semantics: fixes time-zone parsing
eb825ca277 is described below
commit eb825ca2778a792c46eca90bb4993c2e1b7ba913
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jul 13 13:22:10 2022 +0200
ISIS-3049: value-semantics: fixes time-zone parsing
---
.../value/semantics/TemporalValueSemantics.java | 34 ++++++++++--
.../isis/commons/internal/base/_Strings.java | 26 +++++++++
.../isis/commons/internal/base/StringsTest.java | 63 ++++++++++++----------
.../temporal/TemporalValueSemanticsProvider.java | 2 +-
.../isis/testdomain/value/ValueSemanticsTest.java | 27 +++++++++-
.../scalars/datepicker/DateTimeConfig.java | 5 +-
6 files changed, 123 insertions(+), 34 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/TemporalValueSemantics.java b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/TemporalValueSemantics.java
index 07e817a778..dec2c29529 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/semantics/TemporalValueSemantics.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/semantics/TemporalValueSemantics.java
@@ -166,9 +166,29 @@ extends
/**
* The locale-independent (canonical) pattern used for editing time-zone in the UI.
+ * <p>
+ * Java time-zone formats<pre>
+ * V time-zone ID zone-id America/Los_Angeles; Z; -08:30
+ * z time-zone name zone-name Pacific Standard Time; PST
+ * O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
+ * X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
+ * x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
+ * Z zone-offset offset-Z +0000; -0800; -08:00;
+ *</pre>
+ *
+ * @apiNote Yet only tested with {@literal XXX}, as there needs to be a format correspondence with
+ * <i>momentJs</i> supported formats for the <i>tempus-dominus</i> date/time-picker to work
+ * (as used by the <i>Wicket Viewer</i>).
*/
@NotNull @NotEmpty
- private String zonePattern = "x";
+ private String zonePatternForOutput = "XXX";
+
+ /**
+ * Support both forms for parsing, with or without colon.
+ * @see "https://stackoverflow.com/questions/34637626/java-datetimeformatter-for-time-zone-with-an-optional-colon-separator"
+ */
+ @NotNull @NotEmpty
+ private String zonePatternForInput = "[XXX][X]";
// -- JOINING PATTERNS
@@ -205,20 +225,26 @@ extends
String.format(getDateTimeJoiningPattern(), getDatePattern(), timePattern(timePrecision, direction));
return offsetCharacteristic.isLocal()
? dateTimePattern
- : String.format(getZoneJoiningPattern(), dateTimePattern, getZonePattern());
+ : String.format(getZoneJoiningPattern(), dateTimePattern, zonePattern(direction));
case DATE_ONLY:
return offsetCharacteristic.isLocal()
? getDatePattern()
- : String.format(getZoneJoiningPattern(), getDatePattern(), getZonePattern());
+ : String.format(getZoneJoiningPattern(), getDatePattern(), zonePattern(direction));
case TIME_ONLY:
return offsetCharacteristic.isLocal()
? timePattern(timePrecision, direction)
- : String.format(getZoneJoiningPattern(), timePattern(timePrecision, direction), getZonePattern());
+ : String.format(getZoneJoiningPattern(), timePattern(timePrecision, direction), zonePattern(direction));
default:
throw _Exceptions.unmatchedCase(temporalCharacteristic);
}
}
+ private String zonePattern(@NonNull final EditingFormatDirection direction) {
+ return direction.isInput()
+ ? getZonePatternForInput()
+ : getZonePatternForOutput();
+ }
+
// -- HELPER
private String timePattern(
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java b/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
index f549e13d69..e23022ce3f 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/base/_Strings.java
@@ -425,6 +425,32 @@ public final class _Strings {
return nullToEmpty(str) + of(fillCount, c);
}
+ /**
+ * Returns a string that is a substring of this string.
+ * The substring begins at the specified beginIndex and extends to the character at index endIndex - 1.
+ * Thus the length of the substring is endIndex-beginIndex.
+ * <p>
+ * Supports negative endIndex, as well as index overflow.
+ */
+ public static String substring(final @Nullable String str, final int beginIndex, final int endIndex) {
+ if(isEmpty(str)) {
+ return str;
+ }
+ final int maxIndex = str.length()-1; // >= 0
+
+ final int i1 = endIndex<0
+ ? str.length() + endIndex
+ : endIndex;
+
+ final int i0 = beginIndex>0
+ ? Math.min(beginIndex, maxIndex)
+ : 0;
+
+ return i0<i1
+ ? str.substring(i0, i1)
+ : "";
+ }
+
// -- SPLITTING
/**
diff --git a/commons/src/test/java/org/apache/isis/commons/internal/base/StringsTest.java b/commons/src/test/java/org/apache/isis/commons/internal/base/StringsTest.java
index 490d8246c5..2e984524e1 100644
--- a/commons/src/test/java/org/apache/isis/commons/internal/base/StringsTest.java
+++ b/commons/src/test/java/org/apache/isis/commons/internal/base/StringsTest.java
@@ -46,18 +46,27 @@ class StringsTest {
assertThat(_Strings.isNotEmpty(null), is(false));
}
+ @Test
+ public void substring() throws Exception {
+ assertThat(_Strings.substring("12abc", 0, 5), is("12abc"));
+ assertThat(_Strings.substring("12abc", 1, 5), is("2abc"));
+ assertThat(_Strings.substring("12abc", 0, 4), is("12ab"));
+ assertThat(_Strings.substring("12abc", 0, -1), is("12ab"));
+ assertThat(_Strings.substring("12abc", 10, -10), is("")); // index overflow
+ assertThat(_Strings.substring(null, 1, 1), nullValue());
+ }
@Test
public void lowerWithNull() throws Exception {
assertThat(
- _Strings.lower(null),
+ _Strings.lower(null),
nullValue());
}
@Test
public void lowerMixed() throws Exception {
assertThat(
- _Strings.lower("12aBc"),
+ _Strings.lower("12aBc"),
is("12abc"));
}
@@ -65,56 +74,56 @@ class StringsTest {
@Test
public void upperWithNull() throws Exception {
assertThat(
- _Strings.upper(null),
+ _Strings.upper(null),
nullValue());
}
@Test
public void upperMixed() throws Exception {
assertThat(
- _Strings.upper("12aBc"),
+ _Strings.upper("12aBc"),
is("12ABC"));
}
@Test
public void capitalizeWithNull() throws Exception {
assertThat(
- _Strings.capitalize(null),
+ _Strings.capitalize(null),
nullValue());
}
@Test
public void capitalizeSize0() throws Exception {
assertThat(
- _Strings.capitalize(""),
+ _Strings.capitalize(""),
is(""));
}
@Test
public void capitalizeSize1() throws Exception {
assertThat(
- _Strings.capitalize("a"),
+ _Strings.capitalize("a"),
is("A"));
}
@Test
public void capitalizeSize2() throws Exception {
assertThat(
- _Strings.capitalize("ab"),
+ _Strings.capitalize("ab"),
is("Ab"));
}
@Test
public void trimWithNull() throws Exception {
assertThat(
- _Strings.trim(null),
+ _Strings.trim(null),
nullValue());
}
@Test
public void trimMixed() throws Exception {
assertThat(
- _Strings.trim(" 12 aBc"),
+ _Strings.trim(" 12 aBc"),
is("12 aBc"));
}
@@ -157,7 +166,7 @@ class StringsTest {
.collect(Collectors.joining("|")),
is(" 1|2 a||Bc "));
}
-
+
@Test
public void splitThenStreamWithnewLine() throws Exception {
assertThat(
@@ -169,14 +178,14 @@ class StringsTest {
@Test
public void condenseWhitespacesWithNull() throws Exception {
assertThat(
- _Strings.condenseWhitespaces(null,"|"),
+ _Strings.condenseWhitespaces(null,"|"),
nullValue());
}
@Test
public void condenseWhitespaces() throws Exception {
assertThat(
- _Strings.condenseWhitespaces(" 12 aBc","|"),
+ _Strings.condenseWhitespaces(" 12 aBc","|"),
is("|12|aBc"));
}
@@ -185,7 +194,7 @@ class StringsTest {
@Test
public void toByteConvertWithNull() throws Exception {
assertThat(
- _Strings.toBytes(null, StandardCharsets.UTF_8),
+ _Strings.toBytes(null, StandardCharsets.UTF_8),
nullValue());
}
@@ -208,21 +217,21 @@ class StringsTest {
@Test
public void fromByteConvertWithNull() throws Exception {
assertThat(
- _Strings.ofBytes(null, StandardCharsets.UTF_8),
+ _Strings.ofBytes(null, StandardCharsets.UTF_8),
nullValue());
}
@Test
public void fromByteConvertWithEmpty() throws Exception {
assertThat(
- _Strings.ofBytes(_Constants.emptyBytes, StandardCharsets.UTF_8),
+ _Strings.ofBytes(_Constants.emptyBytes, StandardCharsets.UTF_8),
is(""));
}
@Test
public void fromByteConvert() throws Exception {
assertThat(
- _Strings.ofBytes(new byte[] {48,49,50,51}, StandardCharsets.UTF_8),
+ _Strings.ofBytes(new byte[] {48,49,50,51}, StandardCharsets.UTF_8),
is("0123"));
}
@@ -232,11 +241,11 @@ class StringsTest {
public void convertIdentity() throws Exception {
assertThat(
- _Strings.convert(null, _Bytes.operator(), StandardCharsets.UTF_8),
+ _Strings.convert(null, _Bytes.operator(), StandardCharsets.UTF_8),
nullValue());
assertThat(
- _Strings.convert("0123", _Bytes.operator(), StandardCharsets.UTF_8),
+ _Strings.convert("0123", _Bytes.operator(), StandardCharsets.UTF_8),
is("0123"));
}
@@ -245,14 +254,14 @@ class StringsTest {
@Test
public void composeIdentityWithNull() throws Exception {
assertThat(
- _Strings.operator().apply(null),
+ _Strings.operator().apply(null),
nullValue());
}
@Test
public void composeIdentity() throws Exception {
assertThat(
- _Strings.operator().apply(" 12 aBc"),
+ _Strings.operator().apply(" 12 aBc"),
is(" 12 aBc"));
}
@@ -261,7 +270,7 @@ class StringsTest {
assertThat(
_Strings.operator()
.andThen(_Strings::lower)
- .apply(null),
+ .apply(null),
nullValue());
}
@@ -270,7 +279,7 @@ class StringsTest {
assertThat(
_Strings.operator()
.andThen(_Strings::lower)
- .apply(" 12 aBc"),
+ .apply(" 12 aBc"),
is(" 12 abc"));
}
@@ -280,7 +289,7 @@ class StringsTest {
_Strings.operator()
.andThen(_Strings::lower)
.andThen(_Strings::upper)
- .apply(" 12 aBc"),
+ .apply(" 12 aBc"),
is(" 12 ABC"));
}
@@ -290,7 +299,7 @@ class StringsTest {
public void asLowerDashed() throws Exception {
assertThat(
_Strings.asLowerDashed
- .apply(" 12 aBc"),
+ .apply(" 12 aBc"),
is("-12-abc"));
}
@@ -298,7 +307,7 @@ class StringsTest {
public void asNormalized() throws Exception {
assertThat(
_Strings.asNormalized
- .apply(" 12 a B c"),
+ .apply(" 12 a B c"),
is(" 12 a B c"));
}
@@ -306,7 +315,7 @@ class StringsTest {
public void asNaturalName2() throws Exception {
assertThat(
_Strings.asNaturalName2
- .apply("NextAvailableDate"),
+ .apply("NextAvailableDate"),
is("Next Available Date"));
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
index 818bb30ab5..a1be6a5295 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuesemantics/temporal/TemporalValueSemanticsProvider.java
@@ -291,7 +291,7 @@ implements TemporalValueSemantics<T> {
.orElseGet(IsisConfiguration.ValueTypes.Temporal::new);
}
- private TemporalEditingPattern temporalEditingPattern() {
+ protected TemporalEditingPattern temporalEditingPattern() {
return temporalConfig().getEditing();
}
diff --git a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
index 742064d232..33d0989ef5 100644
--- a/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
+++ b/regressiontests/stable-value/src/test/java/org/apache/isis/testdomain/value/ValueSemanticsTest.java
@@ -18,6 +18,9 @@
*/
package org.apache.isis.testdomain.value;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZonedDateTime;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
@@ -53,6 +56,7 @@ import org.apache.isis.applib.value.semantics.ValueDecomposition;
import org.apache.isis.applib.value.semantics.ValueSemanticsAbstract.PlaceholderLiteral;
import org.apache.isis.applib.value.semantics.ValueSemanticsProvider;
import org.apache.isis.applib.value.semantics.ValueSemanticsResolver;
+import org.apache.isis.commons.internal.base._Strings;
import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
@@ -202,12 +206,33 @@ class ValueSemanticsTest {
} else {
- System.err.printf("using %s trying to parse '%s'%n", valueType.getName(), stringified);
+ //debug
+ //System.err.printf("using %s trying to parse '%s'%n", valueType.getName(), stringified);
tester.assertValueEquals(
example.getValue(),
parser.parseTextRepresentation(context, stringified),
"parser roundtrip failed");
+
+ if(valueType.equals(OffsetDateTime.class)
+ || valueType.equals(OffsetTime.class)
+ || valueType.equals(ZonedDateTime.class)) {
+
+ // test alternative time-zone format with 4 digits +-HHmm
+ tester.assertValueEquals(
+ example.getValue(),
+ parser.parseTextRepresentation(context,
+ _Strings.substring(stringified, 0, -6) + "+0200"),
+ "parser roundtrip failed (alternative time-zone format with 4 digits +-HHmm)");
+
+ // test alternative time-zone format with 2 digits +-HH
+ tester.assertValueEquals(
+ example.getValue(),
+ parser.parseTextRepresentation(context,
+ _Strings.substring(stringified, 0, -6) + "+02"),
+ "parser roundtrip failed (alternative time-zone format with 2 digits +-HH)");
+ }
+
}
}
@Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/DateTimeConfig.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/DateTimeConfig.java
index 4507544f65..2cf027dba9 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/DateTimeConfig.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/DateTimeConfig.java
@@ -379,6 +379,9 @@ public class DateTimeConfig extends AbstractConfig {
return this;
}
+ /**
+ * @param value Whether on show, will set the picker to the current date/time.
+ */
public DateTimeConfig useCurrent(final boolean value) {
put(UseCurrent, value);
return this;
@@ -425,7 +428,7 @@ public class DateTimeConfig extends AbstractConfig {
private static class TodayButtonSerializer extends JsonSerializer<TodayButton> {
@Override
- public void serialize(TodayButton value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+ public void serialize(final TodayButton value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
switch (value) {
case TRUE:
jgen.writeBoolean(true);