Есть ли способ конвертировать из. Net TimeZoneInfo в Java ZonedDateTime? - PullRequest
1 голос
/ 12 июля 2020

Это продолжение этого вопроса . Я создаю сервер RESTful (то есть в C#, но основной движок - Java (через IKVM)). Мы пишем клиентов в C# Java, et c.

Итак, для конкретного случая c клиента C#, если они хотят ZonedDateTime на стороне сервера, мне нужно чтобы передать строку, подобную «2018-10-21T08: 11: 55-06: 00 [Америка / Денвер]». В этом случае, я думаю, мне нужно передать мне (DateTime, TimeZoneInfo) и из этого построить строку.

Для этого мне нужно получить Java «America / Denver» из настройки для TimeZoneInfo. Есть ли способ получить это преобразование.

Насколько я понимаю, нет ISO или других широко используемых настроек для однозначной идентификации часовых поясов.

1 Ответ

1 голос
/ 13 июля 2020

«Америка / Денвер» - это название IANA для этого часового пояса. База данных часовых поясов (tzdb) содержит эти имена и их правила (которые могут меняться со временем). NodaTime использует данные tzdb для выполнения своего logi c.

Вы можете использовать пакет TimeZoneConverter для преобразования TimeZoneInfo в идентификатор часового пояса tzdb.

Вы Я задал несколько вопросов, связанных с этим, и я хотел бы собрать некоторые из них для вас здесь.

NodaTime All The Way Down

Если это возможно, вам следует попросите потребителя передать вам ZonedDateTime. Это единое значение со всей информацией, необходимой базовому движку на основе Java, а это именно то, что вы просили ( здесь ). Использование единственного значения, которое было проверено в домене (в отличие от настраиваемого контейнера для составных частей), откладывает действия, подверженные ошибкам, для потребителя, который лучше подходит для их устранения, чем вы, и должен сделайте перед тем, как позвонить своему клиенту. Тогда вам не нужно нести ответственность за какие-либо ошибки или недочеты, связанные с тем, что вас не должно волновать. предоставит вам строку в формате, ожидаемом стороной Java.

ZonedDateTimePattern customPattern = ZonedDateTimePattern.Create(
    "uuuu'-'MM'-'dd'T'HH':'mm':'sso<Z-HH':'mm>'['z']'",
    CultureInfo.InvariantCulture,
    mapping => mapping.LocalDateTime.InZoneLeniently(mapping.Zone),
    DateTimeZoneProviders.Tzdb,
    default);

Судя по вашим предыдущим вопросам, похоже, что вам нужен буквальный «Z» для UT C вместо «+00:00 ". Это делает подшаблон «Z-HH':'mm». Взгляните на документацию Шаблоны смещения , если вам нужно что-то другое.

Теперь вы можете использовать customPattern для создания строки, которую нужно отправить.

string formatted = customPattern.Format(zonedDateTime);

Тот же шаблон можно использовать для синтаксического анализа такой строки до ZonedDateTime, если необходимо.

Использование NodaTime только для внутренних целей

Если вы не можете ожидать, что потребитель будет работать с типами NodaTime , это нормально. Получение DateTimeOffset и TimeZoneInfo также может работать. Вы можете без особых церемоний преобразовать их в ZonedDateTime в своем клиенте.

// Given: DateTimeOffset dateTimeOffset, TimeZoneInfo timeZoneInfo

DateTimeZone dateTimeZone = DateTimeZoneProviders.Tzdb[TZConvert.WindowsToIana(timeZoneInfo.Id)];

ZonedDateTime zonedDateTime = OffsetDateTime.FromDateTimeOffset(dateTimeOffset).InZone(dateTimeZone);

Потенциальная проблема с этим состоит в том, что коллективный ввод не был проверен в домене. Мэтт Джонсон-Пинт в своем ответе указал, что может быть передано смещение, которое не соответствует указанному часовому поясу. Будьте готовы добавить проверку или попытку / уловку, чтобы вы могли очень ясным языком рассказать потребителю, что он сделал не так.

Принятие неоднозначного времени

Вы могли бы принять DateTime, но вы будете вынуждены сделать предположения о двусмысленных временах, которые могут быть неприемлемы для вас и / или потребителя. Затем вы берете на себя ответственность за logi c, который не имеет ничего общего с функциональностью вашего API.

Я включу его сюда для полноты, но это не является одобрением какого-либо рода.

// Given: DateTime dateTime, TimeZoneInfo timeZoneInfo

DateTimeZone dateTimeZone = DateTimeZoneProviders.Tzdb[TZConvert.WindowsToIana(timeZoneInfo.Id)];

ZonedDateTime zonedDateTime = LocalDateTime.FromDateTime(dateTime).InZoneLeniently(dateTimeZone);

InZoneLeniently - это большой красный флаг. Он будет "просто делать это", когда встречается неоднозначное время, и это может быть неправильно. Помните, что «просто» - это четырехбуквенное слово.

...