Java.util.Date öğesini java.time.LocalDate birimine dönüştür


494

Bir java.util.Datenesneyi yeni JDK 8 / JSR-310'a dönüştürmenin en iyi yolu nedir java.time.LocalDate?

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

Yanıtlar:


828

Kısa cevap

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

açıklama

İsmine rağmen, java.util.Datebir "tarih" değil, zaman çizgisinde bir anı temsil eder. Nesne içinde saklanan gerçek veriler, long1970-01-01T00: 00Z'den (1970 GMT / UTC'nin başında gece yarısı) bu yana geçen milisaniye sayısıdır.

java.util.DateJSR-310'daki eşdeğer sınıf Instant, bu nedenle toInstant()dönüşümü sağlamak için uygun bir yöntem vardır :

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

Bir java.util.Dateörneğin saat dilimi kavramı yoktur. Aradığınızda, bu garip görünebilir toString()bir üzerinde java.util.Dateçünkü toStringbir zaman dilimine göre yapılır. Ancak bu yöntem aslında dizeyi sağlamak için Java'nın varsayılan saat dilimini anında kullanır. Saat dilimi, gerçek durumunun bir parçası değildir java.util.Date.

Bir Instantde zaman dilimine hakkında herhangi bir bilgi içermez. Bu nedenle, Instantbir değeri yerel bir tarihe dönüştürmek için bir saat dilimi belirtmek gerekir. Bu varsayılan bölge olabilir - ZoneId.systemDefault()- veya uygulamanızın kontrol ettiği bir saat dilimi olabilir, örneğin kullanıcı tercihlerinden bir saat dilimi. atZone()Saat dilimini uygulamak için yöntemi kullanın :

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

A ZonedDateTime, yerel tarih ve saat, saat dilimi ve GMT / UTC'den ofsetten oluşan bir durum içerir. Bu nedenle tarih - LocalDate- kullanılarak kolayca çıkarılabilir toLocalDate():

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

Java 9 yanıtı

Java SE 9'da, bu görevi biraz basitleştiren yeni bir yöntem eklendi:

Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());

Bu yeni alternatif daha doğrudandır, daha az çöp oluşturur ve bu nedenle daha iyi performans göstermelidir.


14
Sanırım LocalDate.from(Instant.ofEpochMilli(date.getTime()))seninkine eşdeğer, ama daha doğrudan.
Marko Topolnik

9
@MarkoTopolnik derleyen ancak çalışmaz. Anında Arama bir saat dilimi içermez, bu nedenle LocalDate'i almanın bir yolu yoktur.
JodaStephen

11
@assylias Sadece sqlDate.toLocalDate () kullanın!
JodaStephen

25
@JodaStephen Datesaat dilimi kavramına Instantsahip değildir , ayrıca saat dilimi hakkında bilgi içermez. LocalDateAPI "bir zaman dilimi bulunmayan bir tarih" diyor. O zaman neden dönüştürme Dateiçin Instanthiç LocalDateihtiyaçları atZone(ZoneId.systemDefault())?
Gustavo

8
@Gustavo: LocalDateve LocalDateTime"bir saat veya saat dilimini saklama veya temsil etme" (ref: javadocs). Saklamasalar da - sınıflar bir Localtarih ve / veya saati temsil eder , dolayısıyla yerel tarih / saate dönüşüm bir saat dilimi anlamına gelir.
Cuga

158

Daha iyi bir yol:

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

Bu sürümün avantajları:

  • girdinin bir örneği java.util.Dateveya alt sınıfı ne olursa olsun çalışır java.sql.Date(@ JodaStephen'in yolunun aksine). Bu JDBC kaynaklı verilerde yaygındır. java.sql.Date.toInstant()her zaman bir istisna atar.

  • JSR-310 backport ile JDK8 ve JDK7 için aynıdır

Şahsen bir yardımcı sınıf kullanıyorum (ancak backport uyumlu değil):

/**
 * 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);
    }

}

Buradaki asLocalDate()yöntem null güvenlidir, toLocalDate()girdi ise kullanır java.sql.Date(saat dilimi sorunlarını veya gereksiz hesaplamaları önlemek için JDBC sürücüsü tarafından geçersiz kılınabilir), aksi takdirde yukarıda belirtilen yöntemi kullanır.


12
Bu daha iyi bir yolsa, çok çirkin ve ayrıntılıdır. Çok acı verici.
ceklock

3
Kabul edilen cevaba kıyasla daha iyi, nedenini açıklıyorum. Evet, çirkin, ama bu yüzden yazdı DateConvertUtils.
Oliv

Neden yeni API'da bir dönüşüm sınıfı uygulamadıklarını anlamıyorum.
ceklock

@ceklock, onlar did değil, bir dönüşüm sınıfını, ama gibi dönüşüm yöntemlerinin bir çift, uygulamak Date.toInstant().
Ole VV

2
Bir geliştirici aşağıdakileri yapabilmesi için bunları uzantı işlevleri olarak paketleyen bir Kotlin kütüphanesi var mı? Tarih x = ...; x.asLocalDate ();
Mark Ashworth

20
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );

7
Burada, SimpleDateFormatörnek geçerli iş parçacığı ile sınırlıdır . Bu edilir kullanılan bir iş parçacığı güvenli bir şekilde. Şimdi, SimpleDateFormat(ihtiyacı iç veri yapılarının tüm hesabıyla) 'örneğini pahalı' olmak ünlüdür ama olamaz paylaşmak çünkü, (bu bilgilere erişimi senkronizasyon olmadan) 'tekil' olarak birini o gerçekten parçacığı değil kasa. ( EğerThreadLocal çözüm 'kirletici' ise iş parçacığının yaşam döngüsünden sorumluysa ... ama bu nadiren olur). Garip. Kaçınmak olduğunu kullanılmasının sebebi . ThreadSimpleDateFormatjavax.time
David Bullock

6
Bu yaklaşımın çok fazla yükü vardır: 'pahalı' SimpleDateFormat(atılan), ara ip (atılan) ve ayrıştırma maliyeti. Bu bir çözüm, ama önerilmez.
David Bullock

2
@ceklock ama o zaman bu kadar sorunu olsun artık evreli
FLUP

4
@ceklock SimpleDateFormat, aynı anda yalnızca bir tarihi işleyebilir, eşzamanlı olarak kullanırsanız, karışık sonuçlar verir. Yani evet, önemli. Genel değişkente tek bir SimpleDateFormat örneği oluşturmayın.
flup

19

Java 8 kullanıyorsanız, @ JodaStephen'in cevabı kesinlikle en iyisidir. Ancak, JSR-310 backport ile çalışıyorsanız , maalesef böyle bir şey yapmanız gerekir:

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

4
Doğru değil, @ JodaStephen'in cevabı hala çalışıyor. Sadece java.util.Date'i bir Anında dönüştürmek için başka bir yola ihtiyacınız var. Bunun için org.threeten.bp.DateTimeUtils.toInstant kullanabilirsiniz: threeten.org/threetenbp/apidocs/org/threeten/bp/…
Christian Ciach

3
Backport'u kullanırken DateTimeUtils kullanılamadı, ancak ThreeTen Backport 1.0 veya üstünü kullanan herkes tarafından kullanılabilir olduğu doğru. Gösterdiğiniz için teşekkürler.
dhalsim2

14
LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();

1
Ve en basit gerçekleştirme: LocalDate.of (getYear () + 1900, getMonth () + 1, getDate ())
Grigory Kislin

Yine de kullanımdan kaldırılan diyen satırlar: |
TheRealChx101

8

Tek bir satıra dönüştürebilirsiniz:

public static LocalDate getLocalDateFromDate(Date date){
   return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}

Bu yöntemi kullanarak böyle bir hata alıyorum: java.time.DateTimeException: TemporalAccessor: 2018-01-31T11: 54: 27.964Z türünde java.time.Instant
Luigi Rubino

@LuigiRubino işaret ettiğiniz için teşekkürler. Lütfen güncellenmiş cevaba bakınız. Zone'u daha önce eklemeyi unuttum.
Sahil Chhabra

8

ilk olarak, bir Tarihi Anlık Olarak Dönüştürmek kolaydır

Instant timestamp = new Date().toInstant(); 

Daha sonra, ofInstant () yöntemini kullanarak Anında jdk 8'deki herhangi bir api tarihine dönüştürebilirsiniz:

LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault()); 

localDate, localDateTime, localTime içerir
Shedom Wei

Burada ZoneId belirtmek ne anlama gelir? API'den Date -> Instant alırsam ve bunu UTC'de 1970'den milisaniye olarak düşünebilirsem. Herhangi bir saat dilimine dönüştürülmemiş api perspektifinden sadece karşılık gelen LocalDate (yyyy-aa-dd) almak istediğimde, yerel saat dilimime bu anlık ofsete sahip olmamak için ZoneOffset.UTC kullanmamalıyım. ZoneId.systemDefault () ile örnek tarih form sunucusunu değiştirmiyor. Ör. instant 2018-10-20 0:00 değerini temsil eder ve daha sonra UTC'den 2018-10-20 yerine Yerel Tarih 2018-10-19'da aldığım Amerika / Los_Angeles'e mi geçtiniz?
Michał Ziobro

import java.sql.DateDosyanızda varsa kırılır : her zaman atar toInstant()yöntemi java.sql.Date.
Oliv

4
Date input = new Date();
LocalDateTime  conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();

DateÖrnek ise tarihle birlikte çok vakit içermiyor LocalDatedeğil. Eğer öncelikle dönüştürebilir Yani LocalDateTimeonun yöntemini kullanarak ofInstant()olmadan bunu istersen o zaman zaman sonra içine örneği dönüştürmek LocalDate.


1
public static LocalDate Date2LocalDate(Date date) {
        return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))

bu biçim şuradan 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();
    }

0

@ JodaStephen'in JBoss EAP 6'daki uygulamasında sorun yaşadım. Bu yüzden, http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html adresindeki Oracle'ın Java Eğitimi'ni izleyerek dönüşümü yeniden yazdım .

    Date input = new Date();
    GregorianCalendar gregorianCalendar = (GregorianCalendar) Calendar.getInstance();
    gregorianCalendar.setTime(input);
    ZonedDateTime zonedDateTime = gregorianCalendar.toZonedDateTime();
    zonedDateTime.toLocalDate();

-2

Bu 1 basit çizgide yanlış olan ne?

new LocalDateTime(new Date().getTime()).toLocalDate();

Java, ilkel tipte uzun süredir toLocalDate () yöntemini çağıramayacağından şikayet eder. Gerçek bir Date nesnesi kullandım; belki ovmak var ??
TheGeeko61

-8

Bu soruyu aşağıdaki çözümle çözdüm

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

Bu durumda localDate tarihinizi "yyyy-AA-gg" biçiminde yazdırın


1
Soru java.timeJoda Time ile değil JDK8'deki sınıfları kullanarak bir çözüm aramaktır.
pioto
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.