Який найкращий спосіб перетворити 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 GMT / UTC).
Клас, еквівалентний java.util.Date
JSR-310, є Instant
, таким чином, існує зручний спосіб toInstant()
забезпечення перетворення:
Date input = new Date();
Instant instant = input.toInstant();
java.util.Date
Примірник не має поняття про час зони. Це може здатися дивним, якщо ви зателефонуєте toString()
на "a" 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
також не містить інформації про часовий пояс. LocalDate
API говорить «датувати без часового поясу». Тоді чому перетворення від Date
до Instant
до LocalDate
потреб atZone(ZoneId.systemDefault())
?
LocalDate
і LocalDateTime
не "зберігати і не представляти час або часовий пояс" (посилання: 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
Я особисто використовую клас утиліти (але він не підтримує підтримку):
/**
* 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();
Тоді ви можете конвертувати Миттєвий пошук до будь-якого 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-підручника 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();
Я вирішив це питання з рішенням нижче
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 надрукує свою дату у такому форматі "yyyy-MM-dd"
java.time
класи в JDK8, а не Joda Time.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
думав, що це рівнозначно вашому, але більш пряме.