Числа с плавающей точкой в дотнете
Хотел бы я сейчас в паре абзацев доступно рассказать о том, как устроены числа с плавающей точкой в дотнете, но тема слишком сложная, чтобы уложить её в пост в телеграме и одновременно важная, хоть какое-то понимание о ней должно быть у каждого дотнетчика. Нужно иметь представление и чем decimal отличается от double и какие ограничения у каждого типа данных существуют, поэтому буду давать ссылки.
Моя статья: Представление чисел с плавающей точкой в памяти в дотнете - в которой разбирается как Double хранится в памяти, подробнее остановивливаясь на нормализованных числах (поймёте после прочтения) и на том как самому посмотреть, что в реальности хранится в памяти, а также разбирается представление в памяти нескольких чисел.
У Джона Скита есть две небольшие статьи на эту тему, первая: Binary floating point and .NET - про double и float, вторая: Decimal floating point in .NET - про decimal.
Сам Скит рекомендует к прочтению эту статью: Floating Point in .NET part 1: Concepts and Formats - она более подробная и позволит уже более основательно разобраться в вопросе.
Ещё есть статья на русском: Взгляд со стороны: Стандарт IEEE754 - она в целом о стандарте хранения чисел IEEE754, статья основательная, но довольно абстрактная и её не назовёшь лёгким, доступным материалом.
Ну и чтобы закрепить знания можно посмотреть два выступления Андрея Акиньшина на дотнексте и подумать над задачками, которые он задаёт зрителям, после прочтения статей выше многие ответы на задачи понять будет проще:
Поговорим про Арифметику
Продолжаем говорить про Арифметику
#computerscience #floatingpointnumbers
Хотел бы я сейчас в паре абзацев доступно рассказать о том, как устроены числа с плавающей точкой в дотнете, но тема слишком сложная, чтобы уложить её в пост в телеграме и одновременно важная, хоть какое-то понимание о ней должно быть у каждого дотнетчика. Нужно иметь представление и чем decimal отличается от double и какие ограничения у каждого типа данных существуют, поэтому буду давать ссылки.
Моя статья: Представление чисел с плавающей точкой в памяти в дотнете - в которой разбирается как Double хранится в памяти, подробнее остановивливаясь на нормализованных числах (поймёте после прочтения) и на том как самому посмотреть, что в реальности хранится в памяти, а также разбирается представление в памяти нескольких чисел.
У Джона Скита есть две небольшие статьи на эту тему, первая: Binary floating point and .NET - про double и float, вторая: Decimal floating point in .NET - про decimal.
Сам Скит рекомендует к прочтению эту статью: Floating Point in .NET part 1: Concepts and Formats - она более подробная и позволит уже более основательно разобраться в вопросе.
Ещё есть статья на русском: Взгляд со стороны: Стандарт IEEE754 - она в целом о стандарте хранения чисел IEEE754, статья основательная, но довольно абстрактная и её не назовёшь лёгким, доступным материалом.
Ну и чтобы закрепить знания можно посмотреть два выступления Андрея Акиньшина на дотнексте и подумать над задачками, которые он задаёт зрителям, после прочтения статей выше многие ответы на задачи понять будет проще:
Поговорим про Арифметику
Продолжаем говорить про Арифметику
#computerscience #floatingpointnumbers
boyarincev.net
Представление чисел с плавающей точкой в памяти в дотнете
Поехали
В этой статье я разбираю, как Double хранится в памяти, но это не самостоятельная статья, в том плане, что вряд ли вы сможете разобраться с этой темой, прочитав одну её, поэтому я порекомендую ссылки на другие статьи (хотя и их тоже не назовёшь идеальными).…
В этой статье я разбираю, как Double хранится в памяти, но это не самостоятельная статья, в том плане, что вряд ли вы сможете разобраться с этой темой, прочитав одну её, поэтому я порекомендую ссылки на другие статьи (хотя и их тоже не назовёшь идеальными).…
На днях поймали deadlock на блокировках в PostgreSQL и оказалась полезной эта статья - взял из неё запрос, который в удобном виде показывает, какие запросы какими запросами заблокированы
#postgresql
[eve] sandbox=# SELECT
COALESCE(blockingl.relation::regclass::text,blockingl.locktype) as locked_item,
blockeda.pid AS blocked_pid, blockeda.query as blocked_query,
blockedl.mode as blocked_mode, blockinga.pid AS blocking_pid,
blockinga.query as blocking_query, blockingl.mode as blocking_mode
FROM pg_catalog.pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_catalog.pg_locks blockingl ON(
( (blockingl.transactionid=blockedl.transactionid) OR
(blockingl.relation=blockedl.relation AND blockingl.locktype=blockedl.locktype)
) AND blockedl.pid != blockingl.pid)
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid
WHERE NOT blockedl.granted
AND blockinga.datname='sandbox';
Ну и вообще статья хорошая - по шагам от простого сложного и с понятными примерами даёт неплохой экскурс в блокировки.#postgresql
Big-Elephants
Exploring Query Locks in Postgres - Big elephants
Understanding query locking is key to using postgres concurrently. So let’s look at an example to learn more about how locking works and how to …
С термином инкапсуляция всё не очень просто - само слово нам мало что о себе сообщает, а его интерпретация в головах разных программистов варьируется в гигантских пределах, хотя сама инкапсуляция считается фундаментом на котором стоит ООП. Эту статью я написал по следам одного спора, как раз по поводу интерпретации термина Инкапсуляция. В ней я привожу разные точки зрения на него и пытаюсь докопаться до смысла заложенного в него при рождении.
https://boyarincev.net/articles/dotnet/what-is-encapsulation/
#misconceptions #oop
https://boyarincev.net/articles/dotnet/what-is-encapsulation/
#misconceptions #oop
Бояринцев .NET
Инкапсуляция - что ты такое?
Вроде живёшь себе спокойно, думаешь, что понимаешь кое-что в программировании, но вдруг во время беседы в зуме с друзьями программистами говоришь: Инкапсуляция? - Ну это сокрытие деталей реализации. А тебе в ответ: Вообще-то инкапсуляция - это объединение…
Если написав очередной switch/case, вы останавливались и задумывались - а нужно ли вообще обрабатывать default-ветку, а если обрабатывать, то бросать ли исключение, а если бросать то какое, а нормально ли вообще, что у меня эти switch/case по всей кодовой базе дублируются ? - то на эти вопросы я попробовал сформулировать своё мнение в этом тексте:
Какое исключение бросать в swith, если case не нашлось?
Какое исключение бросать в swith, если case не нашлось?
Бояринцев .NET
Какое исключение бросать в swith, если case не нашлось?
В чём проблема Если написав очередной switch/case, вы останавливались и задумывались - а нужно ли вообще обрабатывать default-ветку, а если обрабатывать, то бросать ли исключение, а если бросать то какое, а нормально ли вообще, что у меня эти switch/case…
На работе у нас есть некое подобие самописной ORM, работающей напрямую с ADO.NET и одна из проблем с которой мы сталкивались при её разработке - это то, что у количества параметров используемых в DbCommand есть лимит, этот лимит накладывается базой данных и у разных баз данных он разный.
Например, у PostgreSQL в каждом SQL statement (под SQL statement имеется в виду то, что в разговорной речи называют SQL запросом) может использоваться не больше 65535 параметров (в одну DbCommand можно отправить множество SQL statement и таким образом в общем DbCommand может содержать больше 65535 параметров).
В большинстве запросов довольно сложно преодолеть разрешённую планку, мы столкнулись с этим ограничением в двух случаях - в Insert, когда за один запрос вставляется множество строк и в запросах с использованием оператора IN.
Первым делом я конечно же полез смотреть как эту проблему решает и решает ли вообще Entity Framework...
Написал небольшую заметку о том, можно ли при использовании Entity Framework столкнуться с ограничениями, которые накладывает использование DbCommand под его капотом: Entity Framework и ограничения DbCommand
Например, у PostgreSQL в каждом SQL statement (под SQL statement имеется в виду то, что в разговорной речи называют SQL запросом) может использоваться не больше 65535 параметров (в одну DbCommand можно отправить множество SQL statement и таким образом в общем DbCommand может содержать больше 65535 параметров).
В большинстве запросов довольно сложно преодолеть разрешённую планку, мы столкнулись с этим ограничением в двух случаях - в Insert, когда за один запрос вставляется множество строк и в запросах с использованием оператора IN.
Первым делом я конечно же полез смотреть как эту проблему решает и решает ли вообще Entity Framework...
Написал небольшую заметку о том, можно ли при использовании Entity Framework столкнуться с ограничениями, которые накладывает использование DbCommand под его капотом: Entity Framework и ограничения DbCommand
Бояринцев .NET
Entity Framework и ограничения DbCommand
На работе у нас есть некое подобие самописной ORM, работающей напрямую с ADO.NET и одна из проблем с которой мы сталкивались при её разработке - это то, что у количества параметров используемых в DbCommand есть лимит, этот лимит накладывается базой данных…
Не используйте
Для начала тест:
Вопрос: Какая дата выведется в консоль ?
Ответ: Дата будет зависеть от вашей локальной таймзоны, от даты которую передают в json и от вашей локальной таблицы переводов времени в ОС, но если ваша локальная таймзона UTC, то скорее всего выведется
Проблема в том, что
Вот несколько обсуждений этой проблемы:
https://stackoverflow.com/questions/46829888/how-parse-string-to-jobject-ignoring-time-zone
https://github.com/JamesNK/Newtonsoft.Json/issues/1110
В качестве решения предлагается использовать
Интересно более глубокое раскрытие этой темы ?
JObject.Parse()
из JSON.NETДля начала тест:
var json = "{ \"Date\":\"2024-09-14T00:00:00+04:00\"}";
var jsonObject = JObject.Parse(json);
Console.WriteLine(jsonObject.ToString());
Вопрос: Какая дата выведется в консоль ?
Ответ: Дата будет зависеть от вашей локальной таймзоны, от даты которую передают в json и от вашей локальной таблицы переводов времени в ОС, но если ваша локальная таймзона UTC, то скорее всего выведется
{
"Date": "2024-09-13T20:00:00+00:00"
}
Проблема в том, что
JObject.Parse()
умеет работать только с DateTime
, поэтому во время его работы теряется часовой пояс переданного времени. Вот несколько обсуждений этой проблемы:
https://stackoverflow.com/questions/46829888/how-parse-string-to-jobject-ignoring-time-zone
https://github.com/JamesNK/Newtonsoft.Json/issues/1110
В качестве решения предлагается использовать
JsonConvert.DeserializeObject()
- что далеко не всегда подходит, так как результат вызова Parse()
позволяет манипулировать объектом как json'ом, например, исследовать его и изменять.Интересно более глубокое раскрытие этой темы ?
Newtonsoft
Parsing JSON Object using JObject.Parse
This sample parses a JSON object using M:Newtonsoft.Json.Linq.JObject.Parse(System.String).
Веб-разработка на .NET // dotnet web dev
Не используйте JObject.Parse() из JSON.NET Для начала тест: var json = "{ \"Date\":\"2024-09-14T00:00:00+04:00\"}"; var jsonObject = JObject.Parse(json); Console.WriteLine(jsonObject.ToString()); Вопрос: Какая дата выведется в консоль ? Ответ: Дата будет…
Вместо
Вот текущая реализация Parse:
А вот такой будет исправленная версия, поддерживающая парсинг в
И тогда результат выполнения кода:
Будет:
JObject.Parse()
, кстати, можно использовать JOjbect.Load()
- который Parse внутреннее и использует, но только в Load уже можно передать настроенный на парсинг DateTimeOffset
JsonReader
.Вот текущая реализация Parse:
public new static JObject Parse(string json, JsonLoadSettings? settings)
{
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
{
JObject o = Load(reader, settings);
while (reader.Read())
{
// Any content encountered here other than a comment will throw in the reader.
}
return o;
}
}
А вот такой будет исправленная версия, поддерживающая парсинг в
DateTimeOffset
:static JObject ParseWithDateTimeOffset(string json, JsonLoadSettings? settings)
{
using (JsonReader reader = new JsonTextReader(new StringReader(json)))
{
reader.DateParseHandling = DateParseHandling.DateTimeOffset;
JObject o = JObject.Load(reader, settings);
while (reader.Read())
{
// Any content encountered here other than a comment will throw in the reader.
}
return o;
}
}
И тогда результат выполнения кода:
var json = "{ \"Date\":\"2024-09-14T00:00:00+04:00\"}";
var jsonObject = ParseWithDateTimeOffset(json);
Console.WriteLine(jsonObject.ToString());
Будет:
{
"Date": "2024-09-14T00:00:00+04:00"
}
GitHub
Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JObject.cs at 13.0.3 · JamesNK/Newtonsoft.Json
Json.NET is a popular high-performance JSON framework for .NET - JamesNK/Newtonsoft.Json
Библиотека, которая генерирует запрос для curl по HttpRequest - HttpClientToCurlGenerator
Очень часто при проблемах с http-запросами нужно попробовать воспроизвести этот запрос вне приложения или передать его другой команде для исследования - что всегда геморрой, и в этом случае получить сразу готовый запрос для курла - бесценно.
Можно, например, прикрутить её вызов к обработке всех неуспешных статус кодов ответов и писать curl-запрос сразу в логи, единственный момент который в этом случае нужно учесть - это появление в логах логинов, паролей и прочих токенов, но это всё решаемо.
string curlScript = httpClient.GenerateCurlInString(httpRequestMessage);
Очень часто при проблемах с http-запросами нужно попробовать воспроизвести этот запрос вне приложения или передать его другой команде для исследования - что всегда геморрой, и в этом случае получить сразу готовый запрос для курла - бесценно.
Можно, например, прикрутить её вызов к обработке всех неуспешных статус кодов ответов и писать curl-запрос сразу в логи, единственный момент который в этом случае нужно учесть - это появление в логах логинов, паролей и прочих токенов, но это всё решаемо.
GitHub
GitHub - amingolmahalle/HttpClientToCurlGenerator: A NuGet package for generating curl script of HttpClient in .NET ( C# | CSharp…
A NuGet package for generating curl script of HttpClient in .NET ( C# | CSharp | Dotnet ) supported features: Post, Get, Put, and Delete. content types: application/json, text/xml, application/x-w...
Сегодня начнём про приём дат во входящих запросах ASP.NET - в частности, про приём дат в json-теле запроса.
За привязку моделей из тела запроса у нас отвечают Input formatters.
Из коробки за привязку json отвечает SystemTextJsonInputFormatter
Он в свою очередь использует System.Text.Json, поэтому все особенности обработки дат, будут специфичны для этого сериализатора.
Есть статья описывающая как System.Text.Json работает с датами - DateTime and DateTimeOffset support in System.Text.Json, но она рассказывает далеко не о всех особенностях десериализации, поэтому будем подсматривать в исходном коде.
Начнём с десериализации дат из тела запроса в поля с типом DateTime в моделях.
Дата поддерживается в формате ISO 8601-1:2019
Нас интересует как десериализатор обработает вот такие даты:
"2024-02-08T00:00:00+00:00"
"2024-02-08T00:00:00+01:00"
"2024-02-08T00:00:00:10Z"
"2024-02-08T00:00:00"
"2024-02-08"
В исходном коде сначала выходим на TryGetDateTime в Utf8JsonReader а затем на JsonHelper.TryParseAsISO()
Правила следующие:
- Если есть offset, то дата создаётся c Kind Local и приводится к локальной дате согласно текущему часовому поясу системы.
- Если Z - то дата создаётся с Kind UTC
- В остальных случаях Kind Unspecified и время из присланной даты или 00:00:00, если времени не было
В первом случае с offset возможна потеря дня из-за часовых поясов.
Вывод:
Во втором примере -
@boyarincevdotnet
За привязку моделей из тела запроса у нас отвечают Input formatters.
Из коробки за привязку json отвечает SystemTextJsonInputFormatter
Он в свою очередь использует System.Text.Json, поэтому все особенности обработки дат, будут специфичны для этого сериализатора.
Есть статья описывающая как System.Text.Json работает с датами - DateTime and DateTimeOffset support in System.Text.Json, но она рассказывает далеко не о всех особенностях десериализации, поэтому будем подсматривать в исходном коде.
Начнём с десериализации дат из тела запроса в поля с типом DateTime в моделях.
Дата поддерживается в формате ISO 8601-1:2019
Нас интересует как десериализатор обработает вот такие даты:
"2024-02-08T00:00:00+00:00"
"2024-02-08T00:00:00+01:00"
"2024-02-08T00:00:00:10Z"
"2024-02-08T00:00:00"
"2024-02-08"
В исходном коде сначала выходим на TryGetDateTime в Utf8JsonReader а затем на JsonHelper.TryParseAsISO()
Правила следующие:
- Если есть offset, то дата создаётся c Kind Local и приводится к локальной дате согласно текущему часовому поясу системы.
- Если Z - то дата создаётся с Kind UTC
- В остальных случаях Kind Unspecified и время из присланной даты или 00:00:00, если времени не было
В первом случае с offset возможна потеря дня из-за часовых поясов.
var jsonWithOffset0 = "{ \"Date\":\"2024-02-08T00:00:00+00:00\"}";
var jsonWithOffset1 = "{ \"Date\":\"2024-02-08T00:00:00+01:00\"}";
var jsonZ = "{ \"Date\":\"2024-02-08T00:00:00Z\"}";
var jsonDateTime = "{ \"Date\":\"2024-02-08T00:00:00\"}";
var jsonOnlyDate = "{ \"Date\":\"2024-02-08\"}";
Console.WriteLine($"Local TimeZone: {TimeZoneInfo.Local}");
var resultJsonWithOffset0 = System.Text.Json.JsonSerializer.Deserialize<DateTimeModel>(jsonWithOffset0);
Console.WriteLine(GetDateTimeString(resultJsonWithOffset0.Date));
var resultJsonWithOffset1 = System.Text.Json.JsonSerializer.Deserialize<DateTimeModel>(jsonWithOffset1);
Console.WriteLine(GetDateTimeString(resultJsonWithOffset1.Date));
var resultJsonZ = System.Text.Json.JsonSerializer.Deserialize<DateTimeModel>(jsonZ);
Console.WriteLine(GetDateTimeString(resultJsonZ.Date));
var resultJsonDateTime = System.Text.Json.JsonSerializer.Deserialize<DateTimeModel>(jsonDateTime);
Console.WriteLine(GetDateTimeString(resultJsonDateTime.Date));
var resultJsonOnlyDate = System.Text.Json.JsonSerializer.Deserialize<DateTimeModel>(jsonOnlyDate);
Console.WriteLine(GetDateTimeString(resultJsonOnlyDate.Date));
static string GetDateTimeString(DateTime dateTime, string json) => $"{dateTime} {dateTime.Kind} ({json})";
class DateTimeModel
{
public DateTime Date { get; set; }
}
Вывод:
Local TimeZone: (UTC) Время в формате UTC
08.02.2024 0:00:00 Local ({ "Date":"2024-02-08T00:00:00+00:00"})
07.02.2024 23:00:00 Local ({ "Date":"2024-02-08T00:00:00+01:00"})
08.02.2024 0:00:00 Utc ({ "Date":"2024-02-08T00:00:00Z"})
08.02.2024 0:00:00 Unspecified ({ "Date":"2024-02-08T00:00:00"})
08.02.2024 0:00:00 Unspecified ({ "Date":"2024-02-08"})
Во втором примере -
2024-02-08T00:00:00+01:00
при локальном часовом поясе +0 (время в UTC) мы во входящем запросе будем получать дату 07.02.2024 23:00:00
@boyarincevdotnet
Docs
Model Binding in ASP.NET Core
Learn how model binding in ASP.NET Core works and how to customize its behavior.
Please open Telegram to view this post
VIEW IN TELEGRAM
Продолжим про десериализацию во входящих запросах ASP.NET - в частности, про приём дат в json-теле запроса.
Первая часть (https://teleg.eu/boyarincevdotnet/41) где мы посмотрели как десериализуется DateTime.
Сегодня посмотрим как десериализатор отработает по нашему тестовому набору дат:
Если целевой тип будет DateTimeOffse:
Результат:
Тут без сюрпризов - как мне кажется, мы получаем всё ровно так как и ожидаем.
Реализация в коде System.Text.Json
Первая часть (https://teleg.eu/boyarincevdotnet/41) где мы посмотрели как десериализуется DateTime.
Сегодня посмотрим как десериализатор отработает по нашему тестовому набору дат:
"2024-02-08T00:00:00+00:00"
"2024-02-08T00:00:00+01:00"
"2024-02-08T00:00:00:10Z"
"2024-02-08"
Если целевой тип будет DateTimeOffse:
using System.Text.Json;
using System.Runtime.InteropServices;
var jsonWithOffset0 = "{ \"Date\":\"2024-02-08T00:00:00+00:00\"}";
var jsonWithOffset3 = "{ \"Date\":\"2024-02-08T00:00:00+03:00\"}";
var jsonZ = "{ \"Date\":\"2024-02-08T00:00:00Z\"}";
var jsonDateTime = "{ \"Date\":\"2024-02-08T00:00:00\"}";
var jsonOnlyDate = "{ \"Date\":\"2024-02-08\"}";
Console.WriteLine($"{RuntimeInformation.OSDescription}");
Console.WriteLine($"Local TimeZone: {TimeZoneInfo.Local}");
var resultJsonWithOffset0 = JsonSerializer.Deserialize<DateTimeOffsetModel>(jsonWithOffset0);
Console.WriteLine(GetDateTimeOffsetString(resultJsonWithOffset0.Date, jsonWithOffset0));
var resultJsonWithOffset3 = JsonSerializer.Deserialize<DateTimeOffsetModel>(jsonWithOffset3);
Console.WriteLine(GetDateTimeOffsetString(resultJsonWithOffset3.Date, jsonWithOffset3));
var resultJsonZ = JsonSerializer.Deserialize<DateTimeOffsetModel>(jsonZ);
Console.WriteLine(GetDateTimeOffsetString(resultJsonZ.Date, jsonZ));
var resultJsonDateTime = JsonSerializer.Deserialize<DateTimeOffsetModel>(jsonDateTime);
Console.WriteLine(GetDateTimeOffsetString(resultJsonDateTime.Date, jsonDateTime));
var resultJsonOnlyDate = JsonSerializer.Deserialize<DateTimeOffsetModel>(jsonOnlyDate);
Console.WriteLine(GetDateTimeOffsetString(resultJsonOnlyDate.Date, jsonOnlyDate));
string GetDateTimeOffsetString(DateTimeOffset dateTime, string json) =>
$"{dateTime} {dateTime.DateTime.Kind} ({json})";
class DateTimeOffsetModel
{
public DateTimeOffset Date { get; set; }
}
Результат:
Microsoft Windows 10.0.22621
Local TimeZone: (UTC) Время в формате UTC
08.02.2024 0:00:00 +00:00 Unspecified ({ "Date":"2024-02-08T00:00:00+00:00"})
08.02.2024 0:00:00 +01:00 Unspecified ({ "Date":"2024-02-08T00:00:00+01:00"})
08.02.2024 0:00:00 +00:00 Unspecified ({ "Date":"2024-02-08T00:00:00Z"})
08.02.2024 0:00:00 +00:00 Unspecified ({ "Date":"2024-02-08T00:00:00"})
08.02.2024 0:00:00 +00:00 Unspecified ({ "Date":"2024-02-08"})
Тут без сюрпризов - как мне кажется, мы получаем всё ровно так как и ожидаем.
Реализация в коде System.Text.Json
Please open Telegram to view this post
VIEW IN TELEGRAM
Десериализация DateOnly в json-теле запроса.
Поддержку DateOnly и TimeOnly добавили в System.Text.Json в .NET 7 (https://github.com/dotnet/runtime/issues/53539)
Реализацию можно посмотреть в DateOnlyConverter
Так как поддерживается только дата в формате
И результат выполнения:
Тут особо ничего не прокомментируешь - максимально прозрачное и ожидаемое поведение, единственной проблемой может быть необходимость использования .NET 7.
Поддержку DateOnly и TimeOnly добавили в System.Text.Json в .NET 7 (https://github.com/dotnet/runtime/issues/53539)
Реализацию можно посмотреть в DateOnlyConverter
Так как поддерживается только дата в формате
yyyy-MM-dd
, то проверять мы только её и будем:var jsonOnlyDate = "{ \"Date\":\"2024-02-08\"}";
Console.WriteLine($"{RuntimeInformation.OSDescription}");
Console.WriteLine($"Local TimeZone: {TimeZoneInfo.Local}");
var resultJsonOnlyDate = JsonSerializer.Deserialize<DateOnlyModel>(jsonOnlyDate);
Console.WriteLine(GetDateOnlyString(resultJsonOnlyDate.Date, jsonOnlyDate));
string GetDateOnlyString(DateOnly date, string json) => $"{date} ({json})";
public class DateOnlyModel
{
public DateOnly Date { get; set; }
}
И результат выполнения:
Microsoft Windows 10.0.22621
Local TimeZone: (UTC+03:00) Москва, Санкт-Петербург
08.02.2024 ({ "Date":"2024-02-08"})
Тут особо ничего не прокомментируешь - максимально прозрачное и ожидаемое поведение, единственной проблемой может быть необходимость использования .NET 7.
GitHub
Support DateOnly and TimeOnly in JsonSerializer · Issue #53539 · dotnet/runtime
#51302 proposes adding DateOnly and TimeOnly support to System.Text.Json: on the serializer, reader, writer, and DOM types. We won't get to all of this in 6.0 but can support them at the JsonSe...