简体   繁体   English

将 java.util.Date 转换为 java.time.LocalDate

[英]Convert java.util.Date to java.time.LocalDate

What is the best way to convert a java.util.Date object to the new JDK 8/JSR-310 java.time.LocalDate ?java.util.Date对象转换为新的 JDK 8/JSR-310 java.time.LocalDate的最佳方法是什么?

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

Short answer简短的回答

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

Explanation解释

Despite its name, java.util.Date represents an instant on the time-line, not a "date".尽管它的名字, java.util.Date代表时间线上的瞬间,而不是“日期”。 The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).存储在对象中的实际数据是自 1970-01-01T00:00Z(1970 GMT/UTC 开始时的午夜) long的毫秒数。

The equivalent class to java.util.Date in JSR-310 is Instant , thus there is a convenient method toInstant() to provide the conversion: JSR-310 java.util.Date的等效类是Instant ,因此有一个方便的方法toInstant()来提供转换:

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

A java.util.Date instance has no concept of time-zone. java.util.Date实例没有时区的概念。 This might seem strange if you call toString() on a java.util.Date , because the toString is relative to a time-zone.如果您在java.util.Date上调用toString() ,这可能看起来很奇怪,因为toString是相对于时区的。 However that method actually uses Java's default time-zone on the fly to provide the string.然而,该方法实际上使用 Java 的默认时区来提供字符串。 The time-zone is not part of the actual state of java.util.Date .时区不是java.util.Date实际状态的一部分。

An Instant also does not contain any information about the time-zone. Instant也不包含有关时区的任何信息。 Thus, to convert from an Instant to a local date it is necessary to specify a time-zone.因此,要将Instant转换为本地日期,必须指定时区。 This might be the default zone - ZoneId.systemDefault() - or it might be a time-zone that your application controls, such as a time-zone from user preferences.这可能是默认区域 - ZoneId.systemDefault() - 或者它可能是您的应用程序控制的时区,例如来自用户首选项的时区。 Use the atZone() method to apply the time-zone:使用atZone()方法应用时区:

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

A ZonedDateTime contains state consisting of the local date and time, time-zone and the offset from GMT/UTC. ZonedDateTime包含由本地日期和时间、时区和与 GMT/UTC 的偏移量组成的状态。 As such the date - LocalDate - can be easily extracted using toLocalDate() :因此日期 - LocalDate - 可以使用toLocalDate()轻松提取:

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

Java 9 answer Java 9 答案

In Java SE 9, a new method has been added that slightly simplifies this task:在 Java SE 9 中,添加了一个新方法来稍微简化此任务:

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

This new alternative is more direct, creating less garbage, and thus should perform better.这种新的替代方案更直接,产生的垃圾更少,因此性能应该更好。

Better way is:更好的方法是:

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

Advantages of this version:这个版本的优点:

  • works regardless the input is an instance of java.util.Date or it's a subclass of java.sql.Date (unlike @JodaStephen's way).无论输入是java.util.Date的实例还是java.sql.Date的子类(与@JodaStephen 的方式不同),都可以工作。 This is common with JDBC-originated data.这对于源自 JDBC 的数据很常见。 java.sql.Date.toInstant() always throws an exception. java.sql.Date.toInstant()总是抛出异常。

  • it's the same for JDK8 and JDK7 with JSR-310 backport JDK8 和 JDK7 与 JSR-310 backport 相同

I personally use an utility class (but it is not backport-compatible):我个人使用一个实用程序类(但它不是向后移植兼容的):

/**
 * 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() method here is null-safe, uses toLocalDate() , if input is java.sql.Date (it may be overriden by the JDBC driver to avoid timezone problems or unnecessary calculations), otherwise uses the abovementioned method.这里的asLocalDate()方法是空安全的,使用toLocalDate() ,如果输入是java.sql.Date (它可能被 JDBC 驱动程序覆盖以避免时区问题或不必要的计算),否则使用上述方法。

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

If you're using Java 8, @JodaStephen's answer is obviously the best.如果您使用的是 Java 8,@JodaStephen 的答案显然是最好的。 However, if you're working with the JSR-310 backport , you unfortunately have to do something like this:但是,如果您正在使用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();

You can convert in one line :您可以在一行中转换:

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

first, it's easy to convert a Date to an Instant首先,将 Date 转换为 Instant 很容易

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

Then, you can convert the Instant to any date api in jdk 8 using ofInstant() method:然后,您可以使用 ofInstant() 方法将 Instant 转换为 jdk 8 中的任何日期 api:

LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault()); 
Date input = new Date();
LocalDateTime  conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();

The Date instance does contain time too along with the date while LocalDate doesn't. Date实例也包含时间和日期,而LocalDate不包含。 So you can firstly convert it into LocalDateTime using its method ofInstant() then if you want it without time then convert the instance into LocalDate .因此,您可以首先使用其方法ofInstant()将其转换为LocalDateTime ,然后如果您想要它没有时间,则将实例转换为LocalDate

To simplify the process of converting LocalDate/time to Date and vice versa, I created two charts:为了简化将 LocalDate/time 转换为 Date 的过程,反之亦然,我创建了两个图表:

  1. converting LocalDate to Date and vice versa:将 LocalDate 转换为 Date ,反之亦然:

在此处输入图像描述

  1. converting LocalDateTime to Date and vice versa:将 LocalDateTime 转换为 Date ,反之亦然:

在此处输入图像描述

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

this format is from Date#tostring此格式来自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();
    }

If you are using ThreeTen Backport including ThreeTenABP如果您使用的是 ThreeTen Backport,包括 ThreeTenABP

    Date input = new Date(); // Imagine your Date here
    LocalDate date = DateTimeUtils.toInstant(input)
            .atZone(ZoneId.systemDefault())
            .toLocalDate();

If you are using the backport of JSR 310, either you haven't got a Date.toInstant() method or it won't give you the org.threeten.bp.Instant that you need for you further conversion.如果您使用的是 JSR 310 的反向移植,要么您没有Date.toInstant()方法,要么它不会为您提供进一步转换所需的org.threeten.bp.Instant Instead you need to use the DateTimeUtils class that comes as part of the backport.相反,您需要使用作为 backport 一部分的DateTimeUtils类。 The remainder of the conversion is the same, so so is the explanation.转换的其余部分是相同的,解释也是如此。

I have had problems with @JodaStephen's implementation on JBoss EAP 6. So, I rewrote the conversion following Oracle's Java Tutorial inhttp://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .我在 JBoss EAP 6 上的 @JodaStephen 实现遇到了问题。因此,我按照http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html中的 Oracle 的 Java 教程重写了转换。

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

I solved this question with solution below我用下面的解决方案解决了这个问题

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

In this case localDate print your date in this format "yyyy-MM-dd"在这种情况下,localDate 以这种格式“yyyy-MM-dd”打印您的日期

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM