Returning JSON With Date

I've been scripting a few RPC calls in a module of ours, and I would ultimately like to return a Document/JSON object that will contain a few dates inside of it. I thought using java.util.Date would be best to work with the rest of Ignition, but when I return my data it's treated as a PyUnicode object in designer instead of a native date. What's the right way to return a date?

For the most part, I've been using Gson to return a JsonTree whenever I'm returning a dictionary to Perspective and it seems to natively work except for dates.

return gson.toJsonTree(...myReturnPOJOHere);

You need to register a type adapter when you build your GSON instance that has serialization logic for a Date.

    public static class DateAdapter implements JsonDeserializer<Date>, JsonSerializer<Date> {

        @Override
        public Date deserialize(JsonElement jsonElement, Type type,
                                JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            if (jsonElement.isJsonPrimitive()) {
                if (jsonElement.getAsJsonPrimitive().isNumber()) {
                    return new Date(jsonElement.getAsJsonPrimitive().getAsLong());
                } else {
                    return TypeUtilities.toDate(jsonElement.getAsString());
                }
            }
            throw new JsonParseException("Unable to parse as date.");
        }

        @Override
        public JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) {
            return new JsonPrimitive(date.getTime());
        }
    }
1 Like

Ok so we did that with Instants before but I was thinking it'd be nice to return it as a native date. I can see in a view json that you have something like:

    "startDate": {
      "$": [
        "ts",
        201,
        1747668532860
      ],
      "$ts": 1747075096000
    }

If I were to return a structure like that would it work as a native date?

What does the 201 mean? :sweat_smile:

Where do you get this JSON? This is not a standard format to represent a timestamp or date.

I don't think the JSON standard specifies how dates should be represented. There are conventions that people have somewhat standardized on, but you'll still need to define a TypeAdapter like Kevin suggested.

Another option for representation (instead of long) is a string that represents your date format (i.e. "MM/DD/YYYY"), but that leaves a bit more room for error (but is much easier to read).

EDIT: The format in this Stack Overflow answer is what we used at my last job-- it's fairly standard and easy to read. https://stackoverflow.com/a/15952652

1 Like

There is no such thing as a "native date" in JSON. You have to invent a representation.

In this context you're talking about JSON as a serialization format, so the representation can be anything as long as both sides agree on it.

3 Likes

Ah sorry - I was meaning a java.util.Date. Basically so I can take a date out of the json object I pass and pass it right back into a different script endpoint on another screen.

That's the type adapter solution I gave you.

3 Likes

For Perspective components, I’ve been using toJsonDeep with the DollarQualified format.

1 Like

If the desired end result is the format you posted above, BindingUtils is the way to go; what you have above is the 'dollar qualified' format Carl invented that attaches qualified values (quality code + timestamp) and some type metadata to objects.

1 Like

Ok, I explored a few different options and in the end I'm just going to return the instant long. The "dollar qualified" format returned it how I wanted in perspective, but the same script wouldn't work in a normal gateway/designer python script, so determined it would be better for interoperability to return a long directly and have the user convert to java.util.Date in python if needed.