How to include time zone in Web API 2 JSON dates? - json

How do I configure the JSON dates produced by my Web API 2 Controller to include the time zone?
Data type used for dates in SQL Server are datetime and I don’t have the option of changing the Legacy database.

Breeze uses Json.NET to serialize/deserialize json. You can configure the serializer settings that Breeze uses by creating a custom class that inherits from Breeze.ContextProvider.BreezeConfig. Breeze will automatically discover this class and create an instance of it for all configuration tasks.
Something like this:
public class CustomBreezeConfig : Breeze.ContextProvider.BreezeConfig
{
protected override Newtonsoft.Json.JsonSerializerSettings CreateJsonSerializerSettings()
{
var ret = base.CreateJsonSerializerSettings();
ret.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
// ret.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
return ret;
}
}
But before you go down this path please read this (the response specifically):
breezejs: date is not set to the right time

Try returning your DateTime formatted with .ToString() and use a custom date and time format like "K". See: http://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx#KSpecifier for more information.

Related

How do you control how the Couchbase Java client serializes Dates?

Here's my code (Couchbase Java SDK 3)
Cluster cluster = Cluster.connect("localhost", "Administrator", "password");
Collection c = cluster.bucket("default").defaultCollection();
c.upsert("myDocumentId", new Date());
When I look at the resulting document in Couchbase, I see the java.util.Date has been converted to epoch milliseconds:
1602791214674
What I want instead is for the date to be formatted like yyyy-mm-dd.
How can I make that happen?
By default, the Couchbase Java client uses Jackson to serialize and deserialize JSON. Unless you tell it otherwise, it will use an ObjectMapper with default settings. By default, Jackson serializes java.util.Date objects by converting them to milliseconds since the epoch.
You have a couple of choices. If you're using a POJO to represent your document content, you can apply Jackson annotations to the date fields to control how they are [de]serialized. Here's an article that shows how to use the #JsonFormat annotation to control how a date field is serialized.
Alternatively, you can configure an ObjectMapper to change the default way dates are serialized. Here's how you tell the Couchbase Java SDK to use your custom ObjectMapper:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
ClusterEnvironment env = ClusterEnvironment.builder()
.jsonSerializer(JacksonJsonSerializer.create(objectMapper))
.build();
Cluster cluster = Cluster.connect("localhost",
ClusterOptions.clusterOptions("Administrator", "password")
.environment(env));
Collection c = cluster.bucket("default").defaultCollection();
c.upsert("myDocumentId", new Date());
cluster.disconnect();
// since we created a custom environment, we're responsible for shutting it down
env.shutdown();
This will give you a document that looks like:
"2020-10-15T19:59:45.685+0000"
If you want a different format, you can configure Jackson to serialize dates however you want.

JsonSerializer fails to de-serialize DateTimes in Azure Function

I have an Azure Function that receives some JSON from a queue, fx.
{"FromDate":"2020-05-26T07:15:00.3714532+00:00","ToDate":"2020-06-25T07:15:00.3714532+00:00"}
Using System.Text.Json.JsonSerializer I am trying to de-serialize this JSON into an object of the following type:
public class DateRange
{
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
}
The de-serialization:
var dateRange = JsonSerializer.Deserialize<DateRange>(json);
This does not work in Azure - FromDate and ToDate are always parsed to the default date 1/1/0001 12:00:00 AM. The strange thing is that the JSON is created from another Azure Function with JsonSerializer.Serialize(dateRange).
But if I run the Azure Function locally it does work.
It seems from the documentation, that the date/time format
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm"
sent in the JSON is supported (which makes sense because it is created by JsonSerializer.Serialize()).
Why does it fail to de-serialize my JSON? And why does it work locally but not on Azure?
Are you using a queue which is bonded as an input to your function (and triggers it)? Could you show how you write the serialized string to queue and then how you read it from the queue before deserialization?
Are you sure that the string which is taken from the message looks exactly like in your example?
I am asking because the messages in queues bound to functions are expected to be base64 encoded which causes a lot of issues if you forget about this. And since it works locally, I would blame the transport mechanism (queue) for changing the behavior.

How to modify spring/jackson JSON deserialisation

I'm trying to figure out how to adjust the way spring/jackson convert a JSON string (stored in a file) into various POJOs. For example, if I have this JSON:
{
"rates":{
"EURUSD":5.4321,
"USDHKD":1.2345
}
}
I actually want to get an instance of my 'Rates' class. Inside that I want a List containing each individual rate.
In my spring config file I created this entry:
#Bean
public ObjectMapper jsonObjectMapper() {
return new MappingJackson2HttpMessageConverter().getObjectMapper();
}
And in my service class I did this:
#Autowired
ObjectMapper jsonObjectMapper;
public Rates currentRates() {
Resource resource = this.ctx.getResource("classpath:stub/data/rates/Rates-01.json");
return this.jsonObjectMapper.readValue(resource.getURL(), Rates.class);
}
The problem is that I am trying to figure out how to take the Map containing the currencies as a single key, break those currencies in two and then create a RateEntry object containing the two currencies and the rate, before populating a list in the Rates class.
I've been looking at Spring's Conversion Service with the idea to define a converter that maps the Map to a list. i.e. this signature: Converter<Map<String, BigDecimal>, List<Rate>>. However this is based on the assumption that the JSON is first converted to standard types before the conversion service is called. An assumption I now think is incorrect.
So I'm now trying to figure out if I need to register some sort of custom ObjectMapper to handle reading directly from the JSON String data. But that sounds like over kill as I only want to adjust part of the object graph, and let the default converters handle the rest.
Any pointers appreciated. Thanks.
Ok, Jackson tries to stay away from structural transformations (since it's a quick-sand pit with unlimited number of general permutations). But it might be possible to use some existing features to do what you want.
First: to use Object key to indicate type, you will probably want to enable polymorphic type handling with "as object wrapper" inclusion.
So add something like:
#JsonTypeInfo(as=Include.WRAPPER_OBJECT)
for your Rates class declaration.
As to converting values into list; this might work by defining "any-setter" (see http://www.cowtowncoder.com/blog/archives/2011/07/entry_458.html), something like:
#JsonAnySetter
public void set(String key, Double value) // or "Object value")
{
list.add(new Rate(key, value));
}
I hope this helps.

Json .net settings equivalent to JavaScriptSerializer default for dates

I am using the JQuery Ganntt plugin and it needs dates formatted in the Unix epoch format. Using Newtonsoft's Json.Net with these settings
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
return JsonConvert.SerializeObject(headers, microsoftDateFormatSettings);
I get json that looks like the following
[{"desc":"STAT","name":"Status","values":[{"to":"/Date(1357483427000-0500)/","from":"/Date(1354891427000-0500)/","desc":"","label":"Implement","customClass":"ganttBlue","dataObj":{"id":35,"projectId":18705,"updatedById":437996,"updatedByName":"Linda","updated":"/Date(1354891427000-0500)/","statusId":160,"statusDescription":"","status":"Implement"}}]},{"desc":"ASGNTO","name":"Assigned To","values":[{"to":"/Date(1357762454000-0500)/","from":"/Date(1355170454000-0500)/","desc":"Suzy","label":"Suzy","customClass":"ganttRed","dataObj":{"id":55,"projectId":18705,"updatedById":719816,"updatedByName":"Joe","updated":"/Date(1355170454000-0500)/","assignedToId":561260,"assignedToName":"Suzy"}}]}]
The gantt plugin does not like the date with the -500. It wants this, which is generated from using the JavaScriptSerializer
"[{\"desc\":\"STAT\",\"name\":\"Status\",\"values\":[{\"to\":\"\/Date(1357483427000)\/\",\"from\":\"\/Date(1354891427000)\/\",\"description\":\"\",\"label\":\"Implement\",\"customClass\":\"ganttBlue\",\"dataObj\":{\"Id\":35,\"ProjectId\":18705,\"UpdatedById\":437996,\"UpdatedByName\":\"Linda\",\"Updated\":\"\/Date(1354891427000)\/\",\"StatusId\":160,\"StatusDescription\":\"\",\"Status\":\"Implement\"}}]},{\"desc\":\"ASGNTO\",\"name\":\"Assigned To\",\"values\":[{\"to\":\"\/Date(1357762454000)\/\",\"from\":\"\/Date(1355170454000)\/\",\"description\":\"Suzy\",\"label\":\"Suzy\",\"customClass\":\"ganttRed\",\"dataObj\":{\"Id\":55,\"ProjectId\":18705,\"UpdatedById\":719816,\"UpdatedByName\":\"Joe\",\"Updated\":\"\/Date(1355170454000)\/\",\"AssignedToId\":561260,\"AssignedToName\":\"Suzy\"}}]}]"
What would be the proper setting for the Json.Net converter? I want to use Json.net when we move to .net 4.5.
To make it display a date that is like the one produced by JavaScriptSerializer, you have to give two settings:
JsonSerializerSettings serializerSettings = new JsonSerializerSettings()
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc
};
Using any other type of DateTimeZoneHandling will cause the timezone offset to be put in. (Seems like a bug that Unspecified still puts the offset in.)
However, if you are using local time throughout the system, doing this will shift the dates by your timezone offset when serializing them. Your dates will be off.
The easiest fix for me was to use the default ISO date, set DateTimeZoneHandling to Local, and change the client to parse the ISO date. Otherwise you would need to adjust the dates before serializing or play with your own custom serializer. Neither of those last two seemed worth it to me.

WinRT serializing a DateTimeOffset

I'm working on a Windows 8 Metro application that references a c# WinRT project. Among other things, the c# project makes web requests to an Azure service to perform CRUD operations against a SQL Azure database.
When performing a POST operation on the service, I'm serializing an instance of a class and putting it in the body of the request.
public sealed class Foo
{
int FooId { get; set; }
DateTimeOffset FooDate { get; set; }
}
When this is serialized using the DataContractJSONSerializer, the result is something like this:
{"FooId":1,"FooDate":{"DateTime":"/Date(1342732970000)/","OffsetMinutes":-420}}
FYI that this is 7/19/2012 2:22:50PM -07:00.
OK great ... Only problem is that the Azure service is expecting just a DateTime, not a DateTimeOffset. I don't own the Azure service so I can't change its behavior.
So (ignoring that I'm losing the offset) what I need is this to serialize into:
{"FooId":1,"FooDate":"/Date(1342732970)/"}
My first approach was to add a new aliased DateTime property/datamember to the class with a getter that returns the DateTime portion of the DateTimeOffset. However, WinRT doesn't support the DateTime type.
There are a couple of hacky ways to get around this, but I wanted to see if there's an elegant way to do this before resorting to one of these:
Regex on the serialization result before the POST
String property on the class that returns a JSON formatted date
Thanks
I ended up implementing a property on the class with a getter that formats the date appropriately.
I decorated the Foo field with the IgnoreDataMember attribute so that it gets ignored during serialization. I then added a new field and gave it the alias of Foo for serialization.
Thanks