Apa cara terbaik untuk mengonversi java.util.Date
objek ke JDK 8 / JSR-310 yang baru java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Apa cara terbaik untuk mengonversi java.util.Date
objek ke JDK 8 / JSR-310 yang baru java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Jawaban:
Jawaban singkat
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Penjelasan
Meskipun namanya, java.util.Date
mewakili instan di garis waktu, bukan "tanggal". Data aktual yang disimpan dalam objek adalah along
hitungan milidetik sejak 1970-01-01T00: 00Z (tengah malam pada awal 1970 GMT / UTC).
Kelas setara dengan java.util.Date
di JSR-310 adalah Instant
, sehingga ada metode yang mudah toInstant()
untuk menyediakan konversi:
Date input = new Date();
Instant instant = input.toInstant();
Sebuah java.util.Date
instance tidak memiliki konsep zona waktu. Ini mungkin tampak aneh jika Anda memanggil toString()
pada java.util.Date
, karena toString
relatif ke-zona waktu. Namun metode itu benar-benar menggunakan zona waktu default Java on the fly untuk memberikan string. Zona waktu bukan bagian dari keadaan aktual java.util.Date
.
An Instant
juga tidak mengandung informasi apa pun tentang zona waktu. Jadi, untuk mengonversi dari tanggal Instant
ke tanggal lokal, perlu menentukan zona waktu. Ini mungkin zona default - ZoneId.systemDefault()
- atau mungkin zona waktu yang dikontrol aplikasi Anda, seperti zona waktu dari preferensi pengguna. Gunakan atZone()
metode untuk menerapkan zona waktu:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
A ZonedDateTime
berisi keadaan yang terdiri dari tanggal dan waktu setempat, zona waktu dan offset dari GMT / UTC. Dengan demikian tanggal - LocalDate
- dapat dengan mudah diekstraksi menggunakan toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Java 9 jawaban
Di Java SE 9, metode baru telah ditambahkan yang sedikit menyederhanakan tugas ini:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Alternatif baru ini lebih langsung, menghasilkan lebih sedikit sampah, dan karenanya berkinerja lebih baik.
Date
tidak memiliki konsep zona waktu, Instant
juga tidak mengandung informasi tentang zona waktu. The LocalDate
API mengatakan "tanggal A tanpa-zona waktu". Lalu mengapa mengkonversi dari Date
ke Instant
ke LocalDate
kebutuhan atZone(ZoneId.systemDefault())
?
LocalDate
dan LocalDateTime
jangan "menyimpan atau mewakili waktu atau zona waktu" (ref: javadocs). Meskipun mereka tidak menyimpannya - kelas-kelas tersebut mewakili Local
tanggal dan / atau waktu, karenanya konversi ke tanggal / waktu setempat menyiratkan zona waktu.
Cara yang lebih baik adalah:
Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()
Keuntungan dari versi ini:
berfungsi terlepas dari input yang merupakan turunan dari java.util.Date
atau merupakan subkelas dari java.sql.Date
(tidak seperti cara @ JodaStephen). Ini biasa terjadi pada data yang berasal dari JDBC. java.sql.Date.toInstant()
selalu melempar pengecualian.
itu sama untuk JDK8 dan JDK7 dengan JSR-310 backport
Saya pribadi menggunakan kelas utilitas (tetapi tidak kompatibel dengan 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);
}
}
The asLocalDate()
Metode sini adalah nol-aman, penggunaan toLocalDate()
, jika input java.sql.Date
(mungkin overriden oleh driver JDBC untuk masalah menghindari zona waktu atau perhitungan yang tidak perlu), jika tidak menggunakan metode tersebut di atas.
DateConvertUtils
.
Date.toInstant()
.
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );
SimpleDateFormat
instance terbatas pada utas saat ini. Ini digunakan dengan cara yang aman. Sekarang, SimpleDateFormat
terkenal sebagai 'mahal untuk instantiate' (pada rekening semua struktur data internal yang dibutuhkan) tetapi Anda tidak dapat berbagi satu sebagai 'tunggal' (tanpa sinkronisasi akses ke sana), karena itu memang tidak benang- aman. (Sebuah ThreadLocal
solusi dapat bekerja jika kode 'mencemari' Thread
dalam hal ini bertanggung jawab atas siklus hidup utas ... tetapi itu jarang terjadi). Canggung. Menghindari SimpleDateFormat
adalah yang alasan untuk menggunakan javax.time
.
SimpleDateFormat
(yang dibuang), string menengah (yang dibuang), dan biaya penguraian. Ini sebuah solusi, tapi tidak direkomendasikan.
Jika Anda menggunakan Java 8, jawaban @ JodaStephen jelas yang terbaik. Namun, jika Anda bekerja dengan backport JSR-310 , Anda sayangnya harus melakukan sesuatu seperti ini:
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();
Anda dapat mengonversi dalam satu baris:
public static LocalDate getLocalDateFromDate(Date date){
return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}
pertama, mudah untuk mengubah Tanggal menjadi Instan
Instant timestamp = new Date().toInstant();
Kemudian, Anda dapat mengonversi api Instan ke api tanggal mana saja di jdk 8 menggunakan metode ofInstant ():
LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault());
import java.sql.Date
di file Anda: toInstant()
metode java.sql.Date
selalu melempar.
Date input = new Date();
LocalDateTime conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();
Mesin Date
virtual juga mengandung waktu bersama dengan tanggal sementara LocalDate
tidak. Jadi, pertama-tama Anda dapat mengonversinya menjadi LocalDateTime
menggunakan metodenya ofInstant()
maka jika Anda menginginkannya tanpa waktu, maka konversikan instance tersebut menjadi LocalDate
.
public static LocalDate Date2LocalDate(Date date) {
return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))
format ini dari 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();
}
Saya memiliki masalah dengan implementasi @ JodaStephen di JBoss EAP 6. Jadi, saya menulis ulang konversi mengikuti Tutorial Java Oracle di 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();
Apa yang salah dengan 1 baris sederhana ini?
new LocalDateTime(new Date().getTime()).toLocalDate();
Saya memecahkan pertanyaan ini dengan solusi di bawah ini
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);
Dalam hal ini localDate mencetak tanggal Anda dalam format ini "yyyy-MM-dd"
java.time
kelas - kelas di JDK8, bukan dengan Joda Time.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
pikir saya itu setara dengan milik Anda, tetapi lebih langsung.