Преобразование java.утиль.Дата на java.время.LocalDate

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

Date input = new Date();
LocalDate date = ???

12 ответов


короткий ответ:

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

объяснение

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

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

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

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

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

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

A ZonedDateTime содержит состояние, состоящее из локальной даты и времени, часового пояса и смещения от GMT/UTC. Как таковая дата -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, a новый метод было добавлено, что немного упрощает эту задачу:

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

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


лучше:

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 backport

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

/**
 * 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);
    }

}

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


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

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));

LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();

LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );

вы можете конвертировать в одну строку:

public static LocalDate getLocalDateFromDate(Date date){
   return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}

во-первых, легко преобразовать дату в мгновенное

Instant timestamp = new Date().toInstant(); 

затем вы можете преобразовать Instant в любой API даты в jdk 8, используя метод ofInstant ():

LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault()); 

public static LocalDate Date2LocalDate(Date date) {
        return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))

этот формат Date#tostring

    public String toString() {
        // "EEE MMM dd HH:mm:ss zzz yyyy";
        BaseCalendar.Date date = normalize();
        StringBuilder sb = new StringBuilder(28);
        int index = date.getDayOfWeek();
        if (index == BaseCalendar.SUNDAY) {
            index = 8;
        }
        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd

        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
        TimeZone zi = date.getZone();
        if (zi != null) {
            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
        } else {
            sb.append("GMT");
        }
        sb.append(' ').append(date.getYear());  // yyyy
        return sb.toString();
    }

У меня были проблемы с реализацией @JodaStephen на JBoss EAP 6. Итак, я переписал преобразование после Java-учебника Oracle вhttp://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html.

    Date input = new Date();
    GregorianCalendar gregorianCalendar = (GregorianCalendar) Calendar.getInstance();
    gregorianCalendar.setTime(input);
    ZonedDateTime zonedDateTime = gregorianCalendar.toZonedDateTime();
    zonedDateTime.toLocalDate();

что не так с этой 1 простой строкой?

new LocalDateTime(new Date().getTime()).toLocalDate();

можно использовать java.sql.Date в качестве промежуточного литья для преобразования между LocalDate и util.Date

и util.Date С LocalDate скачать sql.date С LocalDate и cast на util.Date

java.util.Date date = (java.util.Date) java.sql.Date.valueOf(localDate);

и LocalDate С util.Date cast util.Date до sql.Date сначала, а потом называть toLocalDate() on sql.Date

LocalDate localDate = ((java.sql.Date)java.util.Date).toLocalDate();

Я решил этот вопрос с Решение ниже

  import org.joda.time.LocalDate;
  Date myDate = new Date();
  LocalDate localDate = LocalDate.fromDateFields(myDate);
  System.out.println("My date using Date" Nov 18 11:23:33 BRST 2016);
  System.out.println("My date using joda.time LocalTime" 2016-11-18);

в этом случае localDate напечатает вашу дату в этом формате"гггг-ММ-ДД"