diff options
author | Ahmed Ashour <asashour@yahoo.com> | 2017-09-28 11:37:32 +0200 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-09-28 12:37:32 +0300 |
commit | c520767bf156c54a9d1a9f69f0aa78bc3b835b3f (patch) | |
tree | 208c6d8679708a6cc9e8b425d86fe10f2abeedc9 /server | |
parent | 131601de3693655387313e47e887f593c32fa625 (diff) | |
download | vaadin-framework-c520767bf156c54a9d1a9f69f0aa78bc3b835b3f.tar.gz vaadin-framework-c520767bf156c54a9d1a9f69f0aa78bc3b835b3f.zip |
Handle 'z' (timezone) in AbstractDateField.setDateFormat() (#8844)
Diffstat (limited to 'server')
-rw-r--r-- | server/src/main/java/com/vaadin/ui/AbstractDateField.java | 51 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/util/TimeZoneUtil.java | 150 |
2 files changed, 201 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java index bc6b5f49a8..b5f11f7122 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java +++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.ZoneId; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; import java.util.Calendar; @@ -56,6 +57,7 @@ import com.vaadin.shared.ui.datefield.DateFieldConstants; import com.vaadin.shared.ui.datefield.DateResolution; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.util.TimeZoneUtil; /** * A date editor component with {@link LocalDate} as an input value. @@ -95,6 +97,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & */ private String dateFormat; + private ZoneId zoneId; + private boolean lenient = false; private String dateString = ""; @@ -445,6 +449,53 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & } /** + * Sets the {@link ZoneId}, which is used when {@code z} is included inside + * the {@link #setDateFormat(String)}. + * + * @param zoneId + * the zone id + * @since 8.2 + */ + public void setZoneId(ZoneId zoneId) { + if (zoneId != this.zoneId + || (zoneId != null && !zoneId.equals(this.zoneId))) { + updateTimeZoneJSON(zoneId, getLocale()); + } + this.zoneId = zoneId; + } + + private void updateTimeZoneJSON(ZoneId zoneId, Locale locale) { + String timeZoneJSON; + if (zoneId != null && locale != null) { + timeZoneJSON = TimeZoneUtil.toJSON(zoneId, locale); + } else { + timeZoneJSON = null; + } + getState().timeZoneJSON = timeZoneJSON; + } + + @Override + public void setLocale(Locale locale) { + Locale oldLocale = getLocale(); + if (locale != oldLocale + || (locale != null && !locale.equals(oldLocale))) { + updateTimeZoneJSON(getZoneId(), locale); + } + super.setLocale(locale); + } + + /** + * Returns the {@link ZoneId}, which is used when {@code z} is included + * inside the {@link #setDateFormat(String)}. + * + * @return the zoneId + * @since 8.2 + */ + public ZoneId getZoneId() { + return zoneId; + } + + /** * Specifies whether or not date/time interpretation in component is to be * lenient. * diff --git a/server/src/main/java/com/vaadin/util/TimeZoneUtil.java b/server/src/main/java/com/vaadin/util/TimeZoneUtil.java new file mode 100644 index 0000000000..ec3d28e730 --- /dev/null +++ b/server/src/main/java/com/vaadin/util/TimeZoneUtil.java @@ -0,0 +1,150 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.util; + +import java.io.Serializable; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneRules; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +import elemental.json.JsonArray; +import elemental.json.JsonObject; +import elemental.json.impl.JreJsonFactory; +import elemental.json.impl.JsonUtil; + +/** + * Utilities related to {@link com.google.gwt.i18n.client.TimeZone}. + * + * @author Vaadin Ltd + * @since 8.2 + */ +public final class TimeZoneUtil implements Serializable { + + /** + * The start year used to send the time zone transition dates. + */ + private static final int STARTING_YEAR = 1980; + + /** + * Till how many years from now, should we send the time zone transition + * dates. + */ + private static final int YEARS_FROM_NOW = 20; + + private TimeZoneUtil() { + // Static utils only + } + + /** + * Returns a JSON string of the specified {@code zoneId} and {@link Locale}, + * which is used in + * {@link com.google.gwt.i18n.client.TimeZone#createTimeZone(String)}. + * + * @param zoneId + * the {@link ZoneId} to get the daylight transitions from + * @param locale + * the locale used to determine the short name of the time zone + * + * @return the encoded string + */ + public static String toJSON(ZoneId zoneId, Locale locale) { + if (zoneId == null || locale == null) { + return null; + } + ZoneRules rules = zoneId.getRules(); + TimeZone timeZone = TimeZone.getTimeZone(zoneId); + List<Long> transitionsList = new ArrayList<>(); + + TimeZoneInfo info = new TimeZoneInfo(); + + int endYear = LocalDate.now().getYear() + YEARS_FROM_NOW; + if (timeZone.useDaylightTime()) { + for (int year = STARTING_YEAR; year <= endYear; year++) { + ZonedDateTime i = LocalDateTime.of(year, 1, 1, 0, 0) + .atZone(zoneId); + while (true) { + ZoneOffsetTransition t = rules + .nextTransition(i.toInstant()); + if (t == null) { + break; + } + i = t.getInstant().atZone(zoneId); + if (i.toLocalDate().getYear() != year) { + break; + } + long epocHours = Duration + .ofSeconds(t.getInstant().getEpochSecond()) + .toHours(); + long duration = Math.max(t.getDuration().toMinutes(), 0); + transitionsList.add(epocHours); + transitionsList.add(duration); + } + } + } + info.id = zoneId.getId(); + info.transitions = transitionsList.stream().mapToLong(l -> l).toArray(); + info.std_offset = (int) Duration.ofMillis(timeZone.getRawOffset()) + .toMinutes(); + info.names = new String[] { + timeZone.getDisplayName(false, TimeZone.SHORT, locale), + timeZone.getDisplayName(false, TimeZone.LONG, locale), + timeZone.getDisplayName(true, TimeZone.SHORT, locale), + timeZone.getDisplayName(true, TimeZone.LONG, locale) }; + + return stringify(info); + } + + private static String stringify(TimeZoneInfo info) { + JreJsonFactory factory = new JreJsonFactory(); + JsonObject object = factory.createObject(); + object.put("id", info.id); + object.put("std_offset", info.std_offset); + object.put("names", getArray(factory, info.names)); + object.put("transitions", getArray(factory, info.transitions)); + return JsonUtil.stringify(object); + } + + private static JsonArray getArray(JreJsonFactory factory, long[] array) { + JsonArray jsonArray = factory.createArray(); + for (int i = 0; i < array.length; i++) { + jsonArray.set(i, array[i]); + } + return jsonArray; + } + + private static JsonArray getArray(JreJsonFactory factory, String[] array) { + JsonArray jsonArray = factory.createArray(); + for (int i = 0; i < array.length; i++) { + jsonArray.set(i, array[i]); + } + return jsonArray; + } + + private static class TimeZoneInfo implements Serializable { + String id; + int std_offset; + String[] names; + long[] transitions; + } +} |