Przekonwertuj LocalDate na LocalDateTime lub java.sql.Timestamp

126

Używam JodaTime 1.6.2.

Mam element, LocalDatektóry muszę przekonwertować na (Joda) LocalDateTimelub a java.sqlTimestampfor ormapping.

Powodem tego jest to, że odkryłem, jak przekonwertować między a LocalDateTimei a java.sql.Timestamp:

LocalDateTime ldt = new LocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.forPattern("yyyy-MM-dd HH:mm:ss");
Timestamp ts = Timestamp.valueOf(ldt.toString(dtf));

Tak więc, jeśli mogę po prostu przekonwertować między LocalDatei LocalDateTime, mogę kontynuować konwersję do formatu java.sql.Timestamp. Dziękujemy za wszelkie działania we właściwym kierunku!

IAmYourFaja
źródło
FYI, projekt Joda-Time jest teraz w trybie konserwacji , a zespół doradza migrację do klas java.time . Zobacz samouczek firmy Oracle . Ponadto java.sql.Timestampklasa jest już starsza, wyparta przez klasy java.time , a konkretnie przez Instant.
Basil Bourque

Odpowiedzi:

270

JodaTime

Aby przekonwertować JodaTime na org.joda.time.LocalDatecelu java.sql.Timestamp, po prostu zrób

Timestamp timestamp = new Timestamp(localDate.toDateTimeAtStartOfDay().getMillis());

Aby przekonwertować JodaTime na org.joda.time.LocalDateTimecelu java.sql.Timestamp, po prostu zrób

Timestamp timestamp = new Timestamp(localDateTime.toDateTime().getMillis());

JavaTime

Aby przekonwertować Java8 na java.time.LocalDatecelu java.sql.Timestamp, po prostu zrób

Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay());

Aby przekonwertować Java8 na java.time.LocalDateTimecelu java.sql.Timestamp, po prostu zrób

Timestamp timestamp = Timestamp.valueOf(localDateTime);
BalusC
źródło
Uważaj podczas konwersji LocalDateTimena, DateTimeponieważ nie wszystkie LocalDateTimes są prawidłowe DateTime. Źródło: joda-time.sourceforge.net/faq.html#illegalinstant i właśnie w to wpadam .
Christophe De Troyer
otrzymano błąd kompilacji argumentu, ponieważ valueOf () akceptuje ciąg.
Patriotyczny
@Patriotic: Stanie się tak tylko wtedy, gdy faktycznie nie używasz Java SE 1.8 lub nowszej. Jak wskazano w odpowiedzi oraz w podanych linkach do Javadoc (niebieskie teksty w powyższej odpowiedzi są w rzeczywistości linkami, możesz je kliknąć, aby przejść do Javadoc), Timestamp#valueOf()metoda akceptuje, ponieważ Java SE 1.8 również a LocalDateTime.
BalusC
60

Najlepszy sposób na wykorzystanie czasu API Java 8:

  LocalDateTime ldt = timeStamp.toLocalDateTime();
  Timestamp ts = Timestamp.valueOf(ldt);

Do użytku z JPA umieszczonym w modelu ( https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa ):

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime ldt) {
        return Timestamp.valueOf(ldt);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp ts) {
        return ts.toLocalDateTime();
    }
}

Więc teraz jest to względny czas niezależny od strefy czasowej. Dodatkowo jest to łatwe:

  LocalDate ld = ldt.toLocalDate();
  LocalTime lt = ldt.toLocalTime();

Formatowanie:

 DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
 String str = ldt.format(DATE_TME_FORMATTER);
 ldt = LocalDateTime.parse(str, DATE_TME_FORMATTER);

UPDATE: postgres 9.4.1208, HSQLDB 2.4.0 itd. Rozumieją Java 8 Time API bez żadnych rozmów!

Grigorij Kislin
źródło
17

tl; dr

Projekt Joda-Time jest w trybie konserwacji, który został zastąpiony przez klasy java.time .

  • Po prostu użyjjava.time.Instant klasy.
  • Nie ma potrzeby:
    • LocalDateTime
    • java.sql.Timestamp
    • Smyczki

Uchwyć aktualny moment w UTC.

Instant.now()  

Aby zapisać ten moment w bazie danych:

myPreparedStatement.setObject(  , Instant.now() )  // Writes an `Instant` to database.

Aby pobrać ten moment z bazy danych:

myResultSet.getObject(  , Instant.class )  // Instantiates a `Instant`

Aby ustawić zegar ścienny na czas w określonej strefie czasowej.

instant.atZone( z )  // Instantiates a `ZonedDateTime`

LocalDateTime to zła klasa

Inne odpowiedzi są poprawne, ale nie wskazują, że LocalDateTimejest to niewłaściwa klasa do twojego celu.

W obu java.time i Joda-Time , A LocalDateTimecelowo pozbawiony jakichkolwiek koncepcji strefy czasowej lub przesunięcia-from-UTC. W związku z tym nie reprezentuje momentu i nie jest punktem na osi czasu. A LocalDateTimereprezentuje przybliżony pogląd potencjalnych momentach w zakresie około 26-27 godzin.

Użyj LocalDateTimedla, gdy strefa / przesunięcie jest nieznane (nie jest to dobra sytuacja) lub gdy przesunięcie strefy jest nieokreślone. Na przykład „Boże Narodzenie zaczyna się od pierwszej chwili 25 grudnia 2018 r.” Będzie reprezentowane jako plikLocalDateTime .

Użyj a, ZonedDateTimeaby przedstawić moment w określonej strefie czasowej. Na przykład Boże Narodzenie rozpoczynające się w określonej strefie, takiej jak Pacific/Aucklandlub America/Montrealbyłoby reprezentowane za pomocąZonedDateTime obiekt.

Przez chwilę zawsze w UTC użyj Instant.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

Zastosuj strefę czasową. Ten sam moment, ten sam punkt na osi czasu, ale oglądany z innym czasem na zegarze ściennym.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock time.

Tak więc, jeśli mogę po prostu przekonwertować między LocalDate i LocalDateTime,

Nie, zła strategia. Jeśli masz tylko wartość daty i chcesz mieć wartość daty i godziny, musisz określić godzinę. Ta pora dnia może nie obowiązywać w tym dniu dla określonej strefy - w takim przypadku ZonedDateTimeklasa automatycznie dostosowuje porę dnia w razie potrzeby.

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 14 , 0 ) ;  // 14:00 = 2 PM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

Jeśli chcesz, aby pierwsza chwila dnia była Twoją porą dnia, pozwól java.time określić ten moment. Nie zakładaj, że dzień zaczyna się o 00:00:00. Anomalie, takie jak czas letni (DST), oznaczają, że dzień może zacząć się o innej godzinie, na przykład o godzinie 01:00:00.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp to zła klasa

java.sql.TimestampJest częścią kłopotliwych starych klas daty i godziny, które są teraz Legacy, supplanted całości przez java.time klas. Ta klasa była używana do reprezentowania momentu w UTC z rozdzielczością nanosekund . Temu celowi służy teraz java.time.Instant.

JDBC 4.2 z getObject/setObject

Począwszy od JDBC 4.2 i nowszych, sterownik JDBC może bezpośrednio wymieniać obiekty java.time z bazą danych, wywołując:

Na przykład:

myPreparedStatement.setObject(  , instant ) ;

… i …

Instant instant = myResultSet.getObject(  , Instant.class ) ;

Konwertuj starsze ⬌ nowoczesne

Jeśli musisz łączyć się ze starym kodem, który nie został jeszcze zaktualizowany do java.time , przekonwertuj tam iz powrotem, używając nowych metod dodanych do starych klas.

Instant instant = myJavaSqlTimestamp.toInstant() ;  // Going from legacy class to modern class.

…i…

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( instant ) ;  // Going from modern class to legacy class.

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas.

Skąd wziąć klasy java.time?

  • Java SE 8 , Java SE 9 i nowsze
    • Wbudowany.
    • Część standardowego interfejsu API języka Java z dołączoną implementacją.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i Java SE 7
    • Wiele funkcji java.time jest przenoszonych z powrotem do Java 6 i 7 w ThreeTen-Backport .
  • Android
    • Późniejsze wersje implementacji klas java.time w pakietach Androida.
    • Dla wcześniejszej Androida (<26), ThreeTenABP projekt dostosowuje ThreeTen-backportu (jak wyżej). Zobacz Jak używać ThreeTenABP… .

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
5

W zależności od strefy czasowej możesz stracić kilka minut (1650-01-01 00:00:00 staje się 1649-12-31 23:52:58)

Użyj poniższego kodu, aby tego uniknąć

new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);
user1302021
źródło
3

Ponieważ Joda staje się wyblakły, ktoś może chcieć przekonwertować LocaltDatego LocalDateTimena Javę 8. W Javie 8 LocalDateTimeda to możliwość stworzenia LocalDateTimeinstancji przy użyciu LocalDatei LocalTime. Sprawdź tutaj.

public static LocalDateTime of (data LocalDate, czas lokalny)

Próbka byłaby:

    // just to create a sample LocalDate
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
    LocalDate ld = LocalDate.parse("20180306", dtf);

    // convert ld into a LocalDateTime
    // We need to specify the LocalTime component here as well, it can be any accepted value
    LocalDateTime ldt = LocalDateTime.of(ld, LocalTime.of(0,0)); // 2018-03-06T00:00

Tylko w celach informacyjnych, aby uzyskać poniżej epokowe sekundy, można użyć

    ZoneId zoneId = ZoneId.systemDefault();
    long epoch = ldt.atZone(zoneId).toEpochSecond(); 

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
główny
źródło
LocalDateTimeW ogóle nie ma potrzeby używania tutaj. Ta klasa celowo nie ma pojęcia strefy czasowej ani przesunięcia względem czasu UTC. Więc nie służy to tutaj żadnemu użytecznemu celowi. Zamiast tego: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()nie zakładaj, że dzień zaczyna się o godzinie 00:00, nie zawsze tak jest.
Basil Bourque
Co masz na myśli mówiąc, nie zakładaj, że dzień zaczyna się o 00:00
pierwsza
1
Anomalie, takie jak czas letni (DST), oznaczają, że w niektórych dniach w niektórych miejscach dzień może zaczynać się o innej godzinie, na przykład o godzinie 01:00:00. Więc zamiast zakładać, pozwól java.time określić pierwszy moment, wywołując java.time.LocalDate.atStartOfDayplik ZonedDateTime. Zobacz przykłady w mojej odpowiedzi . Jak już wspomniałem, LocalDateTimezajęcia są w tym wszystkim bezużyteczne i przynoszą skutki odwrotne do zamierzonych.
Basil Bourque
Więc z LocalDateTimemusimy użyć ZoneId?
prime
Myślę, że przegapiłeś wszystkie moje punkty. Przeczytaj ponownie moją odpowiedź na tej stronie. Search Stack Overflow, aby dowiedzieć się więcej z wielu innych przykładów i dyskusji. Ale powiem po raz ostatni tutaj: LocalDateTimejest nie odpowiednie do problemu pod ręką tutaj. LocalDateTimeSposób nie reprezentują chwilę. A nieLocalDateTime ma nic wspólnego z konkretną lokalizacją lub strefą czasową, chociaż na pierwszy rzut oka nazwa może sugerować inaczej - dowiedz się więcej o zamiarze i szczegółach tej klasy. LocalDateTimeKlasa ma służyć jakiemuś celowi, ale nie cel widział w tej kwestii.
Basil Bourque
2

wywołanie funkcji asStartOfDay()na java.time.LocalDateobiekcie zwraca java.time.LocalDateTimeobiekt

Ahmad sibai
źródło
0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)
Mohamed Abdo
źródło
Przydatne, ale tak naprawdę nie wydaje się odpowiadać na pytanie.
Ole VV
Dzięki za kod, ale nie ma to nic wspólnego z pytaniem.
refaelio