1

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.

Markus Meyer
  • 3,327
  • 10
  • 22
  • 35
Abdul Wahab
  • 169
  • 10

2 Answers2

2

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

Markus Meyer
  • 3,327
  • 10
  • 22
  • 35
  • 1
    Thank you very much, Marcus! I simply added a few empty string checks in addition to the RegEx approach for DateTime conversion. It was successful. – Abdul Wahab Jan 11 '23 at 05:32
0

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.

Abdul Wahab
  • 169
  • 10