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

java.util.Date对象转换为新的JDK 8 / JSR-310 java.time.LocalDate的最佳方法是什么?

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

简短的回答

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

说明

尽pipe有它的名字, java.util.Date代表了时间线上的一个瞬间,而不是“date”。 存储在对象中的实际数据是自1970-01-01T00:00Z(1970年GMT / UTC开始时的午夜)以来的long的毫秒数。

JSR-310 java.util.Date的等价类是Instant ,所以有一个方便的方法来让toInstant()提供转换:

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

java.util.Date实例没有时区的概念。 如果您在java.util.Date上调用toString() ,这可能看起来很奇怪,因为toString是相对于时区的。 然而,这个方法实际上使用Java的默认时区来提供string。 时区不是java.util.Date实际状态的一部分。

Instant也不包含任何有关时区的信息。 因此,要从Instant转换为本地date,有必要指定一个时区。 这可能是默认区域ZoneId.systemDefault() – 或者它可能是应用程序控制的时区,例如用户首选项中的时区。 使用atZone()方法来应用时区:

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

ZonedDateTime包含由本地date和时间,时区和GMT / UTC的偏移组成的状态。 因此,可以使用toLocalDate()方便地提取date – LocalDate

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

这个新的select更直接,创造更less的垃圾,因此应该performance更好。

更好的方法是:

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

这个版本的优点:

  • 不pipeinput是java.util.Date一个实例还是它的子类java.sql.Date (不像@ JodaStephen的方式)。 这在JDBC发起的数据中很常见。 java.sql.Date.toInstant()总是抛出一个exception。

  • JDK8和JDK7与JSR-310 backport是一样的

我个人使用一个实用工具类(但是这不是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); } } 

如果input是java.sql.Date (它可能被JDBC驱动程序覆盖以避免时区问题或不必要的计算),则此处的asLocalDate()方法为null安全的,使用toLocalDate() ),否则使用上述方法。

如果你使用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) ); 

我在JossStephen在JBoss EAP 6上的实现方面遇到了问题。因此,我在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(); 
 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(); } 
 java.util.Date date = (java.util.Date) java.sql.Date.valueOf(localDate); LocalDate localDate = ((java.sql.Date)java.util.Date).toLocalDate(); 

我解决了这个问题,解决scheme如下

  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以这种格式打印date“yyyy-MM-dd”