#java #kotlin #java-time #localdatetime #datetimeformatter
Вопрос:
Поэтому я искал, как правильно анализировать входящее время и дату, проблема в том, что эта строка также содержит зону, которая, по-видимому, по какой-то причине не может быть проанализирована. Чтобы привести пример строки входящей даты и времени: 2021-10-05T10:00:00.0000000
Теперь я попытался сделать следующее:
var dateTimeString = "2021-10-05T10:00:00.0000000"
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
var date = LocalDate.parse(dateTimeString, formatter)
Я попытался заменить Z ничем и ZZZZ, но это не сработало, я предполагаю, что это не работает из-за отсутствия знака плюс или минус. К вашему сведению, я получаю дату в этом формате из-за API Microsoft Graph при извлечении событий календаря.
Есть идеи о том, как правильно отформатировать эту дату?
Изменить: Это взято из Microsoft Graph. В основном они дают как дату в качестве объекта:
"start": {
"dateTime": "2021-10-05T10:00:00.0000000",
"timeZone": "UTC"
}
Это страница документации, которая объясняет этот объект даты: тип ресурса dateTimeTimeZone.
Обновить:
Наконец-то я смог решить эту проблему с датой, и я сделал следующее:
var inputDateTime = "2021-10-05T10:00:00.0000000"
var inputTimeZone = "UTC"
var zonedDateTime = ZonedDateTime.parse(
inputDateTime,
DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of(inputTimeZone))
).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
Таким образом, дата будет правильно преобразована в нужный часовой пояс и в нужную дату/время.
Комментарии:
1. С чем именно вы пытаетесь разобраться
Z
? Я не вижу никакого смещения зоны"2021-10-05T10:00:00.0000000"
.2. часовой пояс-это последние 4 цифры
3. Там нет знака «плюс» и «минус», как бы это соотнеслось с допустимым часовым поясом? Хорошо,
0000
будет UTC, но как насчет других зон?4. Я знаю, но это исходит от Microsoft Graph, это не то, что я выдумываю. В основном они дают как дату в качестве объекта:
"start": {"dateTime": "2021-10-05T10:00:00.0000000", "timeZone": "UTC"}
5. Это страница документации, которая объясняет этот объект даты: docs.microsoft.com/en-us/graph/api/resources/…
Ответ №1:
Как я вижу из предоставленных вами документов https://docs.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
dateTime String A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).
timeZone String Represents a time zone, for example, "Pacific Standard Time". See below for more possible values.
dateTime
объект не имеет закодированной зоны. И все 7 нулей представляют собой доли секунды. В таком случае это нормально ISO_DATE_TIME
, и вам не нужно создавать свой собственный форматер.
Следующий код должен работать
var dateTimeString = "2021-10-05T10:00:00.0000000"
var date = LocalDate.parse(dateTimeString, DateTimeFormatter.ISO_DATE_TIME)
Комментарии:
1. Спасибо вам за это, когда я впервые столкнулся с таким форматом, обычно даты содержат только 3 цифры, обозначающие доли секунд, поэтому я предположил, что остальные 4 цифры должны быть смещением часового пояса
Ответ №2:
В вашей строке даты и времени нет информации о часовом поясе
Ваша строка даты и времени 2021-10-05T10:00:00.0000000
не содержит информации о часовом поясе. Он .0000000
представляет долю секунды и на данный момент java.time
способен обрабатывать до 9 цифр точности (т. е. точность в наносекунду).
Поскольку он не содержит информации о часовом поясе, он представляет собой локальную дату-время и, следовательно, должен быть проанализирован LocalDateTime
.
Вам не нужна строка DateTimeFormatter
для даты и времени
Современный API для определения даты и времени основан на стандарте ISO 8601 и не требует DateTimeFormatter
явного использования объекта, если строка даты и времени соответствует стандартам ISO 8601. Ваша строка даты и времени уже находится в формате ISO 8601.
ДЕМОНСТРАЦИЯ:
import java.time.LocalDateTime;
public class Main {
public static void main(String args[]) {
var dateTimeString = "2021-10-05T10:00:00.0000000";
var ldt = LocalDateTime.parse(dateTimeString);
System.out.println(ldt);
}
}
Выход:
2021-10-05T10:00
Как ZonedDateTime
выйти из LocalDateTime
экземпляра?
Вы можете использовать LocalDateTime#atZone
для преобразования вложения a ZoneId
в LocalDateTime
результат в a ZonedDateTime
.
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));
Примечание: Если вам нужен Instant
, вы можете получить его с этого момента ZonedDateTime
, например
Instant instant = zdt.toInstant();
An Instant
представляет собой мгновенную точку на временной шкале, обычно представленную во времени UTC. Z
На выходе отображается обозначение часового пояса для смещения нулевого часового пояса. Он расшифровывается как Zulu и указывает Etc/UTC
часовой пояс (который имеет смещение часового 00:00
пояса в часах).
Узнайте больше о современном API даты и времени* из трейла: Дата и время.
* Если вы работаете в проекте Android, и ваш уровень API Android по-прежнему не соответствует Java-8, проверьте API Java 8 , доступные через десугаринг. Обратите внимание, что Android 8.0 Oreo уже предоставляет поддержку java.time
.
Ответ №3:
В том случае, если последние 4 цифры в вашем примере String
не представляют часовой пояс:
Проанализируйте его без форматирования (нет необходимости, так как это был бы идеальный стандарт ISO, если бы последние 4 цифры были просто дополнительными долями секунды), но также учитывайте часовой пояс, который вы получаете с помощью JSON:
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
fun main() {
// the time String from JSON
var dateTimeString = "2021-10-05T10:00:00.0000000"
// the zone from JSON (may not always work, but does with UTC)
var timeZone = "UTC"
// create the zone from the timezone String
var zoneId = ZoneId.of(timeZone)
// then parse the time String using plain LocalDateTime and add the zone afterwards
var zdt: ZonedDateTime = LocalDateTime.parse(dateTimeString).atZone(zoneId)
// print some results
println("Full ZonedDateTime: ${zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}")
println("(Local)Date only: ${zdt.toLocalDate()}")
}
Full ZonedDateTime: 2021-10-05T10:00:00Z[UTC]
(Local)Date only: 2021-10-05
Пожалуйста, обратите внимание, что анализ часовых поясов, поддерживаемых в настоящее время Windows, не будет работать так просто (кроме как из UTC
), но часовых поясов, поддерживаемых API календаря (в основном), достаточно для создания a java.time.ZoneId
.
Ответ №4:
В качестве дополнения: В вашей документации упоминается Pacific Standard Time
строка часового пояса, которая может быть частью вашего часового пояса MS Graph. Я не думаю, что другие ответы могут справиться с этим, поэтому я хотел бы показать, как вы справляетесь с этим на Java.
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzzz", Locale.ENGLISH);
static ZoneId parseZone(String timeZoneString) {
try {
return ZoneId.from(ZONE_FORMATTER.parse(timeZoneString));
} catch (DateTimeParseException dtpe) {
return ZoneId.of(timeZoneString);
}
}
Я полагаю, что это обрабатывает строки, упомянутые в документации, а также UTC
в вашем вопросе. Я демонстрирую только три разных:
String[] msTimeZoneStrings = { "UTC", "Pacific Standard Time", "Pacific/Honolulu" };
for (String zoneString : msTimeZoneStrings) {
ZoneId zid = parseZone(zoneString);
System.out.format("%-21s parsed to %s%n", zoneString, zid);
}
Выход:
UTC parsed to UTC Pacific Standard Time parsed to America/Los_Angeles Pacific/Honolulu parsed to Pacific/Honolulu
В форматере, который я использую zzzz
, указано название часового пояса, например Pacific Standard Time
. Мой метод синтаксического анализа сначала пробует этот форматер. Это терпит неудачу для UTC
и. Pacific/Honolulu
Когда DateTimeParseException
он пойман, метод затем пытается ZoneId.of
использовать метод, также используемый в других ответах. Он обрабатывает UTC
и все идентификаторы часовых поясов в формате регион/город, указанном в документации.
Объедините ZoneId
полученные из моего метода с проанализированными LocalDateTime
, чтобы получить ZonedDateTime
способ, который деХаар уже показывает в своем ответе.