Каков наилучший способ преобразования java.util.Dateобъекта в новый JDK 8 / JSR-310 java.time.LocalDate?
Date input = new Date();
LocalDate date = ???
Каков наилучший способ преобразования 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();
объяснение
Несмотря на свое название, 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.
InstantТакже не содержит никакой информации о часовом поясе. Таким образом, чтобы преобразовать Instantдату в местную, необходимо указать часовой пояс. Это может быть зона по умолчанию ZoneId.systemDefault()- или это может быть часовой пояс, которым управляет ваше приложение, например часовой пояс из пользовательских настроек. Используйте atZone()метод, чтобы применить часовой пояс:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
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 был добавлен новый метод , который немного упрощает эту задачу:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Эта новая альтернатива является более прямой, создает меньше мусора и, следовательно, должна работать лучше.
Dateне имеет понятия часового пояса, а Instantтакже не содержит информацию о часовом поясе. LocalDateAPI говорит «датировать без часового пояса». Тогда почему преобразование от Dateдо Instantк LocalDateпотребностям atZone(ZoneId.systemDefault())?
LocalDateи LocalDateTimeне «хранить или представлять время или часовой пояс» (ref: javadocs). Хотя они не хранят его - классы действительно представляют Localдату и / или время, поэтому преобразование в локальную дату / время подразумевает часовой пояс.
Лучший способ это:
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);
}
}
asLocalDate()Здесь метод нуль-безопасна, использует toLocalDate(), если вход java.sql.Date(он может быть переопределен драйвером JDBC к проблемам избежать часовых поясов или ненужных вычислений), в противном случае использует вышеупомянутый метод.
DateConvertUtils.
Date.toInstant().
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );
SimpleDateFormatэкземпляр ограничен текущим потоком. Он используется потокобезопасным способом. Теперь SimpleDateFormatсчитается, что он «дорогостоящий для создания экземпляра» (из-за всех необходимых ему внутренних структур данных), но вы не можете использовать его как «синглтон» (без синхронизации доступа к нему), потому что он действительно не является потоковым безопасно. ( ThreadLocalРешение может сработать, если код, «загрязняющий» Threadэтот объект, отвечает за жизненный цикл потока ... но это случается редко). Неловко. Избежание SimpleDateFormatявляется причиной использования . javax.time
SimpleDateFormat(который отбрасывается), промежуточная строка (которая отбрасывается) и стоимость синтаксического анализа. Это решение, но не рекомендуется.
Если вы используете 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));
LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();
Вы можете конвертировать в одну строку:
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());
import java.sql.Dateв вашем файле: toInstant()метод java.sql.Dateвсегда бросает.
Date input = new Date();
LocalDateTime conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();
DateЭкземпляр действительно содержит время тоже вместе с датой пока LocalDateне делает. Таким образом, вы можете сначала преобразовать его в LocalDateTimeметод, а ofInstant()затем, если хотите, без времени, затем преобразовать экземпляр в LocalDate.
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 Tutorial 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();
Что не так с этой простой строкой?
new LocalDateTime(new Date().getTime()).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 выведите вашу дату в формате «гггг-мм-дд»
java.timeклассов в JDK8, а не с Joda Time.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))думаю, что это эквивалентно вашему, но более прямолинейно.