You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TimeZoneUtil.java 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.util;
  17. import java.io.Serializable;
  18. import java.time.Duration;
  19. import java.time.LocalDate;
  20. import java.time.LocalDateTime;
  21. import java.time.ZoneId;
  22. import java.time.ZonedDateTime;
  23. import java.time.zone.ZoneOffsetTransition;
  24. import java.time.zone.ZoneRules;
  25. import java.util.ArrayList;
  26. import java.util.List;
  27. import java.util.Locale;
  28. import java.util.TimeZone;
  29. import elemental.json.JsonArray;
  30. import elemental.json.JsonObject;
  31. import elemental.json.impl.JreJsonFactory;
  32. import elemental.json.impl.JsonUtil;
  33. /**
  34. * Utilities related to {@link com.google.gwt.i18n.client.TimeZone}.
  35. *
  36. * @author Vaadin Ltd
  37. * @since 8.2
  38. */
  39. public final class TimeZoneUtil implements Serializable {
  40. /**
  41. * The default start year (inclusive) from which to calculate the
  42. * daylight-saving time zone transition dates.
  43. */
  44. private static final int STARTING_YEAR = 1980;
  45. /**
  46. * The default value of the number of future years from the current date for
  47. * which the daylight-saving time zone transition dates are calculated.
  48. */
  49. private static final int YEARS_FROM_NOW = 20;
  50. private TimeZoneUtil() {
  51. // Static utils only
  52. }
  53. /**
  54. * Returns a JSON string of the specified {@code zoneId} and {@link Locale},
  55. * which is used in
  56. * {@link com.google.gwt.i18n.client.TimeZone#createTimeZone(String)}.
  57. *
  58. * This method calculates the JSON string from the year
  59. * {@value #STARTING_YEAR} until {@value #YEARS_FROM_NOW} years into the
  60. * future from the current date.
  61. *
  62. * @see #toJSON(ZoneId, Locale, int, int)
  63. *
  64. * @param zoneId
  65. * the {@link ZoneId} to get the daylight transitions from
  66. * @param locale
  67. * the locale used to determine the short name of the time zone
  68. *
  69. * @return the encoded string
  70. */
  71. public static String toJSON(ZoneId zoneId, Locale locale) {
  72. int endYear = LocalDate.now().getYear() + YEARS_FROM_NOW;
  73. return toJSON(zoneId, locale, STARTING_YEAR, endYear);
  74. }
  75. /**
  76. * Returns a JSON string of the specified {@code zoneId} and {@link Locale},
  77. * which is used in
  78. * {@link com.google.gwt.i18n.client.TimeZone#createTimeZone(String)}.
  79. *
  80. * This method calculates the JSON string from {@code startYear} until
  81. * {@code startYear}, both inclusive.
  82. *
  83. * @param zoneId
  84. * the {@link ZoneId} to get the daylight transitions from
  85. * @param locale
  86. * the locale used to determine the short name of the time zone
  87. * @param startYear
  88. * the start year of DST transitions
  89. * @param endYear
  90. * the end year of DST transitions
  91. *
  92. * @return the encoded string
  93. * @since 8.11
  94. */
  95. public static String toJSON(ZoneId zoneId, Locale locale, int startYear,
  96. int endYear) {
  97. if (zoneId == null || locale == null) {
  98. return null;
  99. }
  100. ZoneRules rules = zoneId.getRules();
  101. TimeZone timeZone = TimeZone.getTimeZone(zoneId);
  102. List<Long> transitionsList = new ArrayList<>();
  103. TimeZoneInfo info = new TimeZoneInfo();
  104. if (timeZone.useDaylightTime()) {
  105. for (int year = startYear; year <= endYear; year++) {
  106. ZonedDateTime i = LocalDateTime.of(year, 1, 1, 0, 0)
  107. .atZone(zoneId);
  108. while (true) {
  109. ZoneOffsetTransition t = rules
  110. .nextTransition(i.toInstant());
  111. if (t == null) {
  112. break;
  113. }
  114. i = t.getInstant().atZone(zoneId);
  115. if (i.toLocalDate().getYear() != year) {
  116. break;
  117. }
  118. long epochHours = Duration
  119. .ofSeconds(t.getInstant().getEpochSecond())
  120. .toHours();
  121. long duration = Math.max(t.getDuration().toMinutes(), 0);
  122. transitionsList.add(epochHours);
  123. transitionsList.add(duration);
  124. }
  125. }
  126. }
  127. info.id = zoneId.getId();
  128. info.transitions = transitionsList.stream().mapToLong(l -> l).toArray();
  129. info.stdOffset = (int) Duration.ofMillis(timeZone.getRawOffset())
  130. .toMinutes();
  131. info.names = new String[] {
  132. timeZone.getDisplayName(false, TimeZone.SHORT, locale),
  133. timeZone.getDisplayName(false, TimeZone.LONG, locale),
  134. timeZone.getDisplayName(true, TimeZone.SHORT, locale),
  135. timeZone.getDisplayName(true, TimeZone.LONG, locale) };
  136. return stringify(info);
  137. }
  138. private static String stringify(TimeZoneInfo info) {
  139. JreJsonFactory factory = new JreJsonFactory();
  140. JsonObject object = factory.createObject();
  141. object.put("id", info.id);
  142. object.put("std_offset", info.stdOffset);
  143. object.put("names", getArray(factory, info.names));
  144. object.put("transitions", getArray(factory, info.transitions));
  145. return JsonUtil.stringify(object);
  146. }
  147. private static JsonArray getArray(JreJsonFactory factory, long[] array) {
  148. JsonArray jsonArray = factory.createArray();
  149. for (int i = 0; i < array.length; i++) {
  150. jsonArray.set(i, array[i]);
  151. }
  152. return jsonArray;
  153. }
  154. private static JsonArray getArray(JreJsonFactory factory, String[] array) {
  155. JsonArray jsonArray = factory.createArray();
  156. for (int i = 0; i < array.length; i++) {
  157. jsonArray.set(i, array[i]);
  158. }
  159. return jsonArray;
  160. }
  161. private static class TimeZoneInfo implements Serializable {
  162. String id;
  163. int stdOffset;
  164. String[] names;
  165. long[] transitions;
  166. }
  167. }