Вопрос-ответ

Convert java.util.Date to java.time.LocalDate

Преобразовать java.util.Date в java.time.LocalDate

Каков наилучший способ преобразовать java.util.Date объект в новый JDK 8 / JSR-310 java.time.LocalDate?

Date input = new Date();
LocalDate date = ???
Переведено автоматически
Ответ 1

Краткий ответ

Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

Объяснение

Несмотря на свое название, java.util.Date представляет момент в строке времени, а не "дату". Фактические данные, хранящиеся внутри объекта, представляют собой long количество миллисекунд с 1970-01 по 01T00:00Z (полночь в начале 1970 года по Гринвичу / UTC).

Эквивалентным классом для java.util.Date в JSR-310 является Instant, таким образом, существует удобный метод toInstant() для обеспечения преобразования:

Date input = new Date();
Instant instant = input.toInstant();

У java.util.Date экземпляра нет понятия часового пояса. Это может показаться странным, если вы вызываете toString() для java.util.Date, потому что toString относится к часовому поясу. Однако этот метод фактически использует часовой пояс Java по умолчанию "на лету" для предоставления строки. Часовой пояс не является частью фактического состояния java.util.Date.

An Instant также не содержит никакой информации о часовом поясе. Таким образом, для преобразования из an Instant в локальную дату необходимо указать часовой пояс. Это может быть зона по умолчанию - ZoneId.systemDefault() - или это может быть часовой пояс, которым управляет ваше приложение, например часовой пояс из пользовательских настроек. Используйте метод atZone() для применения часового пояса:

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());

A ZonedDateTime содержит состояние, состоящее из местных даты и времени, часового пояса и смещения от GMT / UTC. Таким образом, date - LocalDate - можно легко извлечь с помощью toLocalDate():

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();

Java 9 ответ

В Java SE 9 добавлен новый метод, который немного упрощает эту задачу:

Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());

Эта новая альтернатива более прямая, создает меньше мусора и, следовательно, должна работать лучше.

Ответ 2

Лучший способ - это:

Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()

Преимущества этой версии:


  • работает независимо от того, является ли ввод экземпляром java.util.Date или это подкласс java.sql.Date (в отличие от способа @JodaStephen). Это обычное дело для данных, созданных на JDBC. java.sql.Date.toInstant() всегда выдает исключение.


  • то же самое для JDK8 и JDK7 с обратным портом JSR-310


Я лично использую служебный класс (но он не совместим с обратным портом):

/**
* Utilities for conversion between the old and new JDK date types
* (between {@code java.util.Date} and {@code java.time.*}).
*
* <p>
* All methods are null-safe.
*/

public class DateConvertUtils {

/**
* Calls {@link #asLocalDate(Date, ZoneId)} with the system default time zone.
*/

public static LocalDate asLocalDate(java.util.Date date) {
return asLocalDate(date, ZoneId.systemDefault());
}

/**
* Creates {@link LocalDate} from {@code java.util.Date} or it's subclasses. Null-safe.
*/

public static LocalDate asLocalDate(java.util.Date date, ZoneId zone) {
if (date == null)
return null;

if (date instanceof java.sql.Date)
return ((java.sql.Date) date).toLocalDate();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDate();
}

/**
* Calls {@link #asLocalDateTime(Date, ZoneId)} with the system default time zone.
*/

public static LocalDateTime asLocalDateTime(java.util.Date date) {
return asLocalDateTime(date, ZoneId.systemDefault());
}

/**
* Creates {@link LocalDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/

public static LocalDateTime asLocalDateTime(java.util.Date date, ZoneId zone) {
if (date == null)
return null;

if (date instanceof java.sql.Timestamp)
return ((java.sql.Timestamp) date).toLocalDateTime();
else
return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDateTime();
}

/**
* Calls {@link #asUtilDate(Object, ZoneId)} with the system default time zone.
*/

public static java.util.Date asUtilDate(Object date) {
return asUtilDate(date, ZoneId.systemDefault());
}

/**
* Creates a {@link java.util.Date} from various date objects. Is null-safe. Currently supports:<ul>
* <li>{@link java.util.Date}
* <li>{@link java.sql.Date}
* <li>{@link java.sql.Timestamp}
* <li>{@link java.time.LocalDate}
* <li>{@link java.time.LocalDateTime}
* <li>{@link java.time.ZonedDateTime}
* <li>{@link java.time.Instant}
* </ul>
*
* @param zone Time zone, used only if the input object is LocalDate or LocalDateTime.
*
* @return {@link java.util.Date} (exactly this class, not a subclass, such as java.sql.Date)
*/

public static java.util.Date asUtilDate(Object date, ZoneId zone) {
if (date == null)
return null;

if (date instanceof java.sql.Date || date instanceof java.sql.Timestamp)
return new java.util.Date(((java.util.Date) date).getTime());
if (date instanceof java.util.Date)
return (java.util.Date) date;
if (date instanceof LocalDate)
return java.util.Date.from(((LocalDate) date).atStartOfDay(zone).toInstant());
if (date instanceof LocalDateTime)
return java.util.Date.from(((LocalDateTime) date).atZone(zone).toInstant());
if (date instanceof ZonedDateTime)
return java.util.Date.from(((ZonedDateTime) date).toInstant());
if (date instanceof Instant)
return java.util.Date.from((Instant) date);

throw new UnsupportedOperationException("Don't know hot to convert " + date.getClass().getName() + " to java.util.Date");
}

/**
* Creates an {@link Instant} from {@code java.util.Date} or it's subclasses. Null-safe.
*/

public static Instant asInstant(Date date) {
if (date == null)
return null;
else
return Instant.ofEpochMilli(date.getTime());
}

/**
* Calls {@link #asZonedDateTime(Date, ZoneId)} with the system default time zone.
*/

public static ZonedDateTime asZonedDateTime(Date date) {
return asZonedDateTime(date, ZoneId.systemDefault());
}

/**
* Creates {@link ZonedDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
*/

public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) {
if (date == null)
return null;
else
return asInstant(date).atZone(zone);
}

}

asLocalDate() Метод здесь безопасен для null, использует toLocalDate(), если входные данные есть java.sql.Date (он может быть переопределен драйвером JDBC, чтобы избежать проблем с часовым поясом или ненужных вычислений), в противном случае использует вышеупомянутый метод.

Ответ 3
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );
Ответ 4

Если вы используете Java 8, ответ @JodaStephen, очевидно, лучший. Однако, если вы работаете с исходным портом JSR-310, вам, к сожалению, придется сделать что-то вроде этого:

Date input = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(input);
LocalDate date = LocalDate.of(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH));
java java-8