Сравните время строки со временем локального сервера

Есть строковый объект с определенным форматом даты. Необходимо проверить, что dateStr после текущего времени на локальном компьютере. Возникли проблемы с конверсиями и LocalDateTime

String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
public static final String DATE_FORMAT = "MMM dd yyyy HH:mm:ss zzzZ";

Я знаю, что что-то подозрительно в приведенном ниже коде с использованием LocalDateTime

public static boolean isFutureDate(String dateStr){
      DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
      LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
      return(dateTime.isAfter(LocalDateTime.now()));
}

Проблема в часовых поясах и преобразованиях дат. Пожалуйста, помогите найти правильный способ проверки, если dateStr после текущей локальной даты это в Java 8?

2 ответа

Решение

При разборе на LocalDateTime вы игнорируете смещение (+0000), и я не уверен, действительно ли вы этого хотите.

В этом случае +0000 смещение означает дату / время 27 октября 2017 года в 02:29 по Гринвичу. Когда вы анализируете LocalDateTime вы игнорируете смещение (поэтому оно представляет только "27 октября 2017 г. в 02:29", не привязанное к какому-либо часовому поясу) и сравниваете его с местной датой / временем (или текущей датой / временем в часовом поясе JVM по умолчанию)).

Если вы хотите сделать сравнение, которое также учитывает смещение, вы можете проанализировать его OffsetDateTime и преобразовать в Instant сравнить его с фактическим временем UTC, независимо от часового пояса.

Кроме того, название месяца на английском языке (я предполагаю, что это английский, но вы можете изменить это соответственно), поэтому вы должны java.util.Locale в форматере (если вы не зададите языковой стандарт, он будет использовать JVM по умолчанию, и он не всегда будет английским):

// parse to OffsetDateTime (use the same formatter)
String dateStr = "Oct 27 2017 02:29:00 GMT+0000";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss zzzZ", Locale.US);
OffsetDateTime odt = OffsetDateTime.parse(dateStr, fmt);
// compare Instant's
System.out.println(odt.toInstant().isAfter(Instant.now()));

Хотя это работает для вас сейчас, имейте в виду, что локаль по умолчанию может быть изменена без уведомления, даже во время выполнения. Если ваш ввод имеет чувствительную к локали дату (например, названия месяцев), лучше указать ее, как указано выше.

Local… у типов нет часового пояса

Вы используете неправильный тип для ваших данных.

Local… типы в том числе LocalDateTime намеренно не имеют понятия о часовом поясе или смещении от UTC. Как таковые, они не представляют момент на временной шкале, а лишь приблизительное представление о диапазоне возможных моментов. использование LocalDateTime только когда часовой пояс неизвестен или не имеет значения; никогда не используйте это для фактического момента в истории.

использование OffsetDateDate для значений со смещением от UTC - количество часов и минут.

использование ZonedDateTime для значений с назначенным часовым поясом. Часовой пояс, такой как Asia/Kolkata или же America/Montreal является историей прошлого, настоящего и будущего региона относительно его смещения от UTC. Аномалии, такие как переход на летнее время (DST), означают изменение смещения.

Если вы знаете, что все ваши входы в GMT/UTC, используйте OffsetDateTime, Если входы могут использовать часовые пояса, проанализируйте как ZonedDateTime объекты.

Этот формат входных данных ужасен. Если у вас есть какой-либо элемент управления, используйте вместо этого стандартные форматы ISO 8601 при обмене значениями времени и даты в виде текста.

Все это уже много раз освещалось на Stack Exchange. Пожалуйста, ищите более тщательно перед публикацией. И поиск переполнения стека, чтобы узнать больше. Я держал свой ответ здесь кратким, так как это дубликат.

Другие вопросы по тегам