Abdul Wahab
Abdul Wahab

Reputation: 169

How to change timezone with Offset when Deserializing DateTime using JSON.NET in Azure APIM?

I'm using Azure APIM policy expression to aggregate multiple responses. In that one of the JSON response contains multiple dateTime fields. all of them are in UTC TZ. I want to deserialize all of the date fields to specific Timezone(in my case SGT +08:00) from +00:00

Input:

{
    "Header": {
        "UserID": "xxxxxx",
        "MessageID": "xxxxxx",
        "CorrelationID": "xxxx",
        "DateTime": "2018-02-12T15:31:18+00:00",
        "ReqID": "xxx"
    },
    "ResultSet": {
        "Tier": {
            "CardSuffix": "91",
            "RetentionDeadline": "2022-02-27T16:00:00+00:00",
            "PointsRequireToQualify": "xxxxx",
            "QualifyingDeadline": "2022-02-27T16:00:00+00:00",
            "SignupDate": "2020-08-07",
            "IssuedDate": "2021-06-15",
            "JoiningDateTime": "2010-03-31T10:10:00+00:00",
            "RequireToUpgradeInYear": "288886",
            "YearlyUpgradeDeadline": "2022-02-27T16:00:00+00:00",
            "CurrentCardDesc": "xxxxxxxx",
            "NextCardDesc": "xxxxxxxxx",
            "CurrentTierPoints": "0",
            "UpdatedDateTime": "2023-01-09T17:43:54.844+00:00",
            "LastRefreshedDateTime": "2022-02-10T07:45:13+00:00"
        }
    }
}

Expected Output:

{
    "Header": {
        "UserID": "xxxxxx",
        "MessageID": "xxxxxx",
        "CorrelationID": "xxxx",
        "DateTime": "2018-02-12T15:31:18+08:00",
        "ReqID": "xxx"
    },
    "ResultSet": {
        "Tier": {
            "CardSuffix": "91",
            "RetentionDeadline": "2022-02-28T0:00:00+08:00",
            "PointsRequireToQualify": "xxxxx",
            "QualifyingDeadline": "2022-02-28T0:00:00+08:00",
            "SignupDate": "2020-08-07",
            "IssuedDate": "2021-06-15",
            "JoiningDateTime": "2010-03-31T10:10:00+08:00",
            "RequireToUpgradeInYear": "288886",
            "YearlyUpgradeDeadline": "2022-02-28T0:00:00+08:00",
            "CurrentCardDesc": "xxxxxxxx",
            "NextCardDesc": "xxxxxxxxx",
            "CurrentTierPoints": "0",
            "UpdatedDateTime": "2023-01-10T22:08:08+08:00",
            "LastRefreshedDateTime": "2022-02-10T15:45:13+08:00"
        }
    }
}

I have tried and achieved the expected output by using ConvertTimeBySystemTimeZoneId(DateTimeOffset, String) Method, But real Problem is I don't want to add each individual Property name to change the time zone with Offset. I need generic efficient solution that deserialize DateTime fields to Specific TimeZone with the format .ToString("yyyy-MM-ddTH:mm::sszzz")

Here's my fiddle: sample

If you see my above sample, I have parse the input as JObject and converts to required format for the first property alone obj["ResultSet"]["Tier"]["RetentionDeadline"] which changed from "RetentionDeadline": "2022-02-27T16:00:00+00:00", to "RetentionDeadline": "2022-02-28T0:00:00+08:00",

Problem with this solution: If any new DateField is added in the backend response, I need to revisit my policy expression again and do this manual conversion. So I want generic one time conversion for all dateTime fields.

Please note that I'm writing this inside policy expression; so I can't reuse the functionality by using any c# extensions or helper methods.

Upvotes: 1

Views: 352

Answers (2)

Abdul Wahab
Abdul Wahab

Reputation: 169

Update: My backend has been sending proper TimeZone data.

If your response has a Proper DateTime field with TimeZone and you want to keep the original value in TimeZone, this DateParseHandling = DateParseHandling.None can be used.

Below is an example Snippet.

https://dotnetfiddle.net/AlPJmk

This could be useful to someone.

Upvotes: 0

Markus Meyer
Markus Meyer

Reputation: 3967

You can do this by looping over the children of the JSON object:

var obj = context.Request.Body.AsJObject(true, new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None } );
foreach (JProperty x in (JToken)obj["ResultSet"]["Tier"])
{}

DateParseHandling is used for the date format does not change.

A very simple Regex is used to recognize dates 2022-02-27T:

^[0-9]{4}-[0-9]{2}-[0-9]{2}T

Complete policy:

<policies>
    <inbound>
        <base />
        <return-response>
            <set-status code="200" reason="OK" />
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            </set-header>
            <set-body>@{   
                var obj = context.Request.Body.AsJObject(true, new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None } );

                var pattern = @"^[0-9]{4}-[0-9]{2}-[0-9]{2}T";
                var regex = new Regex(pattern);

                foreach (JProperty x in (JToken)obj["ResultSet"]["Tier"])
                { 
                    string name = x.Name;
                    JToken tokenValue = x.Value;

                    if(regex.IsMatch(tokenValue.ToString()))
                    {
                        obj["ResultSet"]["Tier"][name] = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(new DateTimeOffset(Convert.ToDateTime(obj["ResultSet"]["Tier"][name])), "Singapore Standard Time").ToString("yyyy-MM-ddTH:mm::sszzz");
                    }
                }

                return obj.ToString();
            }</set-body>
        </return-response>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Result:

enter image description here

Upvotes: 2

Related Questions