package example.support.morphia;

import org.mongodb.morphia.converters.SimpleValueConverter;
import org.mongodb.morphia.converters.TypeConverter;
import org.mongodb.morphia.mapping.MappedField;

import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;

/**
 * Morphia converter for JDK Date Time objects with timezone info : {@link ZonedDateTime} and {@link OffsetDateTime}.
 *
 * @author pgentile
 */
public class ZonedDateTimeConverter extends TypeConverter implements SimpleValueConverter {

    public ZonedDateTimeConverter() {
        super(ZonedDateTime.class, OffsetDateTime.class);
    }

    @Override
    public Object decode(final Class<?> targetClass, final Object fromDBObject, final MappedField optionalExtraInfo) {
        if (fromDBObject == null) {
            return null;
        }

        if (targetClass == ZonedDateTime.class) {
            if (fromDBObject instanceof Date) {
                return ZonedDateTime.ofInstant(((Date) fromDBObject).toInstant(), ZoneId.systemDefault());
            }
        }

        if (targetClass == OffsetDateTime.class) {
            if (fromDBObject instanceof Date) {
                return OffsetDateTime.ofInstant(((Date) fromDBObject).toInstant(), ZoneId.systemDefault());
            }
        }

        throw createUnsupportedTypeException("Decode", fromDBObject);
    }

    @Override
    public Object encode(final Object value, final MappedField optionalExtraInfo) {
        if (value == null) {
            return null;
        }

        if (value instanceof ZonedDateTime) {
            return Date.from(((ZonedDateTime) value).toInstant());
        }
        if (value instanceof OffsetDateTime) {
            return Date.from(((OffsetDateTime) value).toInstant());
        }
        throw createUnsupportedTypeException("Encode", value);
    }

    private static IllegalArgumentException createUnsupportedTypeException(final String context, final Object value) {
        return new IllegalArgumentException(context + ": unsupported type " + value.getClass() + " for value " + value);
    }

}

@@ -189,16 +189,42 @@
 Field;%0A%0A
+import java.time.Instant;%0A
 import j
@@ -1110,190 +1110,581 @@
     
-%7D%0A%0A        if (targetClass == OffsetDateTime.class) %7B%0A            if (fromDBObject instanceof Date) %7B%0A                return OffsetDateTime.ofInstant(((Date) fromDBObject).toInstant(
+    if (fromDBObject instanceof Number) %7B%0A                return ZonedDateTime.ofInstant(Instant.ofEpochMilli(((Number) fromDBObject).longValue()), ZoneId.systemDefault());%0A            %7D%0A        %7D%0A%0A        if (targetClass == OffsetDateTime.class) %7B%0A            if (fromDBObject instanceof Date) %7B%0A                return OffsetDateTime.ofInstant(((Date) fromDBObject).toInstant(), ZoneId.systemDefault());%0A            %7D%0A            if (fromDBObject instanceof Number) %7B%0A                return OffsetDateTime.ofInstant(Instant.ofEpochMilli(((Number) fromDBObject).longValue()
 ), Z

Convert number (millis from epoch) to OffsetDateTime or ZonedDateTime