diff --git a/bundles/core/org.eclipse.smarthome.core.test/src/test/java/org/eclipse/smarthome/core/library/types/DateTimeTypeTest.java b/bundles/core/org.eclipse.smarthome.core.test/src/test/java/org/eclipse/smarthome/core/library/types/DateTimeTypeTest.java index fb444b109c2..fea42e644a0 100644 --- a/bundles/core/org.eclipse.smarthome.core.test/src/test/java/org/eclipse/smarthome/core/library/types/DateTimeTypeTest.java +++ b/bundles/core/org.eclipse.smarthome.core.test/src/test/java/org/eclipse/smarthome/core/library/types/DateTimeTypeTest.java @@ -10,12 +10,15 @@ import static org.junit.Assert.*; import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.TimeZone; +import java.util.concurrent.TimeUnit; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,6 +28,7 @@ /** * @author Thomas.Eichstaedt-Engelen * @author Gaël L'hopital - Added Timezone and Milliseconds + * @author Erdoan Hadzhiyusein - Added ZonedDateTime tests */ @RunWith(Parameterized.class) public class DateTimeTypeTest { @@ -115,18 +119,20 @@ public static Collection parameters() { "2014-03-30T10:58:47.033+0000") }, { new ParameterSet(TimeZone.getTimeZone("UTC"), initTimeMap(), TimeZone.getTimeZone("CET"), "2014-03-30T08:58:47.033+0000") }, - { new ParameterSet(TimeZone.getTimeZone("UTC"), "2014-03-30T10:58:47UTS", + { new ParameterSet(TimeZone.getTimeZone("UTC"), "2014-03-30T10:58:47UTC", "2014-03-30T10:58:47.000+0000") }, { new ParameterSet(TimeZone.getTimeZone("CET"), initTimeMap(), TimeZone.getTimeZone("UTC"), "2014-03-30T12:58:47.033+0200") }, { new ParameterSet(TimeZone.getTimeZone("CET"), initTimeMap(), TimeZone.getTimeZone("CET"), "2014-03-30T10:58:47.033+0200") }, - { new ParameterSet(TimeZone.getTimeZone("CET"), "2014-03-30T10:58:47UTS", + { new ParameterSet(TimeZone.getTimeZone("CET"), "2014-03-30T10:58:47CET", "2014-03-30T10:58:47.000+0200") }, { new ParameterSet(TimeZone.getTimeZone("GMT+5"), "2014-03-30T10:58:47.000Z", "2014-03-30T15:58:47.000+0500") }, { new ParameterSet(TimeZone.getTimeZone("GMT"), initTimeMap(), TimeZone.getTimeZone("GMT"), "2014-03-30T10:58:47.033+0000") }, + { new ParameterSet(TimeZone.getTimeZone("CET"), initTimeMap(), TimeZone.getTimeZone("+02:00"), + "2014-03-30T12:58:47.033+0200") }, { new ParameterSet(TimeZone.getTimeZone("GMT+2"), initTimeMap(), TimeZone.getTimeZone("GML"), "2014-03-30T12:58:47.033+0200") }, { new ParameterSet(TimeZone.getTimeZone("GMT-2"), initTimeMap(), TimeZone.getTimeZone("GMT+3"), @@ -165,14 +171,34 @@ public void serializationTest() { assertTrue(dt.equals(new DateTimeType(dt.toString()))); } + @Test + public void serializationTestZoned() { + ZonedDateTime zoned = ZonedDateTime.now(); + DateTimeType dt = new DateTimeType(zoned); + DateTimeType sdt = new DateTimeType(dt.toFullString()); + assertEquals(dt.getZonedDateTime(), sdt.getZonedDateTime()); + } + @Test public void equalityTest() { DateTimeType dt1 = new DateTimeType(Calendar.getInstance()); - DateTimeType dt2 = DateTimeType.valueOf(dt1.toString()); + DateTimeType dt2 = DateTimeType.valueOf(dt1.toFullString()); assertTrue(dt1.toString().equals(dt2.toString())); assertTrue(dt1.equals(dt2)); assertTrue(dt1.getCalendar().equals(dt2.getCalendar())); + + assertTrue(dt1.equals(dt2)); + } + + @Test + public void equalityTestZoned() { + ZonedDateTime zoned = ZonedDateTime.now(); + DateTimeType dt1 = new DateTimeType(zoned); + DateTimeType dt2 = DateTimeType.valueOf(dt1.toFullString()); + + assertTrue(dt1.toString().equals(dt2.toFullString())); + assertTrue(dt1.getZonedDateTime().equals(dt2.getZonedDateTime())); assertTrue(dt1.equals(dt2)); } @@ -190,16 +216,45 @@ public void createDate() { parameterSet.inputTimeMap.get("date"), parameterSet.inputTimeMap.get("hourOfDay"), parameterSet.inputTimeMap.get("minute"), parameterSet.inputTimeMap.get("second")); calendar.set(Calendar.MILLISECOND, parameterSet.inputTimeMap.get("milliseconds")); - inputTimeString = new SimpleDateFormat(DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS).format(calendar.getTime()); } else { inputTimeString = parameterSet.inputTimeString; } - DateTimeType dt = DateTimeType.valueOf(inputTimeString); - + if (parameterSet.inputTimeZone == null) { + dt = new DateTimeType(dt.getZonedDateTime().withZoneSameInstant(TimeZone.getDefault().toZoneId())); + } // Test assertEquals(parameterSet.expectedResult, dt.toString()); + } + @Test + public void createZonedDate() { + String inputTimeString; + + // set default time zone + TimeZone.setDefault(parameterSet.defaultTimeZone); + + // get formatted time string + if (parameterSet.inputTimeString == null) { + int durationInNano = (int) TimeUnit.NANOSECONDS.convert(parameterSet.inputTimeMap.get("milliseconds"), + TimeUnit.MILLISECONDS); + + LocalDateTime dateTime = LocalDateTime.of(parameterSet.inputTimeMap.get("year"), + parameterSet.inputTimeMap.get("month") + 1, parameterSet.inputTimeMap.get("date"), + parameterSet.inputTimeMap.get("hourOfDay"), parameterSet.inputTimeMap.get("minute"), + parameterSet.inputTimeMap.get("second"), durationInNano); + ZonedDateTime zonedDate = ZonedDateTime.of(dateTime, parameterSet.inputTimeZone.toZoneId()).toInstant() + .atZone(parameterSet.defaultTimeZone.toZoneId()); + inputTimeString = zonedDate.format((DateTimeFormatter.ofPattern(DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS))); + } else { + inputTimeString = parameterSet.inputTimeString; + } + DateTimeType dt = new DateTimeType(inputTimeString); + if (parameterSet.inputTimeZone == null) { + dt = new DateTimeType(dt.getZonedDateTime().withZoneSameInstant(TimeZone.getDefault().toZoneId())); + } + // Test + assertEquals(parameterSet.expectedResult, dt.toString()); } } diff --git a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/library/types/DateTimeType.java b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/library/types/DateTimeType.java index 48622125e4c..93ddfc43b46 100644 --- a/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/library/types/DateTimeType.java +++ b/bundles/core/org.eclipse.smarthome.core/src/main/java/org/eclipse/smarthome/core/library/types/DateTimeType.java @@ -7,11 +7,15 @@ */ package org.eclipse.smarthome.core.library.types; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Calendar; -import java.util.Date; +import java.util.GregorianCalendar; import java.util.Locale; +import java.util.TimeZone; import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.PrimitiveType; @@ -20,53 +24,88 @@ /** * * @author Kai Kreuzer - Initial contribution + * @author Erdoan Hadzhiyusein - Refactored to use ZonedDateTime */ public class DateTimeType implements PrimitiveType, State, Command { public static final String DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss"; public static final String DATE_PATTERN_WITH_TZ = "yyyy-MM-dd'T'HH:mm:ssz"; + + // this pattern returns the time zone in RFC822 format public static final String DATE_PATTERN_WITH_TZ_AND_MS = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + + public static final String DATE_PATTERN_WITH_TZ_AND_MS_GENERAL = "yyyy-MM-dd'T'HH:mm:ss.SSSz"; public static final String DATE_PATTERN_WITH_TZ_AND_MS_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSX"; - private Calendar calendar; + private ZonedDateTime zonedDateTime; + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_PATTERN); + private final DateTimeFormatter formatterTz = DateTimeFormatter.ofPattern(DATE_PATTERN_WITH_TZ); + private final DateTimeFormatter formatterTzMs = DateTimeFormatter.ofPattern(DATE_PATTERN_WITH_TZ_AND_MS_GENERAL); + private final DateTimeFormatter formatterTzMsRFC = DateTimeFormatter.ofPattern(DATE_PATTERN_WITH_TZ_AND_MS); + private final DateTimeFormatter formatterTzMsIso = DateTimeFormatter.ofPattern(DATE_PATTERN_WITH_TZ_AND_MS_ISO); + + /** + * @deprecated The constructor uses Calendar object hence it doesn't store time zone. A new constructor is + * available. Use {@link #DateTimeType(ZonedDateTime)} instead. + * + * @param calendar - The Calendar object containing the time stamp. + */ + @Deprecated + public DateTimeType(Calendar calendar) { + this.zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), TimeZone.getDefault().toZoneId()) + .withFixedOffsetZone(); + } public DateTimeType() { - this(Calendar.getInstance()); + this(ZonedDateTime.now()); } - public DateTimeType(Calendar calendar) { - this.calendar = (Calendar) calendar.clone(); + public DateTimeType(ZonedDateTime zoned) { + this.zonedDateTime = ZonedDateTime.from(zoned).withFixedOffsetZone(); } - public DateTimeType(String calendarValue) { - Date date = null; + public DateTimeType(String zonedValue) { + ZonedDateTime date = null; try { try { - date = new SimpleDateFormat(DATE_PATTERN_WITH_TZ_AND_MS).parse(calendarValue); - } catch (ParseException fpe3) { + date = ZonedDateTime.parse(zonedValue, formatterTzMsRFC); + } catch (DateTimeParseException tzMsRfcException) { try { - date = new SimpleDateFormat(DATE_PATTERN_WITH_TZ_AND_MS_ISO).parse(calendarValue); - } catch (ParseException fpe4) { + date = ZonedDateTime.parse(zonedValue, formatterTzMsIso); + } catch (DateTimeParseException tzMsException) { try { - date = new SimpleDateFormat(DATE_PATTERN_WITH_TZ).parse(calendarValue); - } catch (ParseException fpe2) { - date = new SimpleDateFormat(DATE_PATTERN).parse(calendarValue); + date = ZonedDateTime.parse(zonedValue, formatterTz); + } catch (DateTimeParseException tzException) { + try { + date = ZonedDateTime.parse(zonedValue, formatterTzMs); + } catch (DateTimeParseException regularFormatException) { + // A ZonedDateTime object cannot be creating by parsing directly a pattern without zone + LocalDateTime localDateTime = LocalDateTime.parse(zonedValue, formatter); + date = ZonedDateTime.of(localDateTime, ZoneId.systemDefault()); + } } } } - } catch (ParseException fpe) { - throw new IllegalArgumentException(calendarValue + " is not in a valid format.", fpe); + } catch (DateTimeParseException invalidFormatException) { + throw new IllegalArgumentException(zonedValue + " is not in a valid format.", invalidFormatException); } if (date != null) { - calendar = Calendar.getInstance(); - calendar.setTime(date); + zonedDateTime = date; } } + /** + * @deprecated The method is deprecated. You can use {@link #getZonedDateTime()} instead. + */ + @Deprecated public Calendar getCalendar() { - return (Calendar) calendar.clone(); + return GregorianCalendar.from(zonedDateTime); + } + + public ZonedDateTime getZonedDateTime() { + return zonedDateTime; } public static DateTimeType valueOf(String value) { @@ -76,14 +115,14 @@ public static DateTimeType valueOf(String value) { @Override public String format(String pattern) { try { - return String.format(pattern, calendar); + return String.format(pattern, zonedDateTime); } catch (NullPointerException npe) { - return new SimpleDateFormat(DATE_PATTERN).format(calendar.getTime()); + return DateTimeFormatter.ofPattern(DATE_PATTERN).format(zonedDateTime); } } public String format(Locale locale, String pattern) { - return String.format(locale, pattern, calendar); + return String.format(locale, pattern, zonedDateTime); } @Override @@ -93,14 +132,14 @@ public String toString() { @Override public String toFullString() { - return new SimpleDateFormat(DATE_PATTERN_WITH_TZ_AND_MS).format(calendar.getTime()); + return zonedDateTime.format(formatterTzMsRFC); } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((calendar == null) ? 0 : calendar.hashCode()); + result = prime * result + ((getZonedDateTime() == null) ? 0 : getZonedDateTime().hashCode()); return result; } @@ -116,14 +155,13 @@ public boolean equals(Object obj) { return false; } DateTimeType other = (DateTimeType) obj; - if (calendar == null) { - if (other.calendar != null) { + if (zonedDateTime == null) { + if (other.zonedDateTime != null) { return false; } - } else if (calendar.compareTo(other.calendar) != 0) { + } else if (zonedDateTime.compareTo(other.zonedDateTime) != 0) { return false; } return true; } - } diff --git a/bundles/io/org.eclipse.smarthome.io.rest.core/src/main/java/org/eclipse/smarthome/io/rest/core/internal/persistence/PersistenceResource.java b/bundles/io/org.eclipse.smarthome.io.rest.core/src/main/java/org/eclipse/smarthome/io/rest/core/internal/persistence/PersistenceResource.java index 03ed3794f69..1a06f8b010e 100644 --- a/bundles/io/org.eclipse.smarthome.io.rest.core/src/main/java/org/eclipse/smarthome/io/rest/core/internal/persistence/PersistenceResource.java +++ b/bundles/io/org.eclipse.smarthome.io.rest.core/src/main/java/org/eclipse/smarthome/io/rest/core/internal/persistence/PersistenceResource.java @@ -65,6 +65,7 @@ * @author Chris Jackson - Initial Contribution and add support for ModifiablePersistenceService * @author Kai Kreuzer - Refactored to use PersistenceServiceRegistryImpl * @author Franck Dechavanne - Added DTOs to ApiResponses + * @author Erdoan Hadzhiyusein - Adapted the convertTime() method to work with the new DateTimeType * */ @Path(PersistenceResource.PATH) @@ -188,7 +189,7 @@ public Response httpPutPersistenceItemData(@Context HttpHeaders headers, private Date convertTime(String sTime) { DateTimeType dateTime = new DateTimeType(sTime); - return dateTime.getCalendar().getTime(); + return Date.from(dateTime.getZonedDateTime().toInstant()); } private Response getItemHistoryDTO(String serviceId, String itemName, String timeBegin, String timeEnd, diff --git a/bundles/ui/org.eclipse.smarthome.ui.test/src/test/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImplTest.java b/bundles/ui/org.eclipse.smarthome.ui.test/src/test/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImplTest.java index 56d909a1fb9..d076dc22c3c 100644 --- a/bundles/ui/org.eclipse.smarthome.ui.test/src/test/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImplTest.java +++ b/bundles/ui/org.eclipse.smarthome.ui.test/src/test/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImplTest.java @@ -167,6 +167,19 @@ public void getLabel_labelWithDate() throws ItemNotFoundException { assertEquals("Label [01.06.2011]", label); } + @Test + public void getLabel_labelWithZonedDate() throws ItemNotFoundException { + String testLabel = "Label [%1$td.%1$tm.%1$tY]"; + Widget w = mock(Widget.class); + Item item = mock(Item.class); + when(w.getLabel()).thenReturn(testLabel); + when(w.getItem()).thenReturn("Item"); + when(registry.getItem("Item")).thenReturn(item); + when(item.getState()).thenReturn(new DateTimeType("2011-06-01T00:00:00Z")); + String label = uiRegistry.getLabel(w); + assertEquals("Label [01.06.2011]", label); + } + @Test public void getLabel_labelWithTime() throws ItemNotFoundException { String testLabel = "Label [%1$tT]"; @@ -176,10 +189,25 @@ public void getLabel_labelWithTime() throws ItemNotFoundException { when(w.getItem()).thenReturn("Item"); when(registry.getItem("Item")).thenReturn(item); when(item.getState()).thenReturn(new DateTimeType("2011-06-01T15:30:59")); + String label = uiRegistry.getLabel(w); assertEquals("Label [15:30:59]", label); } + @Test + public void getLabel_labelWithZonedTime() throws ItemNotFoundException { + String testLabel = "Label [%1$tT]"; + Widget w = mock(Widget.class); + Item item = mock(Item.class); + when(w.getLabel()).thenReturn(testLabel); + when(w.getItem()).thenReturn("Item"); + when(registry.getItem("Item")).thenReturn(item); + when(item.getState()).thenReturn(new DateTimeType("2011-06-01T15:30:59Z")); + + String label = uiRegistry.getLabel(w); + assertEquals("Label [15:30:59]", label); + } + @Test public void getLabel_widgetWithoutLabelAndItem() throws ItemNotFoundException { Widget w = mock(Widget.class); diff --git a/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java b/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java index 40ac0de5e15..2199ef6b04f 100644 --- a/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java +++ b/bundles/ui/org.eclipse.smarthome.ui/src/main/java/org/eclipse/smarthome/ui/internal/items/ItemUIRegistryImpl.java @@ -7,7 +7,8 @@ */ package org.eclipse.smarthome.ui.internal.items; -import java.util.Calendar; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -83,6 +84,7 @@ * @author Kai Kreuzer - Initial contribution and API * @author Chris Jackson * @author Stefan Triller - Method to convert a state into something a sitemap entity can understand + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType * */ public class ItemUIRegistryImpl implements ItemUIRegistry { @@ -356,7 +358,6 @@ public String getLabel(Widget w) { } } } - // The following exception handling has been added to work around a Java bug with formatting // numbers. See http://bugs.sun.com/view_bug.do?bug_id=6476425 // Without this catch, the whole sitemap, or page can not be displayed! @@ -874,9 +875,9 @@ private boolean matchStateToValue(State state, String value, String matchConditi logger.debug("matchStateToValue: Decimal format exception: ", e); } } else if (state instanceof DateTimeType) { - Calendar val = ((DateTimeType) state).getCalendar(); - Calendar now = Calendar.getInstance(); - long secsDif = (now.getTimeInMillis() - val.getTimeInMillis()) / 1000; + ZonedDateTime val = ((DateTimeType) state).getZonedDateTime(); + ZonedDateTime now = ZonedDateTime.now(); + long secsDif = ChronoUnit.SECONDS.between(now, val); try { switch (condition) { diff --git a/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/AstroStateTest.groovy b/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/AstroStateTest.groovy index cb5af0c44de..dfeccdde418 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/AstroStateTest.groovy +++ b/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/AstroStateTest.groovy @@ -12,7 +12,10 @@ import static org.hamcrest.CoreMatchers.* import static org.junit.Assert.* import java.time.LocalDateTime +import java.time.ZoneId +import java.time.ZoneOffset import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter import org.eclipse.smarthome.binding.astro.AstroBindingConstants import org.eclipse.smarthome.binding.astro.internal.calc.MoonCalc @@ -22,6 +25,8 @@ import org.eclipse.smarthome.binding.astro.internal.model.Planet import org.eclipse.smarthome.binding.astro.internal.util.PropertyUtils import org.eclipse.smarthome.binding.astro.test.cases.AstroBindingTestsData; import org.eclipse.smarthome.binding.astro.test.cases.AstroParametrizedTestCases +import org.eclipse.smarthome.core.i18n.TimeZoneProvider +import org.eclipse.smarthome.core.scheduler.CronExpression.DayOfMonthExpressionPart import org.eclipse.smarthome.core.thing.ChannelUID import org.eclipse.smarthome.core.thing.ThingUID import org.eclipse.smarthome.core.types.State @@ -36,13 +41,16 @@ import org.junit.runners.Parameterized.Parameters * @See {@link AstroParametrizedTestCases} * @author Petar Valchev - Initial implementation * @author Svilen Valkanov - Reworked to plain unit tests - * + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ @RunWith(Parameterized.class) class AstroStateTest { private String thingID private String channelId private State expectedState + + // These test result timestamps are adapted for the +03:00 time zone + private static final ZoneId zone = ZoneId.of("+03:00") public AstroStateTest(String thingID, String channelId, State expectedState){ this.thingID = thingID @@ -58,14 +66,24 @@ class AstroStateTest { @Test public void testParametrized(){ + + PropertyUtils.unsetTimeZone(); + + // Anonymous implementation of the service to adapt the time zone to the tested longtitude and latitude + PropertyUtils.setTimeZone(new TimeZoneProvider() { + @Override + ZoneId getTimeZone() { + return ZoneId.of("+03:00"); + } + }) assertStateUpdate(thingID, channelId, expectedState) } private void assertStateUpdate(String thingID, String channelId, State expectedState){ LocalDateTime time = LocalDateTime.of(TEST_YEAR, TEST_MONTH, TEST_DAY,0,0) - ZonedDateTime zonedTime = ZonedDateTime.ofLocal(time,TEST_ZONE_OFSET,null) + ZonedDateTime zonedTime = ZonedDateTime.ofLocal(time, zone, null) Calendar calendar = GregorianCalendar.from(zonedTime) - + Planet planet ThingUID thingUID switch(thingID) { diff --git a/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/cases/AstroParametrizedTestCases.groovy b/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/cases/AstroParametrizedTestCases.groovy index b7d800e087f..898e94d9773 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/cases/AstroParametrizedTestCases.groovy +++ b/extensions/binding/org.eclipse.smarthome.binding.astro.test/src/test/groovy/org/eclipse/smarthome/binding/astro/test/cases/AstroParametrizedTestCases.groovy @@ -11,6 +11,7 @@ import static org.eclipse.smarthome.binding.astro.test.cases.AstroBindingTestsDa import java.text.SimpleDateFormat import java.time.LocalDateTime; +import java.time.ZoneId import java.time.ZoneOffset import java.time.ZonedDateTime @@ -24,11 +25,11 @@ import org.eclipse.smarthome.core.library.types.DecimalType * @author Svilen Valakanov - Added test data from * http://www.suncalc.net and * http://www.mooncalc.org + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ public class AstroParametrizedTestCases { public static final double TEST_LATITUDE = 22.4343 public static final double TEST_LONGITUDE = 54.3225 - public static final ZoneOffset TEST_ZONE_OFSET = ZoneOffset.of("+03:00") public static final int TEST_YEAR = 2016 public static final int TEST_MONTH = 2 public static final int TEST_DAY = 29 @@ -38,11 +39,11 @@ public class AstroParametrizedTestCases { AstroParametrizedTestCases(){ cases[0][0] = TEST_SUN_THING_ID cases[0][1] = "rise#start" - cases[0][2] = getDateTime("2016-02-29T05:46:00") + cases[0][2] = new DateTimeType("2016-02-29T05:46:00+03:00") cases[1][0] = TEST_SUN_THING_ID cases[1][1] = "rise#end" - cases[1][2] = getDateTime("2016-02-29T05:48:00") + cases[1][2] = new DateTimeType("2016-02-29T05:48:00+03:00") cases[2][0] = TEST_SUN_THING_ID cases[2][1] = "rise#duration" @@ -50,11 +51,11 @@ public class AstroParametrizedTestCases { cases[3][0] = TEST_SUN_THING_ID cases[3][1] = "set#start" - cases[3][2] = getDateTime("2016-02-29T17:25:00") + cases[3][2] = new DateTimeType("2016-02-29T17:25:00+03:00") cases[4][0] = TEST_SUN_THING_ID cases[4][1] = "set#end" - cases[4][2] = getDateTime("2016-02-29T17:27:00") + cases[4][2] = new DateTimeType("2016-02-29T17:27:00+03:00") cases[5][0] = TEST_SUN_THING_ID cases[5][1] = "set#duration" @@ -62,11 +63,11 @@ public class AstroParametrizedTestCases { cases[6][0] = TEST_SUN_THING_ID cases[6][1] = "noon#start" - cases[6][2] = getDateTime("2016-02-29T11:37:00") + cases[6][2] = new DateTimeType("2016-02-29T11:37:00+03:00") cases[7][0] = TEST_SUN_THING_ID cases[7][1] = "noon#end" - cases[7][2] = getDateTime("2016-02-29T11:38:00") + cases[7][2] = new DateTimeType("2016-02-29T11:38:00+03:00") cases[8][0] = TEST_SUN_THING_ID cases[8][1] = "noon#duration" @@ -74,11 +75,11 @@ public class AstroParametrizedTestCases { cases[9][0] = TEST_SUN_THING_ID cases[9][1] = "night#start" - cases[9][2] = getDateTime("2016-02-29T18:42:00") + cases[9][2] = new DateTimeType("2016-02-29T18:42:00+03:00") cases[10][0] = TEST_SUN_THING_ID cases[10][1] = "night#end" - cases[10][2] = getDateTime("2016-03-01T04:31:00") + cases[10][2] = new DateTimeType("2016-03-01T04:31:00+03:00") cases[11][0] = TEST_SUN_THING_ID cases[11][1] = "night#duration" @@ -86,11 +87,11 @@ public class AstroParametrizedTestCases { cases[12][0] = TEST_SUN_THING_ID cases[12][1] = "morningNight#start" - cases[12][2] = getDateTime("2016-02-29T00:00:00") + cases[12][2] = new DateTimeType("2016-02-29T00:00:00+03:00") cases[13][0] = TEST_SUN_THING_ID cases[13][1] = "morningNight#end" - cases[13][2] = getDateTime("2016-02-29T04:32:00") + cases[13][2] = new DateTimeType("2016-02-29T04:32:00+03:00") cases[14][0] = TEST_SUN_THING_ID cases[14][1] = "morningNight#duration" @@ -98,11 +99,11 @@ public class AstroParametrizedTestCases { cases[15][0] = TEST_SUN_THING_ID cases[15][1] = "astroDawn#start" - cases[15][2] = getDateTime("2016-02-29T04:32:00") + cases[15][2] = new DateTimeType("2016-02-29T04:32:00+03:00") cases[16][0] = TEST_SUN_THING_ID cases[16][1] = "astroDawn#end" - cases[16][2] = getDateTime("2016-02-29T04:58:00") + cases[16][2] = new DateTimeType("2016-02-29T04:58:00+03:00") cases[17][0] = TEST_SUN_THING_ID cases[17][1] = "astroDawn#duration" @@ -110,11 +111,11 @@ public class AstroParametrizedTestCases { cases[18][0] = TEST_SUN_THING_ID cases[18][1] = "nauticDawn#start" - cases[18][2] = getDateTime("2016-02-29T04:58:00") + cases[18][2] = new DateTimeType("2016-02-29T04:58:00+03:00") cases[19][0] = TEST_SUN_THING_ID cases[19][1] = "nauticDawn#end" - cases[19][2] = getDateTime("2016-02-29T05:24:00") + cases[19][2] = new DateTimeType("2016-02-29T05:24:00+03:00") cases[20][0] = TEST_SUN_THING_ID cases[20][1] = "nauticDawn#duration" @@ -122,11 +123,11 @@ public class AstroParametrizedTestCases { cases[21][0] = TEST_SUN_THING_ID cases[21][1] = "civilDawn#start" - cases[21][2] = getDateTime("2016-02-29T05:24:00") + cases[21][2] = new DateTimeType("2016-02-29T05:24:00+03:00") cases[22][0] = TEST_SUN_THING_ID cases[22][1] = "civilDawn#end" - cases[22][2] = getDateTime("2016-02-29T05:46:00") + cases[22][2] = new DateTimeType("2016-02-29T05:46:00+03:00") cases[23][0] = TEST_SUN_THING_ID cases[23][1] = "civilDawn#duration" @@ -134,11 +135,11 @@ public class AstroParametrizedTestCases { cases[24][0] = TEST_SUN_THING_ID cases[24][1] = "astroDusk#start" - cases[24][2] = getDateTime("2016-02-29T18:16:00") + cases[24][2] = new DateTimeType("2016-02-29T18:16:00+03:00") cases[25][0] = TEST_SUN_THING_ID cases[25][1] = "astroDusk#end" - cases[25][2] = getDateTime("2016-02-29T18:42:00") + cases[25][2] = new DateTimeType("2016-02-29T18:42:00+03:00") cases[26][0] = TEST_SUN_THING_ID cases[26][1] = "astroDusk#duration" @@ -146,11 +147,11 @@ public class AstroParametrizedTestCases { cases[27][0] = TEST_SUN_THING_ID cases[27][1] = "nauticDusk#start" - cases[27][2] = getDateTime("2016-02-29T17:50:00") + cases[27][2] = new DateTimeType("2016-02-29T17:50:00+03:00") cases[28][0] = TEST_SUN_THING_ID cases[28][1] = "nauticDusk#end" - cases[28][2] = getDateTime("2016-02-29T18:16:00") + cases[28][2] = new DateTimeType("2016-02-29T18:16:00+03:00") cases[29][0] = TEST_SUN_THING_ID cases[29][1] = "nauticDusk#duration" @@ -158,11 +159,11 @@ public class AstroParametrizedTestCases { cases[30][0] = TEST_SUN_THING_ID cases[30][1] = "civilDusk#start" - cases[30][2] = getDateTime("2016-02-29T17:27:00") + cases[30][2] = new DateTimeType("2016-02-29T17:27:00+03:00") cases[31][0] = TEST_SUN_THING_ID cases[31][1] = "civilDusk#end" - cases[31][2] = getDateTime("2016-02-29T17:50:00") + cases[31][2] = new DateTimeType("2016-02-29T17:50:00+03:00") cases[32][0] = TEST_SUN_THING_ID cases[32][1] = "civilDusk#duration" @@ -170,11 +171,11 @@ public class AstroParametrizedTestCases { cases[33][0] = TEST_SUN_THING_ID cases[33][1] = "eveningNight#start" - cases[33][2] = getDateTime("2016-02-29T18:42:00") + cases[33][2] = new DateTimeType("2016-02-29T18:42:00+03:00") cases[34][0] = TEST_SUN_THING_ID cases[34][1] = "eveningNight#end" - cases[34][2] = getDateTime("2016-03-01T00:00:00") + cases[34][2] = new DateTimeType("2016-03-01T00:00:00+03:00") cases[35][0] = TEST_SUN_THING_ID cases[35][1] = "eveningNight#duration" @@ -182,11 +183,11 @@ public class AstroParametrizedTestCases { cases[36][0] = TEST_SUN_THING_ID cases[36][1] = "daylight#start" - cases[36][2] = getDateTime("2016-02-29T05:48:00") + cases[36][2] = new DateTimeType("2016-02-29T05:48:00+03:00") cases[37][0] = TEST_SUN_THING_ID cases[37][1] = "daylight#end" - cases[37][2] = getDateTime("2016-02-29T17:25:00") + cases[37][2] = new DateTimeType("2016-02-29T17:25:00+03:00") cases[38][0] = TEST_SUN_THING_ID cases[38][1] = "daylight#duration" @@ -194,11 +195,11 @@ public class AstroParametrizedTestCases { cases[39][0] = TEST_MOON_THING_ID cases[39][1] = "rise#start" - cases[39][2] = getDateTime("2016-02-29T23:00:00") + cases[39][2] = new DateTimeType("2016-02-29T23:00:00+03:00") cases[40][0] = TEST_MOON_THING_ID cases[40][1] = "rise#end" - cases[40][2] = getDateTime("2016-02-29T23:00:00") + cases[40][2] = new DateTimeType("2016-02-29T23:00:00+03:00") cases[41][0] = TEST_MOON_THING_ID cases[41][1] = "rise#duration" @@ -208,13 +209,4 @@ public class AstroParametrizedTestCases { public List getCases(){ return Arrays.asList(cases) } - - - private DateTimeType getDateTime(String timeStamp) { - LocalDateTime dateTime = LocalDateTime.parse(timeStamp) - ZonedDateTime zonedDateTime = ZonedDateTime.ofLocal(dateTime,TEST_ZONE_OFSET,null) - - Calendar calendar = GregorianCalendar.from(zonedDateTime) - return new DateTimeType(calendar) - } } diff --git a/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/AstroHandlerFactory.java b/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/AstroHandlerFactory.java index d703833580a..bbb4df5adee 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/AstroHandlerFactory.java +++ b/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/AstroHandlerFactory.java @@ -9,21 +9,30 @@ import static org.eclipse.smarthome.binding.astro.AstroBindingConstants.*; +import java.time.ZoneId; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.smarthome.binding.astro.handler.AstroThingHandler; import org.eclipse.smarthome.binding.astro.handler.MoonHandler; import org.eclipse.smarthome.binding.astro.handler.SunHandler; +import org.eclipse.smarthome.binding.astro.internal.util.PropertyUtils; +import org.eclipse.smarthome.core.i18n.LocationProvider; +import org.eclipse.smarthome.core.i18n.TimeZoneProvider; +import org.eclipse.smarthome.core.library.types.PointType; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; /** * The {@link AstroHandlerFactory} is responsible for creating things and thing handlers. @@ -37,6 +46,7 @@ public class AstroHandlerFactory extends BaseThingHandlerFactory { .concat(SunHandler.SUPPORTED_THING_TYPES.stream(), MoonHandler.SUPPORTED_THING_TYPES.stream()) .collect(Collectors.toSet()); private static final Map astroThingHandlers = new HashMap<>(); + private TimeZoneProvider timeZoneProvider; @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -46,8 +56,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { @Override protected ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - AstroThingHandler thingHandler = null; - + AstroThingHandler thingHandler = null; if (thingTypeUID.equals(THING_TYPE_SUN)) { thingHandler = new SunHandler(thing); } else if (thingTypeUID.equals(THING_TYPE_MOON)) { @@ -65,6 +74,15 @@ public void unregisterHandler(Thing thing) { astroThingHandlers.remove(thing.getUID().toString()); } + @Reference + protected void setTimeZoneProvider(TimeZoneProvider timeZone) { + PropertyUtils.setTimeZone(timeZone); + } + + protected void unsetTimeZoneProvider(TimeZoneProvider timeZone) { + PropertyUtils.unsetTimeZone(); + } + public static AstroThingHandler getHandler(String thingUid) { return astroThingHandlers.get(thingUid); } diff --git a/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/util/PropertyUtils.java b/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/util/PropertyUtils.java index 6d491a6ebbc..a67fd4606b6 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/util/PropertyUtils.java +++ b/extensions/binding/org.eclipse.smarthome.binding.astro/src/main/java/org/eclipse/smarthome/binding/astro/internal/util/PropertyUtils.java @@ -10,10 +10,14 @@ import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.ZonedDateTime; import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; import org.apache.commons.lang.StringUtils; import org.eclipse.smarthome.binding.astro.internal.config.AstroChannelConfig; +import org.eclipse.smarthome.core.i18n.TimeZoneProvider; import org.eclipse.smarthome.core.library.types.DateTimeType; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.StringType; @@ -25,6 +29,7 @@ * Methods to get the value from a property of an object. * * @author Gerhard Riegler - Initial contribution + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ public class PropertyUtils { @@ -33,6 +38,8 @@ private PropertyUtils() { throw new IllegalAccessError("Non-instantiable"); } + private static TimeZoneProvider timeZoneProvider; + /** * Returns the state of the channel. */ @@ -42,7 +49,10 @@ public static State getState(ChannelUID channelUID, AstroChannelConfig config, O return UnDefType.UNDEF; } else if (value instanceof Calendar) { Calendar cal = (Calendar) value; - return new DateTimeType(DateTimeUtils.applyConfig(cal, config)); + GregorianCalendar gregorianCal = (GregorianCalendar) DateTimeUtils.applyConfig(cal, config); + cal.setTimeZone(TimeZone.getTimeZone(timeZoneProvider.getTimeZone())); + ZonedDateTime zoned = gregorianCal.toZonedDateTime().withFixedOffsetZone(); + return new DateTimeType(zoned); } else if (value instanceof Number) { BigDecimal decimalValue = new BigDecimal(value.toString()).setScale(2, RoundingMode.HALF_UP); return new DecimalType(decimalValue); @@ -52,7 +62,15 @@ public static State getState(ChannelUID channelUID, AstroChannelConfig config, O throw new RuntimeException("Unsupported value type " + value.getClass().getSimpleName()); } } + + public static void setTimeZone (TimeZoneProvider zone) { + PropertyUtils.timeZoneProvider=zone; + } + public static void unsetTimeZone() { + PropertyUtils.timeZoneProvider=null; + } + /** * Returns the property value from the object instance, nested properties are possible. If the propertyName is for * example rise.start, the methods getRise().getStart() are called. diff --git a/extensions/binding/org.eclipse.smarthome.binding.ntp.test/src/test/java/org/eclipse/smarthome/binding/ntp/test/NtpOSGiTest.java b/extensions/binding/org.eclipse.smarthome.binding.ntp.test/src/test/java/org/eclipse/smarthome/binding/ntp/test/NtpOSGiTest.java index aa93730ac70..6888885fa12 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.ntp.test/src/test/java/org/eclipse/smarthome/binding/ntp/test/NtpOSGiTest.java +++ b/extensions/binding/org.eclipse.smarthome.binding.ntp.test/src/test/java/org/eclipse/smarthome/binding/ntp/test/NtpOSGiTest.java @@ -7,13 +7,17 @@ */ package org.eclipse.smarthome.binding.ntp.test; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Locale; import java.util.TimeZone; @@ -52,7 +56,6 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; /** @@ -60,6 +63,7 @@ * * @author Petar Valchev - Initial Contribution * @author Markus Rathgeb - Migrated tests from Groovy to pure Java + * @author Erdoan Hadzhiyusein - Migrated tests to Java 8 and integrated the new DateTimeType */ public class NtpOSGiTest extends JavaOSGiTest { private static TimeZone systemTimeZone; @@ -75,7 +79,7 @@ public class NtpOSGiTest extends JavaOSGiTest { private ThingRegistry thingRegistry; private ItemRegistry itemRegistry; - private static final String DEFAULT_TIME_ZONE_ID = "Europe/Helsinki"; + private static final ZoneId DEFAULT_TIME_ZONE_ID = ZoneId.of("Europe/Bucharest"); private static final String TEST_TIME_ZONE_ID = "America/Los_Angeles"; private static final String TEST_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss z"; @@ -186,48 +190,43 @@ public void testStringChannelTimeZoneUpdate() { is(anyOf(equalTo(expectedTimeZonePDT), equalTo(expectedTimeZonePST)))); } - @Ignore("the dateTime channel is updated with a time from the system timezone") @Test public void testDateTimeChannelTimeZoneUpdate() { - final String expectedTimeZone = "-0700"; Configuration configuration = new Configuration(); configuration.put(NtpBindingConstants.PROPERTY_TIMEZONE, TEST_TIME_ZONE_ID); initialize(configuration, NtpBindingConstants.CHANNEL_DATE_TIME, ACCEPTED_ITEM_TYPE_DATE_TIME, null, null); String testItemState = getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME).toString(); - /* - * There is no way to format the date in the dateTime channel in - * advance(there is no property for formatting in the dateTime channel), - * so we will rely on the format, returned by the toString() method of - * the DateTimeType. - */ - // FIXME: Adapt the tests if property for formatting in the dateTime - // channel is added. assertFormat(testItemState, DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS); - /* - * Because of the format from the toString() method, the time zone will - * be the last five symbols of the string from the item registry(e.g. - * "+0300" or "-0700"). - */ - String timeZoneFromItemRegistry = testItemState.substring(testItemState.length() - expectedTimeZone.length()); + ZonedDateTime timeZoneFromItemRegistry = ((DateTimeType) getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME)) + .getZonedDateTime(); + ZoneOffset expectedOffset; + if (timeZoneFromItemRegistry.getZone().getRules().isDaylightSavings(timeZoneFromItemRegistry.toInstant())) { + expectedOffset = ZoneOffset.of("-07:00"); + } else { + expectedOffset = ZoneOffset.of("-08:00"); + } - assertThat("The dateTime channel was not updated with the right timezone", timeZoneFromItemRegistry, - is(equalTo(expectedTimeZone))); + assertThat("The dateTime channel was not updated with the right timezone", timeZoneFromItemRegistry.getOffset(), + is(equalTo(expectedOffset))); } - @Ignore("the time zone in the calendar is lost after the serialization of the state") @Test public void testDateTimeChannelCalendarTimeZoneUpdate() { Configuration configuration = new Configuration(); configuration.put(NtpBindingConstants.PROPERTY_TIMEZONE, TEST_TIME_ZONE_ID); - initialize(configuration, NtpBindingConstants.CHANNEL_DATE_TIME, ACCEPTED_ITEM_TYPE_DATE_TIME, null); - - String timeZoneIdFromItemRegistry = ((DateTimeType) getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME)).getCalendar() - .getTimeZone().getID(); - - assertThat("The dateTime channel calendar was not updated with the right timezone", timeZoneIdFromItemRegistry, - is(equalTo(TEST_TIME_ZONE_ID))); + initialize(configuration, NtpBindingConstants.CHANNEL_DATE_TIME, ACCEPTED_ITEM_TYPE_DATE_TIME, null, null); + ZonedDateTime timeZoneIdFromItemRegistry = ((DateTimeType) getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME)) + .getZonedDateTime(); + ZoneOffset testZoneId; + if (timeZoneIdFromItemRegistry.getZone().getRules().isDaylightSavings(timeZoneIdFromItemRegistry.toInstant())) { + testZoneId = ZoneOffset.of("-07:00"); + } else { + testZoneId = ZoneOffset.of("-08:00"); + } + assertThat("The dateTime channel calendar was not updated with the right timezone", + timeZoneIdFromItemRegistry.getOffset(), is(equalTo(testZoneId))); } @Test @@ -254,25 +253,16 @@ public void testStringChannelDefaultTimeZoneUpdate() { @Test public void testDateTimeChannelDefaultTimeZoneUpdate() { - Calendar systemCalendar = Calendar.getInstance(); - String expectedTimeZone = getDateTimeChannelTimeZone(new DateTimeType(systemCalendar).toString()); + ZonedDateTime zoned = ZonedDateTime.now(); + ZoneOffset expectedTimeZone = zoned.getOffset(); Configuration configuration = new Configuration(); // Initialize with configuration with no time zone property set. initialize(configuration, NtpBindingConstants.CHANNEL_DATE_TIME, ACCEPTED_ITEM_TYPE_DATE_TIME, null, null); String testItemState = getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME).toString(); - /* - * There is no way to format the date in the dateTime channel in - * advance(there is no property for formatting in the dateTime channel), - * so we will rely on the format, returned by the toString() method of - * the DateTimeType. - */ - // FIXME: Adapt the tests if property for formatting in the dateTime - // channel is added. assertFormat(testItemState, DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS); - - String timeZoneFromItemRegistry = getDateTimeChannelTimeZone(testItemState); + ZoneOffset timeZoneFromItemRegistry = new DateTimeType(testItemState).getZonedDateTime().getOffset(); assertThat("The dateTime channel was not updated with the right timezone", timeZoneFromItemRegistry, is(equalTo(expectedTimeZone))); @@ -284,21 +274,27 @@ public void testDateTimeChannelCalendarDefaultTimeZoneUpdate() { // Initialize with configuration with no time zone property set. initialize(configuration, NtpBindingConstants.CHANNEL_DATE_TIME, ACCEPTED_ITEM_TYPE_DATE_TIME, null, null); - String timeZoneIdFromItemRegistry = ((DateTimeType) getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME)).getCalendar() - .getTimeZone().getID(); + ZonedDateTime timeZoneIdFromItemRegistry = ((DateTimeType) getItemState(ACCEPTED_ITEM_TYPE_DATE_TIME)) + .getZonedDateTime(); + ZoneOffset expectedOffset; - assertThat("The dateTime channel calendar was not updated with the right timezone", timeZoneIdFromItemRegistry, - is(equalTo(DEFAULT_TIME_ZONE_ID))); + if (timeZoneIdFromItemRegistry.getZone().getRules().isDaylightSavings(timeZoneIdFromItemRegistry.toInstant())) { + expectedOffset = ZoneOffset.of("+03:00"); + } else { + expectedOffset = ZoneOffset.of("+02:00"); + } + + assertThat("The dateTime channel calendar was not updated with the right timezone", + timeZoneIdFromItemRegistry.getOffset(), is(equalTo(expectedOffset))); } @Test public void testStringChannelFormatting() { - final String formatPattern = "EEE, d MMM yyyy HH:mm:ss Z"; + final String formatPattern = "EEE, d MMM yyyy HH:mm:ss z"; Configuration configuration = new Configuration(); Configuration channelConfig = new Configuration(); channelConfig.put(NtpBindingConstants.PROPERTY_DATE_TIME_FORMAT, formatPattern); - initialize(configuration, NtpBindingConstants.CHANNEL_STRING, ACCEPTED_ITEM_TYPE_STRING, channelConfig, null); String dateFromItemRegistry = getItemState(ACCEPTED_ITEM_TYPE_STRING).toString(); @@ -392,6 +388,8 @@ private void initialize(Configuration configuration, String channelID, String ac private void initialize(Configuration configuration, String channelID, String acceptedItemType, Configuration channelConfiguration) { + + configuration.put(NtpBindingConstants.PROPERTY_NTP_SERVER_PORT, TEST_PORT); ThingUID ntpUid = new ThingUID(NtpBindingConstants.THING_TYPE_NTP, TEST_THING_ID); ChannelUID channelUID = new ChannelUID(ntpUid, channelID); @@ -401,8 +399,6 @@ private void initialize(Configuration configuration, String channelID, String ac } else { channel = new Channel(channelUID, acceptedItemType); } - - configuration.put(NtpBindingConstants.PROPERTY_NTP_SERVER_PORT, TEST_PORT); ntpThing = ThingBuilder.create(NtpBindingConstants.THING_TYPE_NTP, ntpUid).withConfiguration(configuration) .withChannel(channel).build(); @@ -456,42 +452,19 @@ private State getItemState(String acceptedItemType) { }, 3 * DFL_TIMEOUT, 2 * DFL_SLEEP_TIME); } - private String getDateTimeChannelTimeZone(String date) { - /* - * Because of the format from the toString() method, the time zone will - * be the last five symbols of the string from the item registry(e.g. - * "+0300" or "-0700"). - */ - return date.substring(date.length() - 5); - } - private String getStringChannelTimeZoneFromItemRegistry() { String itemState = getItemState(ACCEPTED_ITEM_TYPE_STRING).toString(); - /* - * This method is used only in tests for the string channel, where we - * have set the format for the date in advance. Because of that format, - * we know that the time zone will be the last word of the string from - * the item registry. - */ - // FIXME: This can happen a lot easier with Java 8 date time API, so - // tests can be adapted, if there is an - // upgrade to Java 8 String timeZoneFromItemRegistry = StringUtils.substringAfterLast(itemState, " "); return timeZoneFromItemRegistry; } private void assertFormat(String initialDate, String formatPattern) { - SimpleDateFormat dateFormat = new SimpleDateFormat(formatPattern); - - final Date date; - try { - date = dateFormat.parse(initialDate); - } catch (ParseException e) { - fail("An exception $e was thrown, while trying to parse the date $initialDate"); - throw new IllegalStateException("already failed"); - } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern); + + final ZonedDateTime date; + date = ZonedDateTime.parse(initialDate, formatter); - String formattedDate = dateFormat.format(date); + String formattedDate = formatter.format(date); assertThat("The default formatting was not used", formattedDate, is(equalTo(initialDate))); } diff --git a/extensions/binding/org.eclipse.smarthome.binding.ntp/src/main/java/org/eclipse/smarthome/binding/ntp/handler/NtpHandler.java b/extensions/binding/org.eclipse.smarthome.binding.ntp/src/main/java/org/eclipse/smarthome/binding/ntp/handler/NtpHandler.java index e1b64d18b6a..c45dd4e245c 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.ntp/src/main/java/org/eclipse/smarthome/binding/ntp/handler/NtpHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.ntp/src/main/java/org/eclipse/smarthome/binding/ntp/handler/NtpHandler.java @@ -15,6 +15,8 @@ import java.net.UnknownHostException; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; import java.util.Locale; @@ -49,6 +51,7 @@ * @author Marcel Verpaalen - Initial contribution OH2 ntp binding * @author Thomas.Eichstaedt-Engelen OH1 ntp binding (getTime routine) * @author Markus Rathgeb - Add locale provider + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ public class NtpHandler extends BaseThingHandler { @@ -204,8 +207,9 @@ private synchronized void refreshTimeDate() { Calendar calendar = Calendar.getInstance(timeZone, locale); calendar.setTimeInMillis(networkTimeInMillis); + ZonedDateTime zoned = ZonedDateTime.of(LocalDateTime.now(), timeZone.toZoneId()); - updateState(dateTimeChannelUID, new DateTimeType(calendar)); + updateState(dateTimeChannelUID, new DateTimeType(zoned)); updateState(stringChannelUID, new StringType(dateTimeFormat.format(calendar.getTime()))); } else { logger.debug("Not refreshing, since we do not seem to be initialized yet"); diff --git a/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoCoffeeHandler.java b/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoCoffeeHandler.java index 65acbdee4a4..ed10d38bb29 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoCoffeeHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoCoffeeHandler.java @@ -12,12 +12,14 @@ import java.io.StringReader; import java.math.BigDecimal; import java.net.URL; +import java.time.Instant; +import java.time.ZonedDateTime; import java.util.Collection; import java.util.Collections; -import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -61,6 +63,7 @@ * sent to one of the channels and to update their states. * * @author Hans-Jörg Merk - Initial contribution + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ public class WemoCoffeeHandler extends BaseThingHandler implements UpnpIOParticipant, DiscoveryListener { @@ -464,9 +467,8 @@ public State getDateTimeState(String attributeValue) { getThing().getUID()); return null; } - GregorianCalendar brewCal = new GregorianCalendar(); - brewCal.setTimeInMillis(value); - State dateTimeState = new DateTimeType(brewCal); + ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value), TimeZone.getDefault().toZoneId()); + State dateTimeState = new DateTimeType(zoned); if (dateTimeState != null) { logger.trace("New attribute brewed '{}' received", dateTimeState); return dateTimeState; diff --git a/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoHandler.java b/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoHandler.java index 80094a3f2e9..5c6ced5b216 100644 --- a/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoHandler.java +++ b/extensions/binding/org.eclipse.smarthome.binding.wemo/src/main/java/org/eclipse/smarthome/binding/wemo/handler/WemoHandler.java @@ -12,12 +12,14 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URL; +import java.time.Instant; +import java.time.ZonedDateTime; import java.util.Collection; import java.util.Collections; -import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -54,6 +56,7 @@ * @author Hans-Jörg Merk - Initial contribution; Added support for WeMo Insight energy measurement * @author Kai Kreuzer - some refactoring for performance and simplification * @author Stefan Bußweiler - Added new thing status handling + * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ public class WemoHandler extends BaseThingHandler implements UpnpIOParticipant, DiscoveryListener { @@ -246,9 +249,9 @@ public void onValueReceived(String variable, String value, String service) { logger.error("Unable to parse lastChangedAt value '{}' for device '{}'; expected long", splitInsightParams[1], getThing().getUID()); } - GregorianCalendar cal = new GregorianCalendar(); - cal.setTimeInMillis(lastChangedAt); - State lastChangedAtState = new DateTimeType(cal); + ZonedDateTime zoned= ZonedDateTime.ofInstant(Instant.ofEpochMilli(lastChangedAt), TimeZone.getDefault().toZoneId()); + + State lastChangedAtState = new DateTimeType(zoned); if (lastChangedAt != 0) { logger.trace("New InsightParam lastChangedAt '{}' for device '{}' received", lastChangedAtState, getThing().getUID());