Який найкращий спосіб перетворити 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.DateJSR-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також не містить інформації про часовий пояс. LocalDateAPI говорить «датувати без часового поясу». Тоді чому перетворення від 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()))думав, що це рівнозначно вашому, але більш пряме.