Переполнение даты в.NET.

У нас есть конец Scala/Java, который генерирует эквивалент DateTime.MaxValue в.NET.

Я получил следующую дату в виде строки "9999-12-31T23: 59: 59.999999999Z".

Если я использовал DateTime.TryParse("9999-12-31T23:59:59.999999999Z", out var dateTime), то он выдает DateTime.TryParse("9999-12-31T23:59:59.999999999Z", out var dateTime) ArgumentOutOfRangeException (добавленное или вычитаемое значение приводит к не представимому DateTime.Parameter name: value).

Я этого не ожидал, так как я называл Try Parse. Возможно, возвращение ложного было бы более интуитивным?

Если я уменьшу год, я вижу, что.NET переносит дату на следующий день, что, очевидно, не будет работать с максимальной датой/временем!

DateTime.TryParse("9998-12-31T23:59:59.999999999Z", out var dateTime);
dateTime.ToString().Dump();

Выходы: 01/01/9999 00:00:00

Если я уменьшу точность ms на 2, то он работает:

DateTime.TryParse("9998-12-31T23:59:59.9999999Z", out var dateTime);
dateTime.ToString().Dump();

Выходы: 31/12/9998 23:59:59

Это действительно похоже на ошибку в.NET? Это ожидаемое поведение?

Ответ 1

У вас слишком много девяток в вашей строке. Исключением, которое вы наблюдаете, является проблема точности.

Попробуйте сделать следующее:

DateTime.MaxValue.ToString("o")
приведет к "9999-12-31T23: 59: 59.9999999", а не к "9999-12-31T23: 59: 59.999999999Z", то есть на два меньше девяток в конце.

Используйте "9999-12-31T23:59:59.9999999Z" в качестве входных данных, и он будет успешно проанализирован в DateTime.MaxValue.

PS: TryParse также преобразует это значение в ваш локальный часовой пояс, что, я полагаю, не совсем то, что вы ожидаете. Вместо этого используйте расширенную версию:

DateTime.TryParse("9999-12-31T23:59:59.9999999Z", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTime);

Ответ 2

Передача значений Min/Max/Infinity и т.д. Между различными платформами - плохая идея. Каждая платформа может иметь собственное представление специальных значений (а не только даты). Поэтому единственным допустимым вариантом является передача значений эпохи (предпочтительны варианты миллисекунд в большинстве случаев), поскольку они известны обеим сторонам.

Если по какой-либо причине это невозможно, у вас есть два уродливых варианта:

  1. Заменяйте специальные значения на вашем выходе Scala/Java с помощью собственной "кодировки". Например, как "MaxValue", или возьмите свой выбор, как видите. На стороне.Net вы обнаружите специальные значения и соответствующим образом переведите их.

  2. Вставьте некоторую простую предварительную обработку в ваш.Net-код. Например, проверьте "9999-12-31T23:59:59.999999999".StartsWith("9999") для максимальных значений.