summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--all/src/main/templates/release-notes.html1
-rw-r--r--client/src/main/java/com/vaadin/client/DateTimeService.java11
-rw-r--r--client/src/main/java/com/vaadin/client/ui/CalendarEntry.java6
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java81
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java4
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java20
-rw-r--r--client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java11
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractDateField.java72
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java7
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java6
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java6
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java14
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldTimeZones.java53
13 files changed, 214 insertions, 78 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html
index 6e1d221b31..20dd5d53c2 100644
--- a/all/src/main/templates/release-notes.html
+++ b/all/src/main/templates/release-notes.html
@@ -98,6 +98,7 @@
<h2 id="incompatible">Incompatible or Behavior-altering Changes in @version-minor@</h2>
<li><tt>BindingBuilder</tt> will now automatically mark bound field <i>read-only</i> when bound to a read-only property or a <tt>null</tt> setter.</li>
+ <li>Date range limits in <tt>AbstractDateFieldState</tt> are now <tt>String</tt>s instead of <tt>Date</tt>s, some client-side method signatures were changed</li>
<h2>For incompatible or behavior-altering changes in 8.3, please see <a href="https://vaadin.com/download/release/8.3/8.3.0/release-notes.html#incompatible">8.3 release notes</a></h2>
diff --git a/client/src/main/java/com/vaadin/client/DateTimeService.java b/client/src/main/java/com/vaadin/client/DateTimeService.java
index 4883d34caf..50d5f9ed2d 100644
--- a/client/src/main/java/com/vaadin/client/DateTimeService.java
+++ b/client/src/main/java/com/vaadin/client/DateTimeService.java
@@ -60,6 +60,17 @@ public class DateTimeService {
setLocale(locale);
}
+ /**
+ * Utility method to format positive int as zero-padded two-digits number
+ *
+ * @param i the value
+ * @return "00".."99"
+ * @since
+ */
+ public static String asTwoDigits(int i) {
+ return (i < 10 ? "0" : "") + i;
+ }
+
public void setLocale(String locale) throws LocaleNotLoadedException {
if (!LocaleService.getAvailableLocales().contains(locale)) {
throw new LocaleNotLoadedException(locale);
diff --git a/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java b/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java
index d7bea84758..1efe0b6cf8 100644
--- a/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java
+++ b/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java
@@ -20,6 +20,8 @@ import java.util.Date;
import com.vaadin.client.DateTimeService;
+import static com.vaadin.client.DateTimeService.asTwoDigits;
+
public class CalendarEntry {
private final String styleName;
private Date start;
@@ -137,8 +139,4 @@ public class CalendarEntry {
return s;
}
- private static String asTwoDigits(int i) {
- return (i < 10 ? "0" : "") + i;
- }
-
}
diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java
index 8810b26e30..c792d0a2cc 100644
--- a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java
+++ b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java
@@ -60,6 +60,8 @@ import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.util.SharedUtil;
+import static com.vaadin.client.DateTimeService.asTwoDigits;
+
/**
* Abstract calendar panel to show and select a date using a resolution. The
* class is parameterized by the date resolution enumeration type.
@@ -719,21 +721,23 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
return true;
}
- Date valueDuplicate = (Date) date.clone();
- Date rangeStartDuplicate = (Date) rangeStart.clone();
+ String dateStrResolution = dateStrResolution(date, minResolution);
+ return rangeStart.substring(0,dateStrResolution.length())
+ .compareTo(dateStrResolution) <=0;
+ }
- if (isYear(minResolution)) {
- return valueDuplicate.getYear() >= rangeStartDuplicate.getYear();
+ private String dateStrResolution(Date date, R minResolution) {
+ String dateStrResolution = (1900 + date.getYear()) + "";
+ while (dateStrResolution.length() < 4) {
+ dateStrResolution = "0" + dateStrResolution;
}
- if (isMonth(minResolution)) {
- valueDuplicate = clearDateBelowMonth(valueDuplicate);
- rangeStartDuplicate = clearDateBelowMonth(rangeStartDuplicate);
- } else {
- valueDuplicate = clearDateBelowDay(valueDuplicate);
- rangeStartDuplicate = clearDateBelowDay(rangeStartDuplicate);
+ if (!isYear(minResolution)) {
+ dateStrResolution += "-" + asTwoDigits(1 + date.getMonth());
+ if (!isMonth(minResolution)) {
+ dateStrResolution += "-" + asTwoDigits(date.getDate());
+ }
}
-
- return !rangeStartDuplicate.after(valueDuplicate);
+ return dateStrResolution;
}
/**
@@ -755,22 +759,9 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
return true;
}
- Date valueDuplicate = (Date) date.clone();
- Date rangeEndDuplicate = (Date) rangeEnd.clone();
-
- if (isYear(minResolution)) {
- return valueDuplicate.getYear() <= rangeEndDuplicate.getYear();
- }
- if (isMonth(minResolution)) {
- valueDuplicate = clearDateBelowMonth(valueDuplicate);
- rangeEndDuplicate = clearDateBelowMonth(rangeEndDuplicate);
- } else {
- valueDuplicate = clearDateBelowDay(valueDuplicate);
- rangeEndDuplicate = clearDateBelowDay(rangeEndDuplicate);
- }
-
- return !rangeEndDuplicate.before(valueDuplicate);
-
+ String dateStrResolution = dateStrResolution(date, minResolution);
+ return rangeEnd.substring(0,dateStrResolution.length())
+ .compareTo(dateStrResolution) >= 0;
}
private static Date clearDateBelowMonth(Date date) {
@@ -1691,14 +1682,32 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
* @param date
*/
private Date adjustDateToFitInsideRange(Date date) {
- if (rangeStart != null && rangeStart.after(date)) {
- date = (Date) rangeStart.clone();
- } else if (rangeEnd != null && rangeEnd.before(date)) {
- date = (Date) rangeEnd.clone();
+ if(!isAcceptedByRangeStart(date,resolution)) {
+ date = parseRangeString(rangeStart);
+ } else
+ if(!isAcceptedByRangeEnd(date,resolution)) {
+ date = parseRangeString(rangeEnd);
}
return date;
}
+ private Date parseRangeString(String dateStr) {
+ if(dateStr == null || "".equals(dateStr)) return null;
+ int year = Integer.parseInt(dateStr.substring(0,4)) - 1900;
+ int month = parsePart(dateStr, 5, 2,1) - 1;
+ int day = parsePart(dateStr, 8, 2,1);
+ int hrs = parsePart(dateStr, 11, 2,0);
+ int min = parsePart(dateStr, 14, 2,0);
+ int sec = parsePart(dateStr, 17, 2,0);
+
+ return new Date(year,month,day,hrs,min,sec);
+ }
+
+ private int parsePart(String dateStr, int beginIndex, int length, int defValue) {
+ if(dateStr.length() < beginIndex + length) return defValue;
+ return Integer.parseInt(dateStr.substring(beginIndex, beginIndex + length));
+ }
+
/**
* Sets the data of the Panel.
*
@@ -1914,9 +1923,9 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
private static final String SUBPART_DAY = "day";
private static final String SUBPART_MONTH_YEAR_HEADER = "header";
- private Date rangeStart;
+ private String rangeStart;
- private Date rangeEnd;
+ private String rangeEnd;
@Override
public String getSubPartName(
@@ -2070,7 +2079,7 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
* @param newRangeStart
* - the allowed range's start date
*/
- public void setRangeStart(Date newRangeStart) {
+ public void setRangeStart(String newRangeStart) {
if (!SharedUtil.equals(rangeStart, newRangeStart)) {
rangeStart = newRangeStart;
if (initialRenderDone) {
@@ -2088,7 +2097,7 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
* @param newRangeEnd
* - the allowed range's end date
*/
- public void setRangeEnd(Date newRangeEnd) {
+ public void setRangeEnd(String newRangeEnd) {
if (!SharedUtil.equals(rangeEnd, newRangeEnd)) {
rangeEnd = newRangeEnd;
if (initialRenderDone) {
diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java
index 4df4d0e325..bccf867d4e 100644
--- a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java
+++ b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java
@@ -599,7 +599,7 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane
* @param rangeStart
* - the allowed range's start date
*/
- public void setRangeStart(Date rangeStart) {
+ public void setRangeStart(String rangeStart) {
calendar.setRangeStart(rangeStart);
}
@@ -610,7 +610,7 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane
* @param rangeEnd
* - the allowed range's end date
*/
- public void setRangeEnd(Date rangeEnd) {
+ public void setRangeEnd(String rangeEnd) {
calendar.setRangeEnd(rangeEnd);
}
diff --git a/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java b/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java
index 5e9732e091..5dae92564a 100644
--- a/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java
+++ b/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java
@@ -79,8 +79,6 @@ public class VDateTimeCalendarPanel
/**
* Constructs the ListBoxes and updates their value
*
- * @param redraw
- * Should new instances of the listboxes be created
*/
private void buildTime() {
clear();
@@ -89,11 +87,11 @@ public class VDateTimeCalendarPanel
if (getDateTimeService().isTwelveHourClock()) {
hours.addItem("12");
for (int i = 1; i < 12; i++) {
- hours.addItem(asTwoDigits(i));
+ hours.addItem(DateTimeService.asTwoDigits(i));
}
} else {
for (int i = 0; i < 24; i++) {
- hours.addItem(asTwoDigits(i));
+ hours.addItem(DateTimeService.asTwoDigits(i));
}
}
@@ -109,14 +107,14 @@ public class VDateTimeCalendarPanel
if (getResolution().compareTo(DateTimeResolution.MINUTE) <= 0) {
mins = createListBox();
for (int i = 0; i < 60; i++) {
- mins.addItem(asTwoDigits(i));
+ mins.addItem(DateTimeService.asTwoDigits(i));
}
mins.addChangeHandler(this);
}
if (getResolution().compareTo(DateTimeResolution.SECOND) <= 0) {
sec = createListBox();
for (int i = 0; i < 60; i++) {
- sec.addItem(asTwoDigits(i));
+ sec.addItem(DateTimeService.asTwoDigits(i));
}
sec.addChangeHandler(this);
}
@@ -130,7 +128,7 @@ public class VDateTimeCalendarPanel
if (getDateTimeService().isTwelveHourClock()) {
h -= h < 12 ? 0 : 12;
}
- add(new VLabel(asTwoDigits(h)));
+ add(new VLabel(DateTimeService.asTwoDigits(h)));
} else {
add(hours);
}
@@ -139,7 +137,7 @@ public class VDateTimeCalendarPanel
add(new VLabel(delimiter));
if (isReadonly()) {
final int m = mins.getSelectedIndex();
- add(new VLabel(asTwoDigits(m)));
+ add(new VLabel(DateTimeService.asTwoDigits(m)));
} else {
add(mins);
}
@@ -148,7 +146,7 @@ public class VDateTimeCalendarPanel
add(new VLabel(delimiter));
if (isReadonly()) {
final int s = sec.getSelectedIndex();
- add(new VLabel(asTwoDigits(s)));
+ add(new VLabel(DateTimeService.asTwoDigits(s)));
} else {
add(sec);
}
@@ -308,10 +306,6 @@ public class VDateTimeCalendarPanel
}
}
- private static String asTwoDigits(int i) {
- return (i < 10 ? "0" : "") + i;
- }
-
/**
* Dispatches an event when the panel when time is changed.
*/
diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java
index 0702211ccb..08682ff13d 100644
--- a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java
@@ -123,8 +123,8 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel<
super.onStateChanged(stateChangeEvent);
getWidget().setTextFieldEnabled(getState().textFieldEnabled);
- getWidget().setRangeStart(nullSafeDateClone(getState().rangeStart));
- getWidget().setRangeEnd(nullSafeDateClone(getState().rangeEnd));
+ getWidget().setRangeStart(getState().rangeStart);
+ getWidget().setRangeEnd(getState().rangeEnd);
getWidget().calendar.setDateStyles(getState().dateStyles);
getWidget().calendar
@@ -167,13 +167,6 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel<
getWidget().setTextFieldTabIndex();
}
- private Date nullSafeDateClone(Date date) {
- if (date != null) {
- return (Date) date.clone();
- }
- return null;
- }
-
@Override
protected void setWidgetStyleName(String styleName, boolean add) {
super.setWidgetStyleName(styleName, add);
diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
index 3998afbae6..13a6e50ce4 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
@@ -20,7 +20,9 @@ import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.util.Calendar;
import java.util.Collections;
@@ -77,6 +79,7 @@ import com.vaadin.util.TimeZoneUtil;
public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & Serializable & Comparable<? super T>, R extends Enum<R>>
extends AbstractField<T> implements FocusNotifier, BlurNotifier {
+ private static final DateTimeFormatter RANGE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd[ HH:mm:ss]", Locale.ENGLISH);
private AbstractDateFieldServerRpc rpc = new AbstractDateFieldServerRpc() {
@Override
@@ -269,14 +272,12 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
* - the allowed range's start date
*/
public void setRangeStart(T startDate) {
- Date date = convertToDate(startDate);
- if (date != null && getState().rangeEnd != null
- && date.after(getState().rangeEnd)) {
+ if (afterDate(startDate,convertFromDateString(getState().rangeEnd))) {
throw new IllegalStateException(
"startDate cannot be later than endDate");
}
- getState().rangeStart = date;
+ getState().rangeStart = convertToDateString(startDate);
}
/**
@@ -333,9 +334,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
* resolution)
*/
public void setRangeEnd(T endDate) {
- Date date = convertToDate(endDate);
- if (date != null && getState().rangeStart != null
- && getState().rangeStart.after(date)) {
+ String date = convertToDateString(endDate);
+ if (afterDate(convertFromDateString(getState().rangeStart), endDate)) {
throw new IllegalStateException(
"endDate cannot be earlier than startDate");
}
@@ -343,13 +343,67 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
getState().rangeEnd = date;
}
+
/**
* Returns the precise rangeStart used.
*
* @return the precise rangeStart used, may be {@code null}.
*/
public T getRangeStart() {
- return convertFromDate(getState(false).rangeStart);
+ return convertFromDateString(getState(false).rangeStart);
+ }
+
+ /**
+ * Parses string representaion of date range limit into date type
+ *
+ * @param temporalStr the string representation
+ * @return parsed value
+ * @see AbstractDateFieldState#rangeStart
+ * @see AbstractDateFieldState#rangeEnd
+ * @since
+ */
+ protected T convertFromDateString(String temporalStr) {
+ if (temporalStr == null) {
+ return null;
+ }
+ return toType(RANGE_FORMATTER.parse(temporalStr));
+ }
+
+ /**
+ * Converts a temporal value into field-specific data type.
+ * @param temporalAccessor - source value
+ * @return conversion result.
+ * @since
+ */
+ protected abstract T toType(TemporalAccessor temporalAccessor);
+
+ /**
+ * Converts date range limit itno string representaion
+ *
+ * @param temporal the value
+ * @return textual representation
+ * @see AbstractDateFieldState#rangeStart
+ * @see AbstractDateFieldState#rangeEnd
+ * @since
+ */
+ protected String convertToDateString(T temporal) {
+ if (temporal == null) {
+ return null;
+ }
+ return RANGE_FORMATTER.format(temporal);
+ }
+
+ /**
+ * Checks if {@code value} is after {@code base} or not
+ * @param value temporal value
+ * @param base temporal value to compare to
+ * @return {@code true} if {@code value} is after {@code base}, {@code false} otherwise
+ */
+ protected boolean afterDate(T value, T base) {
+ if (value == null || base == null) {
+ return false;
+ }
+ return value.compareTo(base) > 0;
}
/**
@@ -358,7 +412,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
* @return the precise rangeEnd used, may be {@code null}.
*/
public T getRangeEnd() {
- return convertFromDate(getState(false).rangeEnd);
+ return convertFromDateString(getState(false).rangeEnd);
}
/**
diff --git a/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java b/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java
index 84072288e5..be48ce758c 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractLocalDateField.java
@@ -17,9 +17,11 @@ package com.vaadin.ui;
import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
+import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
@@ -155,4 +157,9 @@ public abstract class AbstractLocalDateField
}
return value.format(dateTimeFormatter);
}
+
+ @Override
+ protected LocalDate toType(TemporalAccessor temporalAccessor) {
+ return temporalAccessor == null? null : LocalDate.from(temporalAccessor);
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java b/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java
index adf6e0bc53..ddb39b6a1e 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractLocalDateTimeField.java
@@ -21,6 +21,7 @@ import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
@@ -179,4 +180,9 @@ public abstract class AbstractLocalDateTimeField
}
return value.format(dateTimeFormatter);
}
+
+ @Override
+ protected LocalDateTime toType(TemporalAccessor temporalAccessor) {
+ return temporalAccessor == null? null : LocalDateTime.from(temporalAccessor);
+ }
}
diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
index eea1e33137..91d7384421 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java
@@ -1,6 +1,7 @@
package com.vaadin.tests.server.component.datefield;
import java.time.LocalDateTime;
+import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Map;
@@ -55,6 +56,11 @@ public class DateFieldListenersTest extends AbstractListenerMethodsTestBase {
protected String formatDate(LocalDateTime value) {
return null;
}
+
+ @Override
+ protected LocalDateTime toType(TemporalAccessor temporalAccessor) {
+ return LocalDateTime.from(temporalAccessor);
+ }
}
@Test
diff --git a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java
index 553e82a57e..30f8c71159 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java
@@ -49,17 +49,21 @@ public class AbstractDateFieldState extends AbstractFieldState {
/**
* Start range that has been cleared, depending on the resolution of the
- * date field.
+ * date field. The format is "2018-05-27" or "2018-05-27 14:38:39"
+ *
+ * @see com.vaadin.ui.AbstractDateField#RANGE_FORMATTER
*/
@NoLayout
- public Date rangeStart;
+ public String rangeStart;
/**
- * End range that has been cleared, depending on the resolution of the date
- * field.
+ * End range that has been cleared, depending on the resolution of the
+ * date field. The format is "2018-05-27" or "2018-05-27 14:38:39"
+ *
+ * @see com.vaadin.ui.AbstractDateField#RANGE_FORMATTER
*/
@NoLayout
- public Date rangeEnd;
+ public String rangeEnd;
/**
* The JSON used to construct a TimeZone on the client side, can be
diff --git a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldTimeZones.java b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldTimeZones.java
new file mode 100644
index 0000000000..be7cd1456b
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldTimeZones.java
@@ -0,0 +1,53 @@
+package com.vaadin.tests.components.datefield;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.datefield.DateResolution;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.InlineDateTimeField;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class DateFieldTimeZones extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ InlineDateField d1 = new InlineDateField();
+ InlineDateField d2 = new InlineDateField();
+ InlineDateTimeField d3 = new InlineDateTimeField();
+ InlineDateTimeField d4 = new InlineDateTimeField();
+ InlineDateTimeField d5 = new InlineDateTimeField();
+
+ d1.setValue(LocalDate.of(2018, 1, 1));
+ d2.setValue(LocalDate.of(2019, 12, 1));
+ d3.setValue(LocalDateTime.of(2019, 12, 1,0,0,0));
+ d4.setValue(LocalDateTime.of(2019, 12, 1,0,0,0));
+ d4.setValue(LocalDateTime.of(2019, 12, 1,0,0,0));
+
+ d1.setResolution(DateResolution.DAY);
+ d2.setResolution(DateResolution.DAY);
+
+ d2.setRangeStart(LocalDate.of(2018, 1, 1));
+ d2.setRangeEnd(LocalDate.of(2019, 12, 1));
+
+ d3.setRangeStart(LocalDateTime.of(2018, 1, 1,0,0,0));
+ d3.setRangeEnd(LocalDateTime.of(2019, 12, 1,0,0,0));
+
+ d5.setRangeStart(LocalDateTime.of(2018, 1, 1,0,0,0));
+ d5.setRangeEnd(LocalDateTime.of(2019, 12, 1,0,0,0));
+
+ d5.setZoneId(ZoneId.of("-10"));
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.addComponents(d1, d2,d3,d4,d5);
+
+ addComponent(layout);
+ }
+
+}