nl.vpro.xml.bind.InstantXmlAdapter Maven / Gradle / Ivy
package nl.vpro.xml.bind;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Locale;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import nl.vpro.util.TimeUtils;
import nl.vpro.xml.util.XmlUtils;
/**
* JDK-8042456
* Use like so
*
* {@code
* @XmlAttribute
* @XmlJavaTypeAdapter(InstantXmlAdapter.class)
* @XmlSchemaType(name = "dateTime")
* private Instant lastModified;
*}
* @author Michiel Meeuwissen
* @since 0.21
*/
public class InstantXmlAdapter extends XmlAdapter {
public static final ThreadLocal OMIT_MILLIS_IF_ZERO = ThreadLocal.withInitial(() -> true);
private final static DateTimeFormatter formatter =
DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ")
.withLocale(Locale.US)
.withZone(XmlUtils.DEFAULT_ZONE);
private final static DateTimeFormatter formatterNoMillis =
DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ssZZZZZ")
.withLocale(Locale.US)
.withZone(XmlUtils.DEFAULT_ZONE);
@Override
public Instant unmarshal(String dateValue) {
return TimeUtils.parse(dateValue).orElse(null);
}
@Override
public String marshal(Instant value) {
return toXMLFormat(value);
}
public static String toXMLFormat(Instant value) {
if (value == null) {
return null;
}
if (value.getNano() == 0 && OMIT_MILLIS_IF_ZERO.get()) {
return formatterNoMillis.format(value);
} else {
return formatWithMillis(value);
}
}
static String formatWithMillis(Instant instant) {
if (instant == null) {
return null;
}
return formatter.format(
// round to millis
instant.plusNanos(500_000).truncatedTo(ChronoUnit.MILLIS));
}
}