Reputation: 9296
In my Grails app, the original date read from the database is equal to:
{ endDate=2015-10-19 19:00:00.0}
While the JSON result is:
{"endDate": "2015-10-19T16:00:00Z"}
I think this is maybe related to time zone conversion. How could I show the original date without any timezone conversions in JSON?
Upvotes: 2
Views: 728
Reputation: 2512
Working on an old application that is built with grails 2.3.11 in which for some unbeknownst reason @Dónal's solution wasn't working. Fortunately, I found an easier/more straightforward approach to register a custom marshaller on mrhaki's blog.
So, I made a copy of the default DateMarshaller that resides in org.codehaus.groovy.grails.web.converters.marshaller.json and modified the date formatter in my custom DateMarshaller and then registered the marshaller using the snippet below, taken from mrhaki's post.
dateMarshaller(ObjectMarshallerRegisterer) {
// Assign custom marshaller instance.
marshaller = new DateMarshaller()
// Set converter class type.
converterClass = JSON
// Optional set priority. Default value is 0.
priority = 1
}
Just make sure that your Custom Marshaller has a higher priority than the default one. Works like a charm!
Upvotes: 0
Reputation: 187499
Depending on which time zone you're in, 2015-10-19 19:00:00.0
and 2015-10-19T16:00:00Z
may not be different times, they may be just different representations of the same time (instant).
In my case, I use a custom marshaller to ensure that times in my API's JSON response always use the UTC time zone. My custom marshaller looks like this:
import org.springframework.stereotype.Component
@Component
class DateMarshaller implements CustomMarshaller {
@Override
def getSupportedTypes() {
Date
}
@Override
Closure getMarshaller() {
{ Date date ->
TimeZone tz = TimeZone.getTimeZone('UTC')
date?.format("yyyy-MM-dd'T'HH:mm:ss'Z'", tz)
}
}
}
Remember to register the package this marshaller is in for Spring bean scanning in Config.groovy
. The interface it implements is:
interface CustomMarshaller {
/**
* Indicates the type(s) of object that this marshaller supports
* @return a {@link Class} or collection of {@link Class}
* if the marshaller supports multiple types
*/
def getSupportedTypes()
Closure getMarshaller()
}
Then I have a service that registers all my instances of CustomMarshaller
for the relevant type(s):
import grails.converters.JSON
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import javax.annotation.PostConstruct
class MarshallerRegistrarService implements ApplicationContextAware {
static transactional = false
ApplicationContext applicationContext
// a combination of eager bean initialization and @PostConstruct ensures that the marshallers are registered when
// the app (or a test thereof) starts
boolean lazyInit = false
@PostConstruct
void registerMarshallers() {
Map<String, CustomMarshaller> marshallerBeans = applicationContext.getBeansOfType(CustomMarshaller)
marshallerBeans.values().each { CustomMarshaller customMarshaller ->
customMarshaller.supportedTypes.each { Class supportedType ->
JSON.registerObjectMarshaller supportedType, customMarshaller.marshaller
}
}
}
}
This is a fairly involved solution, but In my case I'm using Grails 2.5.X. If I was using Grails 3.X I'd try to use JSON views instead.
Upvotes: 5
Reputation: 2488
If my memory is correct, JSON spec does not actually define a format for date format. But everybody uses ISO 8601, so it sort of de-facto standard. And most just always use Zulu time zone.
I searched myself some time ago, on ways to force Grails JSON to render dates in certain time zone, but failed. In my Grails web app, I just declare date fields as text and format them to proper time zone and format in my own code. On the good side, it also has an added benefit that you can guarantee it to stay that way in future. (I'm, using Grails since about 1.1 and did see breaking changes on several occasions.)
Upvotes: 0