Skip to content

Commit

Permalink
ZoneOffset support added to Converter
Browse files Browse the repository at this point in the history
  • Loading branch information
jdereg committed Feb 5, 2024
1 parent 5b6a7d1 commit 58cbbbe
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/main/java/com/cedarsoftware/util/convert/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.AbstractMap;
import java.util.Calendar;
Expand Down Expand Up @@ -678,6 +679,7 @@ private static void buildFactoryConversions() {
DEFAULT_FACTORY.put(pair(YearMonth.class, String.class), StringConversions::toString);
DEFAULT_FACTORY.put(pair(Period.class, String.class), StringConversions::toString);
DEFAULT_FACTORY.put(pair(ZoneId.class, String.class), StringConversions::toString);
DEFAULT_FACTORY.put(pair(ZoneOffset.class, String.class), StringConversions::toString);
DEFAULT_FACTORY.put(pair(OffsetTime.class, String.class), OffsetTimeConversions::toString);
DEFAULT_FACTORY.put(pair(OffsetDateTime.class, String.class), OffsetDateTimeConversions::toString);
DEFAULT_FACTORY.put(pair(Year.class, String.class), YearConversions::toString);
Expand Down Expand Up @@ -718,7 +720,12 @@ private static void buildFactoryConversions() {
DEFAULT_FACTORY.put(pair(String.class, ZoneId.class), StringConversions::toZoneId);
DEFAULT_FACTORY.put(pair(Map.class, ZoneId.class), MapConversions::toZoneId);

// java.time.ZoneOffset = com.cedarsoftware.util.io.DEFAULT_FACTORY.ZoneOffsetFactory
// ZoneOffset conversions supported
DEFAULT_FACTORY.put(pair(Void.class, ZoneOffset.class), VoidConversions::toNull);
DEFAULT_FACTORY.put(pair(ZoneOffset.class, ZoneOffset.class), Converter::identity);
DEFAULT_FACTORY.put(pair(String.class, ZoneOffset.class), StringConversions::toZoneOffset);
DEFAULT_FACTORY.put(pair(Map.class, ZoneOffset.class), MapConversions::toZoneOffset);

// java.time.ZoneRegion = com.cedarsoftware.util.io.DEFAULT_FACTORY.ZoneIdFactory

// MonthDay conversions supported
Expand Down Expand Up @@ -838,6 +845,7 @@ private static void buildFactoryConversions() {
DEFAULT_FACTORY.put(pair(YearMonth.class, Map.class), YearMonthConversions::toMap);
DEFAULT_FACTORY.put(pair(Period.class, Map.class), PeriodConversions::toMap);
DEFAULT_FACTORY.put(pair(ZoneId.class, Map.class), ZoneIdConversions::toMap);
DEFAULT_FACTORY.put(pair(ZoneOffset.class, Map.class), ZoneOffsetConversions::toMap);
DEFAULT_FACTORY.put(pair(Class.class, Map.class), MapConversions::initMap);
DEFAULT_FACTORY.put(pair(UUID.class, Map.class), MapConversions::initMap);
DEFAULT_FACTORY.put(pair(Calendar.class, Map.class), MapConversions::initMap);
Expand Down Expand Up @@ -875,6 +883,7 @@ public Converter(ConverterOptions options) {
* many other JDK classes, including Map. For Map, often it will seek a 'value'
* field, however, for some complex objects, like UUID, it will look for specific
* fields within the Map to perform the conversion.
* @see #getSupportedConversions()
* @return An instanceof targetType class, based upon the value passed in.
*/
public <T> T convert(Object from, Class<T> toType) {
Expand Down Expand Up @@ -907,6 +916,7 @@ public <T> T convert(Object from, Class<T> toType) {
* fields within the Map to perform the conversion.
* @param options ConverterOptions - allows you to specify locale, ZoneId, etc. to support conversion
* operations.
* @see #getSupportedConversions()
* @return An instanceof targetType class, based upon the value passed in.
*/
@SuppressWarnings("unchecked")
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/cedarsoftware/util/convert/MapConversions.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ public final class MapConversions {
private static final String DAY = "day";
private static final String DAYS = "days";
private static final String HOUR = "hour";
private static final String HOURS = "hours";
private static final String MINUTE = "minute";
private static final String MINUTES = "minutes";
private static final String SECOND = "second";
private static final String SECONDS = "seconds";
private static final String NANO = "nano";
Expand Down Expand Up @@ -336,6 +338,19 @@ static ZoneId toZoneId(Object from, Converter converter, ConverterOptions option
}
}

private static final String[] ZONE_OFFSET_PARAMS = new String[] { HOURS, MINUTES, SECONDS };
static ZoneOffset toZoneOffset(Object from, Converter converter, ConverterOptions options) {
Map<String, Object> map = (Map<String, Object>) from;
if (map.containsKey(HOURS)) {
int hours = converter.convert(map.get(HOURS), int.class, options);
int minutes = converter.convert(map.get(MINUTES), int.class, options); // optional
int seconds = converter.convert(map.get(SECONDS), int.class, options); // optional
return ZoneOffset.ofHoursMinutesSeconds(hours, minutes, seconds);
} else {
return fromValueForMultiKey(from, converter, options, ZoneOffset.class, ZONE_OFFSET_PARAMS);
}
}

static Year toYear(Object from, Converter converter, ConverterOptions options) {
return fromSingleKey(from, converter, options, YEAR, Year.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -407,6 +408,19 @@ static ZoneId toZoneId(Object from, Converter converter, ConverterOptions option
}
}

static ZoneOffset toZoneOffset(Object from, Converter converter, ConverterOptions options) {
String s = StringUtilities.trimToNull(asString(from));
if (s == null) {
return null;
}
try {
return ZoneOffset.of(s);
}
catch (Exception e) {
throw new IllegalArgumentException("Unknown time-zone offset: '" + s + "'");
}
}

static OffsetDateTime toOffsetDateTime(Object from, Converter converter, ConverterOptions options) {
String s = StringUtilities.trimToNull(asString(from));
if (s == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.cedarsoftware.util.convert;

import java.time.ZoneOffset;
import java.util.Map;

import com.cedarsoftware.util.CompactLinkedMap;

/**
* @author John DeRegnaucourt ([email protected])
* <br>
* Copyright (c) Cedar Software LLC
* <br><br>
* 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
* <br><br>
* <a href="http://www.apache.org/licenses/LICENSE-2.0">License</a>
* <br><br>
* 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.
*/
public final class ZoneOffsetConversions {

private ZoneOffsetConversions() {}

static Map toMap(Object from, Converter converter, ConverterOptions options) {
ZoneOffset offset = (ZoneOffset) from;
Map<String, Object> target = new CompactLinkedMap<>();
int totalSeconds = offset.getTotalSeconds();

// Calculate hours, minutes, and seconds
int hours = totalSeconds / 3600;
int minutes = (totalSeconds % 3600) / 60;
int seconds = totalSeconds % 60;
target.put("hours", hours);
target.put("minutes", minutes);
if (seconds != 0) {
target.put("seconds", seconds);
}
return target;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -364,6 +365,32 @@ class ConverterEverythingTest
{ mapOf("_v", TOKYO_Z), TOKYO_Z },
{ mapOf("zone", mapOf("_v", TOKYO_Z)), TOKYO_Z },
});

// ZoneOffset
TEST_FACTORY.put(pair(Void.class, ZoneOffset.class), new Object[][] {
{ null, null },
});
TEST_FACTORY.put(pair(ZoneOffset.class, ZoneOffset.class), new Object[][] {
{ ZoneOffset.of("-05:00"), ZoneOffset.of("-05:00") },
{ ZoneOffset.of("+5"), ZoneOffset.of("+05:00") },
});
TEST_FACTORY.put(pair(String.class, ZoneOffset.class), new Object[][] {
{ "-00:00", ZoneOffset.of("+00:00") },
{ "-05:00", ZoneOffset.of("-05:00") },
{ "+5", ZoneOffset.of("+05:00") },
{ "+05:00:01", ZoneOffset.of("+05:00:01") },
{ "America/New_York", new IllegalArgumentException("Unknown time-zone offset: 'America/New_York'") },
});
TEST_FACTORY.put(pair(Map.class, ZoneOffset.class), new Object[][] {
{ mapOf("_v", "-10"), ZoneOffset.of("-10:00") },
{ mapOf("hours", -10L), ZoneOffset.of("-10:00") },
{ mapOf("hours", -10L, "minutes", "0"), ZoneOffset.of("-10:00") },
{ mapOf("hrs", -10L, "mins", "0"), new IllegalArgumentException("Map to ZoneOffset the map must include one of the following: [hours, minutes, seconds], [_v], or [value]") },
{ mapOf("hours", -10L, "minutes", "0", "seconds", 0), ZoneOffset.of("-10:00") },
{ mapOf("hours", "-10", "minutes", (byte)-15, "seconds", "-1"), ZoneOffset.of("-10:15:01") },
{ mapOf("hours", "10", "minutes", (byte)15, "seconds", true), ZoneOffset.of("+10:15:01") },
{ mapOf("hours", mapOf("_v","10"), "minutes", mapOf("_v", (byte)15), "seconds", mapOf("_v", true)), ZoneOffset.of("+10:15:01") }, // full recursion
});
}

@BeforeEach
Expand Down

0 comments on commit 58cbbbe

Please sign in to comment.