Как разобрать .net DateTime, полученный как строку json, в объект Date Java

Я получаю объект .NET DateTime в виде строки json через свой веб-сервис asmx и пытаюсь проанализировать его с помощью библиотеки gson. Но похоже, что нет поддержки для синтаксического анализа DateTime в стиле .net. Как я могу легко разобрать его в объект Date java с помощью Gson без особых хлопот?

строка, которую я получаю, похожа на:

"DateOfBirth":"\/Date(736032869080)\/"

P.S. Я не хотел бы вносить какие-либо изменения на стороне сервера, чтобы получать DateTime как длинное значение.


person waqaslam    schedule 03.02.2012    source источник
comment
К сведению: иногда я получаю что-то вроде "\/Date(1327875714113-0800)\/", так что вы можете принять это во внимание.   -  person nielsbot    schedule 04.02.2012
comment
Блин... Какой гений в Microsoft сказал себе - Сегодня я собираюсь создать несовместимый и бессмысленный стандарт с плохой читабельностью... как будто они никогда не слышали об ISO8601.   -  person Jens    schedule 04.02.2012


Ответы (5)


Так:

String json = "\"\\/Date(736032869080)\\/\"";
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new NetDateTimeAdapter()).create();
System.out.println("Date=" + gson.fromJson(json, Date.class));

class NetDateTimeAdapter extends TypeAdapter<Date> {
    @Override
    public Date read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
            reader.nextNull();
            return null;
        }
        Date result = null;
        String str = reader.nextString();
        str = str.replaceAll("[^0-9]", "");
        if (!TextUtils.isEmpty(str)) {
            try {
                result = new Date(Long.parseLong(str));
            } catch (NumberFormatException e) {
            }
        }
        return result;
    }
    @Override
    public void write(JsonWriter writer, Date value) throws IOException {
        // Nah..
    }
}

Или используйте вместо этого этот пример и следуйте инструкциям "Работа с датами WCF Microsoft JSON. " глава.

person Jens    schedule 03.02.2012
comment
Ссылка 404s, и Firefox кажется недовольным подлинностью ссылки - person Diederik; 26.06.2012
comment
@Diederik - гниение ссылок всегда весело. - person Jens; 26.06.2012

Я реализовал это, взаимодействуя с форматом .NET WCF DateTime Json. С часовым поясом

  • "/Дата(12345678989+0000)/"
  • "/Дата(12345678989-0000)/"
  • "/Дата(-12345678989+0000)/"
  • "/Дата(-12345678989-0000)/"

Без часового пояса UTC

  • "/Дата(12345678989)/"
  • "/Дата(-12345678989)/"

Сначала вам нужно добавить в свой проект

1) Библиотека Google Gson GSON

2) Библиотека JodaTime JodaTime Используйте до JDK8.

В JDK8 или более поздних версиях вместо этого используйте java.time.

Основной класс

package tests;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.joda.time.DateTime;

/**
 *
 * @author Joma Espinoza Bone.
 */
public class JsonSerializerDeserializer {

    private static Gson handler = null;

    public static void initialize(Boolean useDotNetFormat) {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(DateTime.class, new DateTimeSerializer(useDotNetFormat));
        builder.registerTypeAdapter(DateTime.class, new DateTimeDeserializer(useDotNetFormat));
        handler = builder.create();
    }

    private JsonSerializerDeserializer() {

    }

    public static <T> String serialize(T instance, Boolean useDotNetFormat) {
        initialize(useDotNetFormat);
        if (useDotNetFormat) {
            return (handler.toJson(instance, instance.getClass())).replace("/", "\\/");
        } else {
            return handler.toJson(instance, instance.getClass());
        }
    }

    public static <T> T deserialize(String json, Class<T> resultType) {
        initialize(json.contains("\\/Date("));
        return handler.fromJson(json, resultType);
    }
}

Сериализатор DateTime

package tests;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;

/**
 *
 * @author Joma Espinoza Bone.
 */
public class DateTimeSerializer implements JsonSerializer<DateTime> {

        private Boolean toDotNetFormat;

        private DateTimeSerializer() {
        }

        public DateTimeSerializer(Boolean isInDotNetFormat) {
            this.toDotNetFormat = isInDotNetFormat;
        }

        @Override
        public JsonElement serialize(DateTime t, Type type, JsonSerializationContext jsc) {
            if (t.getZone() != DateTimeZone.UTC) {
                int offset = t.getZone().getOffsetFromLocal(t.getMillis());
                t = t.toDateTime(DateTimeZone.UTC).plus(offset);
            }
            return toDotNetFormat ? new JsonPrimitive(Strings.format("/Date({0})/", t.getMillis())) : new JsonPrimitive(t.toString(ISODateTimeFormat.dateTime()));
        }
    }

Десериализатор DateTime

package tests;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

/**
 *
 * @author Joma Espinoza Bone.
 */
public class DateTimeDeserializer implements JsonDeserializer<DateTime> {

    Boolean isInDotNetFormat;

    private DateTimeDeserializer() {
    }

    public DateTimeDeserializer(Boolean isInDotNetFormat) {
        this();
        this.isInDotNetFormat = isInDotNetFormat;
    }

    @Override
    public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        String jsonString = json.getAsJsonPrimitive().getAsString();
        if (isInDotNetFormat) {
            String Regexp = "\\/Date\\((\\-?\\d*?)([\\+\\-]\\d*)?\\)\\/";
            Pattern MyPattern = Pattern.compile(Regexp);
            Matcher MyMatcher = MyPattern.matcher(jsonString);
            MyMatcher.matches();
            Long time = new Long(MyMatcher.group(1));
            if (Strings.isNullOrWhiteSpace(MyMatcher.group(2))) {
                return new DateTime(time, DateTimeZone.UTC);
            } else {
                Integer offsetHours = Integer.parseInt(MyMatcher.group(2).substring(0, 3));
                Integer offsetMinutes = Integer.parseInt(MyMatcher.group(2).substring(3, MyMatcher.group(2).length()));
                int offset = DateTimeZone.forOffsetHoursMinutes(offsetHours, offsetMinutes).getOffsetFromLocal(time);
                return new DateTime(time + offset).toDateTime(DateTimeZone.UTC);
            }

        } else {
            DateTime t = DateTime.parse(jsonString.substring(0, jsonString.length()));
            if (t.getZone() != DateTimeZone.UTC) {
                int offset = t.getZone().getOffsetFromLocal(t.getMillis());
                t = t.toDateTime(DateTimeZone.UTC).plus(offset);
            }
            return t;
        }
    }
}

Перейдите к Regex101. Протестируйте это регулярное выражение

Пример класса для сериализации

package tests;

import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;

/**
 *
 * @author Joma Espinoza Bone.
 */
public class MyClass {

    private DateTime DateTime;
    private String Names;

    public DateTime getDateTime() {
        return DateTime;
    }

    public void setDateTime(DateTime DateTime) {
        this.DateTime = DateTime;
    }

    public String getNames() {
        return Names;
    }

    public void setNames(String Names) {
        this.Names = Names;
    }



    @Override
    public String toString() {
        return "Names: " + Names + " // DateTime: " + DateTime.toString(ISODateTimeFormat.dateTime());
    }
}

и мой основной/тестовый класс

package tests;

import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;

/**
 *
 * @author Joma Espinoza Bone.
 */
public class Tests {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        DateTime dateTime = new DateTime();//new DateTime(1467880743533L, DateTimeZone.forOffsetHours(-5));
        System.out.println(dateTime.toString(ISODateTimeFormat.dateTime()));
        String json = JsonSerializerDeserializer.serialize(dateTime, Boolean.TRUE);
        System.out.println(json);
        dateTime = JsonSerializerDeserializer.deserialize(json, DateTime.class);
        System.out.println(dateTime.toString(ISODateTimeFormat.dateTime()));

        MyClass obj = new MyClass();
        DateTime datetime = new DateTime(new Date(115, 5, 18, 18, 5, 14));//new Date(Calendar.getInstance().getTimeInMillis());
        obj.setDateTime(datetime);
        obj.setNames("Joma");
        String jsonDotNet = JsonSerializerDeserializer.serialize(obj, true);
        String jsonJava = JsonSerializerDeserializer.serialize(obj, Boolean.FALSE);
        System.out.println("Json DotNet:  " + jsonDotNet);
        System.out.println("Json Java:  " + jsonJava);
        System.out.println("Deserialized DotNet:  " + JsonSerializerDeserializer.deserialize(jsonDotNet, MyClass.class).toString());
        System.out.println("Deserialized Java:  " + JsonSerializerDeserializer.deserialize(jsonJava, MyClass.class).toString());

        //18/06/2015 21:35:45 Generated from DotNet Date with TimeZone.
        String json1 = "{\"DateTime\":\"\\/Date(1434681345267-0500)\\/\",\"Names\":\"Joma\"}";
        //18/06/2015 21:35:45 Generated from JsonSerializerDeserializer.serialize(Object instance, Boolean ToDotNetFormat) DotNetFormat without TimeZone.
        String json2 = "{\"DateTime\":\"\\/Date(1434663345267)\\/\",\"Names\":\"Joma\"}";
        // Java DateTime with TimeZone.
        String json3 = "{\"DateTime\":\"2016-07-07T16:40:27.720-05:00\",\"Names\":\"Joma\"}";
        //Java DateTime without TimeZone - UTC
        String json4 = "{\"DateTime\":\"2016-07-07T16:40:27.720Z\",\"Names\":\"Joma\"}";
        System.out.println("Deserialized 1: " + JsonSerializerDeserializer.deserialize(json1, MyClass.class));
        System.out.println("Deserialized 2: " + JsonSerializerDeserializer.deserialize(json2, MyClass.class));
        System.out.println("Deserialized 3: " + JsonSerializerDeserializer.deserialize(json3, MyClass.class));
        System.out.println("Deserialized 4: " + JsonSerializerDeserializer.deserialize(json4, MyClass.class));
    }

}

Мой полезный/вспомогательный класс

package tests;

/**
 * Created by Joma on 17/06/2015.
 */
public class Strings
{
    public static Boolean isNullOrEmpty(String value)
    {
        if (value != null)
        {
            return value.length() == 0;
        }
        else
        {
            return true;
        }
    }


    public static Boolean isNullOrWhiteSpace(String value)
    {
        if (value == null)
        {
            return true;
        }

        if (value.trim().length() == 0)
        {
            return true;
        }
        else

        {
            return false;
        }

    }

    public static String format(String format, Object... params)
    {
        for(int i = 0; i< params.length; i++)
        {
            format = format.replaceAll(String.format("\\{%s\\}", i), params[i].toString());
        }
        return format;
    }
}

Примечание: *

Все значения DateTime при сериализации/десериализации преобразуются в формат UTC.

*

person Joma    schedule 19.06.2015
comment
Это было полезно, спасибо! Единственное изменение, которое мне пришлось внести, было в Regex для даты. Служба API, которую я вызываю, иногда возвращает дату, например /Date(-12345678901-0400)/, поэтому мне пришлось учитывать дополнительные - в начале с помощью этого регулярного выражения \/(Date\(([\-]?.*?)((\+|\-).*)?\))\/ - person LukeP; 12.08.2015
comment
Запускаю фрагмент кода десериализации dataTime //18.06.2015 21:35:45 Сгенерировано из DotNet Date with TimeZone. Дата(1434681345267-0500) - person gfan; 17.08.2016
comment
Я запускаю фрагмент кода десериализации dataTime. Я выбираю тестовый код в вашем тестовом классе //18/06/2015 21:35:45 Сгенерировано из DotNet Date with TimeZone. String json1 ....Date(1434681345267-0500) Результат даты в java соответствует вашим комментариям, но когда я запускаю ту же строку даты в .net (используя Newtonsoft.Json.dll версии 4.5 на С#), я получаю дату 19.06.2015 10:35:45. Час другой. Я запускаю код 17.08.2016 +0800 на своем локальном компьютере. - person gfan; 17.08.2016

Я реализовал GsonHelper, который помогает десериализовать и сериализовать формат .NET DateTime из JSON с помощью GSON. Применение:

// How to get DataClass object from JSON string
Gson gson = new GsonHelper().getGson();
DataClass DATA = gson.fromJson(YOUR_JSON, DataClass.class);

// How to get JSON string from your JSON data
Gson gson = new GsonHelper().getGson();
String JSON = gson.toJson(DATA);

Это вспомогательный класс:

public class GsonHelper 
{   
    public Gson getGson()
    {
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(Date.class, new DotNetDateDeserializer());
        builder.registerTypeAdapter(Date.class, new DotNetDateSerializer());
        return builder.create();
    }

    public class DotNetDateDeserializer implements JsonDeserializer<Date> 
    {
        @Override
        public Date deserialize(JsonElement json, Type typfOfT, JsonDeserializationContext context)
        {
            try
            {
                String dateStr = json.getAsString();
                if (dateStr != null) dateStr = dateStr.replace("/Date(", "");
                if (dateStr != null) dateStr = dateStr.replace("+0000)/", "");
                if (dateStr != null) dateStr = dateStr.replace(")/", "");
                long time = Long.parseLong(dateStr);
                return new Date(time);
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
                return null;
            }

        }
    }

    public class DotNetDateSerializer implements JsonSerializer<Date> 
    {
        @Override
        public JsonElement serialize(Date date, Type typfOfT, JsonSerializationContext context)
        {
            if (date == null)
                return null;

            String dateStr = "/Date(" + date.getTime() + ")/";
            return new JsonPrimitive(dateStr);
        }
    }

Примечание. работает для двух форматов: /Date(1362853251000)/ и /Date(1362853251000+0000)/. Помощник должен быть настроен для других форматов с определенным временем.

person peter.bartos    schedule 10.03.2013
comment
Ваша датаStr.replace(+0000)/, ); не является безопасным часовым поясом. Например, в моем случае это было +0100. В остальном мне кажется хорошо - person Bart Burg; 30.12.2014

Чтобы вручную преобразовать дату .NET JSON в объект JodaTime DateTime (аналогичный собственный тип Java), вы также можете использовать регулярное выражение:

public static DateTime parseDotNetTime(String json) {
    DateTime result = null;
    if (json != null) {
        Pattern datePatt = Pattern.compile("^/Date\\((\\d+)([+-]\\d+)?\\)/$");
        Matcher m = datePatt.matcher(json);
        if (m.matches()) {
            Long l = Long.parseLong(m.group(1));
            result = new DateTime(l);
            // Time zone is not needed to calculate date
        } else {
            throw new IllegalArgumentException("Wrong date format");
        }
    }
    return result;
}
person Tarnschaf    schedule 13.05.2014

Не знаю ... Я пробовал все вышеперечисленное ... но у меня не получилось. наконец, я пришел с этим решением :)

когда вы получаете строку из строки объекта json, она будет выглядеть так: «/Date (1373543393598+0200)/». но если вы увидите строку результата, которая исходит с сервера, она будет выглядеть так: {"respDateTime":"/Date(1373267484478+0200)/"}

String json = "/Date(1373543393598+0200)/"; 
json=json.replace("/Date(", "").replace("+0200)/", "");
long time = Long.parseLong(json);
Date d= new Date(time); 
person user840153    schedule 11.07.2013
comment
Это будет работать только до тех пор, пока производитель находится в часовом поясе +0200, в противном случае вы, вероятно, получите исключение формата. Подумайте об использовании регулярного выражения, чтобы сделать его безопасным. - person Tarnschaf; 13.05.2014