Как предотвратить преобразование даты и времени при преобразовании строки json в документ XML

Я хочу преобразовать ответ JSON в эквивалентный XML-документ, но при этом я также хочу сохранить текущий формат даты и времени вместе со смещением, например, DateTime в JSON — «2019-10-25T07:00:00-05: 00", и после преобразования я хочу, чтобы он оставался прежним. Но после преобразования в XML значение DateTime становится «2019-10-25T08:00:00-04:00».

Я пытался искать об этом в документах Microsoft, но не нашел ответа на следующие вопросы:

  1. Как определить часовой пояс заданной строки даты и времени (например, «2019-10-25T07:00:00-05:00»)?
  2. Как преобразовать строку даты и времени (например, «2019-10-25T08:00:00-04:00») в дату и время нужного часового пояса (например, в часовой пояс «2019-10- 25T07:00:00-05:00")
// C# Code Snippet
// Step 1: Reading JsonResponse from a file
string jsonString = System.IO.File.ReadAllText(@"C:\TestDateTimeConvertJSONResponse.txt");
// Step 2: Converting jsonString to XMLDoc
System.Xml.XmlDocument xmlDoc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonString);
Console.WriteLine();
Console.WriteLine("EQUIVALENT XML RESPONSE");
Console.WriteLine(xmlDoc.InnerXml);

Введите строку JSON:

{
    "Flight": {
        "FlightNumber": "747",
        "Source": "JFK",
        "Destination": "LAS",   
        "Status": "ON TIME",
        "DepDateTime": "2019-10-25T07:00:00-05:00",
        "Terminal": "2"
    }
}

Ожидал:

<Flight>
    <FlightNumber>747</FlightNumber>
    <Source>JFK</Source>
    <Destination>LAS</Destination>
    <Status>ON TIME</Status>
    <DepDateTime>2019-10-25T07:00:00-05:00</DepDateTime>
    <Terminal>2</Terminal>
</Flight>

Действительный:

<Flight>
    <FlightNumber>747</FlightNumber>
    <Source>JFK</Source>
    <Destination>LAS</Destination>
    <Status>ON TIME</Status>
    <DepDateTime>2019-10-25T08:00:00-04:00</DepDateTime>
    <Terminal>2</Terminal>
</Flight>

person PumbaTimon    schedule 23.10.2019    source источник


Ответы (2)


Ваша проблема в том, что автоматическое DateTime распознавание Json.NET распознает, что строка "2019-10-25T07:00:00-05:00" является допустимой датой и временем ISO 8601 и преобразует ее в DateTime, который, к сожалению, не поддерживает указание часового пояса. . Таким образом, значение преобразуется (правильно) в местный часовой пояс на вашем компьютере во время десериализации и впоследствии форматируется как таковое в XML.

Чтобы предотвратить это, вам нужно разобрать JSON, используя DateParseHandling.None или DateParseHandling.DateTimeOffset. , однако JsonConvert.DeserializeXmlNode не имеет перегрузки, позволяющей передать этот параметр в Таким образом, вам нужно будет создать метод расширения с необходимым аргументом:

public static partial class JsonExtensions
{
    public static XmlDocument DeserializeXmlNode(string json, DateParseHandling dateParseHandling, 
                                                 string deserializeRootElementName = null, bool writeArrayAttribute = false, bool encodeSpecialCharacters = false)
    {
        var settings = new JsonSerializerSettings
        {
            Converters = 
            { 
                new Newtonsoft.Json.Converters.XmlNodeConverter() 
                {
                    DeserializeRootElementName = deserializeRootElementName,
                    WriteArrayAttribute = writeArrayAttribute,
                    EncodeSpecialCharacters = encodeSpecialCharacters
                } 
            },
            DateParseHandling = dateParseHandling,
        };

        return JsonConvert.DeserializeObject<XmlDocument>(json, settings);
    }
}

Затем используйте его следующим образом:

var xmlDoc = JsonExtensions.DeserializeXmlNode(jsonString, DateParseHandling.None);

Обратите внимание, что и DateParseHandling.None, и DateParseHandling.DateTimeOffset соответствуют вашим потребностям, так как первый отключает распознавание даты ISO 8601, а второй анализирует такие строки в DateTimeOffset, который поддерживает указание часового пояса.

Кстати, аналогичный метод для тех, кто предпочитает более новый XDocument это:

public static partial class JsonExtensions
{
    public static XDocument DeserializeXNode(string json, DateParseHandling dateParseHandling, 
                                                 string deserializeRootElementName = null, bool writeArrayAttribute = false, bool encodeSpecialCharacters = false)
    {
        var settings = new JsonSerializerSettings
        {
            Converters = 
            { 
                new Newtonsoft.Json.Converters.XmlNodeConverter() 
                {
                    DeserializeRootElementName = deserializeRootElementName,
                    WriteArrayAttribute = writeArrayAttribute,
                    EncodeSpecialCharacters = encodeSpecialCharacters
                } 
            },
            DateParseHandling = dateParseHandling,
        };

        return JsonConvert.DeserializeObject<XDocument>(json, settings);
    }
}

Демонстрационная скрипта здесь.

person dbc    schedule 23.10.2019

Я бы прочитал узел как строку и написал его как строку. Это единственный верный способ.

Пример решения для игрушек JsonConvert.DefaultSetting

// Setting the default settings is the only way I know to affect settings
// for DeserializeXmlNode, there may be a better way
Newtonsoft.Json.JsonConvert.DefaultSettings = 
    () => new Newtonsoft.Json.JsonSerializerSettings() { 
    DateParseHandling = Newtonsoft.Json.DateParseHandling.None };

Остерегаться! Изменение Newtonsoft.Json.JsonConvert.DefaultSettings может повлиять на другие части вашего решения!

Тест

var json = @"
{
    ""Flight"": {
        ""FlightNumber"": ""747"",
        ""Source"": ""JFK"",
        ""Destination"": ""LAS"",   
        ""Status"": ""ON TIME"",
        ""DepDateTime"": ""2019-10-25T07:00:00-05:00"",
        ""Terminal"": ""2""
    }
}            
";

Newtonsoft.Json.JsonConvert.DefaultSettings = () => new Newtonsoft.Json.JsonSerializerSettings() { DateParseHandling = Newtonsoft.Json.DateParseHandling.None };

System.Xml.XmlDocument xmlDoc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json);
Console.WriteLine(xmlDoc.InnerXml);

Выход

(...)<DepDateTime>2019-10-25T07:00:00-05:00</DepDateTime><Terminal>2</Terminal></Flight>

Вывод без установки настроек

(...)<DepDateTime>2019-10-25T22:00:00+10:00</DepDateTime><Terminal>2</Terminal></Flight>
person tymtam    schedule 23.10.2019