Konvertieren Sie LocalDate in LocalDateTime oder java.sql.Timestamp

126

Ich benutze JodaTime 1.6.2.

Ich habe eine LocalDate, die ich entweder in eine (Joda) LocalDateTimeoder eine java.sqlTimestampfür das Ormapping konvertieren muss.

Der Grund dafür ist, dass ich herausgefunden habe, wie man zwischen a LocalDateTimeund a konvertiert java.sql.Timestamp:

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

Wenn ich also nur zwischen LocalDateund konvertieren LocalDateTimekann, kann ich die fortgesetzte Konvertierung in durchführen java.sql.Timestamp. Vielen Dank für alle Anstöße in die richtige Richtung!

IAmYourFaja
quelle
Zu Ihrer Information , das Joda-Time- Projekt befindet sich jetzt im Wartungsmodus. Das Team empfiehlt die Migration zu den Klassen java.time . Siehe Tutorial von Oracle . Außerdem ist die java.sql.TimestampKlasse jetzt ein Vermächtnis, das durch die Klassen java.time ersetzt wird , insbesondere durch Instant.
Basil Bourque

Antworten:

269

JodaTime

So konvertieren JodaTime ist org.joda.time.LocalDatezu java.sql.Timestamp, gerade zu tun

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

So konvertieren JodaTime ist org.joda.time.LocalDateTimezu java.sql.Timestamp, gerade zu tun

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

JavaTime

So konvertieren Java8 ist java.time.LocalDatezu java.sql.Timestamp, gerade zu tun

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

So konvertieren Java8 ist java.time.LocalDateTimezu java.sql.Timestamp, gerade zu tun

Timestamp timestamp = Timestamp.valueOf(localDateTime);
BalusC
quelle
Achten Sie beim Konvertieren LocalDateTimeauf, DateTimeda nicht alle LocalDateTimes gültig sind DateTime. Quelle: joda-time.sourceforge.net/faq.html#illegalinstant und nur darauf stoßen .
Christophe De Troyer
Kompilierungsfehler beim Argument erhalten, da valueOf () eine Zeichenfolge akzeptiert.
Patriotischer
@Patriotic: Das passiert nur, wenn Sie Java SE 1.8 oder höher nicht verwenden. Wie in der Antwort und in den bereitgestellten Links zum Javadoc angegeben (die blauen Texte in der obigen Antwort sind tatsächlich Links, Sie können darauf klicken, um einen Drilldown in das Javadoc durchzuführen), Timestamp#valueOf()akzeptiert die Methode seit Java SE 1.8 auch a LocalDateTime.
BalusC
60

Der beste Weg, um die Java 8-Zeit-API zu verwenden:

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

Zur Verwendung mit JPA in Ihr Modell einfügen ( 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();
    }
}

Jetzt ist es also eine relative zeitzonenunabhängige Zeit. Zusätzlich ist es einfach zu tun:

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

Formatierung:

 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 usw. verstehen die Java 8 Time API ohne Konversationen!

Grigory Kislin
quelle
17

tl; dr

Das Joda-Time- Projekt befindet sich im Wartungsmodus und wird jetzt durch java.time- Klassen ersetzt.

  • Verwenden Sie einfachjava.time.Instant Klasse.
  • Kein Bedarf für:
    • LocalDateTime
    • java.sql.Timestamp
    • Saiten

Erfassen Sie den aktuellen Moment in UTC.

Instant.now()  

So speichern Sie diesen Moment in der Datenbank:

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

So rufen Sie diesen Moment aus der Datenbank ab:

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

Zum Einstellen der Wanduhrzeit auf die einer bestimmten Zeitzone.

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

LocalDateTime ist die falsche Klasse

Andere Antworten sind korrekt, weisen jedoch nicht darauf hin, dass dies LocalDateTimedie falsche Klasse für Ihren Zweck ist.

Sowohl in java.time als auch in Joda-TimeLocalDateTime fehlt einem absichtlich jedes Konzept der Zeitzone oder des Versatzes von UTC. Als solches ist es nicht repräsentiert einen Moment, und ist nicht ein Punkt auf der Timeline. A LocalDateTimerepräsentiert eine grobe Vorstellung von möglichen Momenten in einem Bereich von etwa 26 bis 27 Stunden.

Verwenden Sie a LocalDateTimefür, wenn die Zone / der Versatz unbekannt ist (keine gute Situation) oder wenn der Zonenversatz unbestimmt ist. Zum Beispiel würde "Weihnachten beginnt im ersten Moment des 25. Dezember 2018" als dargestellt LocalDateTime.

Verwenden Sie a ZonedDateTime, um einen Moment in einer bestimmten Zeitzone darzustellen. Zum Beispiel Weihnachten, das in einer bestimmten Zone beginnt Pacific/Aucklandoder America/Montrealmit einem ZonedDateTimeObjekt dargestellt wird.

Verwenden Sie für einen Moment immer in UTC Instant.

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

Wenden Sie eine Zeitzone an. Gleicher Moment, gleicher Punkt auf der Zeitachse, aber mit einer anderen Wanduhrzeit betrachtet.

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

Wenn ich also nur zwischen LocalDate und LocalDateTime konvertieren kann,

Nein, falsche Strategie. Wenn Sie einen Nur-Datum-Wert haben und einen Datums- / Uhrzeitwert möchten, müssen Sie eine Uhrzeit angeben. Diese Tageszeit ist an diesem Datum möglicherweise nicht für eine bestimmte Zone gültig. In diesem Fall ZonedDateTimepasst die Klasse die Tageszeit automatisch nach Bedarf an.

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

Wenn Sie den ersten Moment des Tages als Tageszeit verwenden möchten , lassen Sie java.time diesen Moment bestimmen. Gehen Sie nicht davon aus, dass der Tag um 00:00:00 Uhr beginnt. Anomalien wie die Sommerzeit (DST) bedeuten, dass der Tag möglicherweise zu einer anderen Zeit beginnt, z. B. um 01:00:00 Uhr.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp ist die falsche Klasse

Das java.sql.Timestampist Teil der problematischen alten Datums- / Uhrzeitklassen , die jetzt Legacy sind und vollständig durch die Klassen java.time ersetzt werden. Diese Klasse wurde verwendet, um einen Moment in UTC mit einer Auflösung von Nanosekunden darzustellen . Diesem Zweck wird jetzt gedient java.time.Instant.

JDBC 4.2 mit getObject/setObject

Ab JDBC 4.2 und höher kann Ihr JDBC-Treiber java.time-Objekte direkt mit der Datenbank austauschen, indem er Folgendes aufruft:

Beispielsweise:

myPreparedStatement.setObject(  , instant ) ;

… und …

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

Vermächtnis ⬌ modern umwandeln

Wenn Sie mit altem Code arbeiten müssen, der noch nicht auf java.time aktualisiert wurde , konvertieren Sie mit neuen Methoden, die zu den alten Klassen hinzugefügt wurden, hin und her.

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

…und…

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

Über java.time

Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie java.util.Date, Calendar, & SimpleDateFormat.

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für java.sql.*Klassen.

Woher bekomme ich die java.time-Klassen?

Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden Interval, YearWeek, YearQuarter, und mehr .

Basil Bourque
quelle
5

Abhängig von Ihrer Zeitzone können Sie einige Minuten verlieren (1650-01-01 00:00:00 wird 1649-12-31 23:52:58)

Verwenden Sie den folgenden Code, um dies zu vermeiden

new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);
user1302021
quelle
3

Da Joda verblasst immer, vielleicht will jemanden konvertieren , LocaltDateum LocalDateTimein Java 8. In Java 8 LocalDateTimees eine Möglichkeit geben eine erstellen LocalDateTimeInstanz mit ein LocalDateund LocalTime. Überprüfen Sie hier.

public static LocalDateTime von (LocalDate-Datum, LocalTime-Zeit)

Probe wäre,

    // 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

Nur als Referenz, Um die Epoche zu erhalten, können die folgenden Sekunden verwendet werden:

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

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
Prime
quelle
Hier muss LocalDateTimeüberhaupt nichts verwendet werden. Dieser Klasse fehlt absichtlich jedes Konzept der Zeitzone oder des Versatzes von UTC. Es hat hier also keinen nützlichen Zweck. Stattdessen: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()Gehen Sie nicht davon aus, dass der Tag um 00:00 Uhr beginnt, was nicht immer der Fall ist.
Basil Bourque
Was meinst du damit, nimm nicht an, dass der Tag um 00.00 Uhr beginnt
Prime
1
Anomalien wie die Sommerzeit (DST) bedeuten, dass an einigen Daten an einigen Orten der Tag zu einer anderen Zeit beginnen kann, z. B. um 01:00:00 Uhr. Also, anstatt anzunehmen, lassen Sie java.time den ersten Moment bestimmen, indem Sie aufrufen java.time.LocalDate.atStartOfDay, um a zu erhalten ZonedDateTime. Siehe Beispiele in meiner Antwort . Wie ich bereits sagte, ist die LocalDateTimeKlasse in all dem nutzlos und kontraproduktiv.
Basil Bourque
Also mit LocalDateTimemüssen wir ein verwenden ZoneId?
Prime
Ich denke, Sie haben alle meine Punkte verpasst. Lesen Sie meine Antwort auf dieser Seite erneut. Durchsuchen Sie den Stapelüberlauf, um mehr aus vielen weiteren Beispielen und Diskussionen zu erfahren. Aber ich werde hier zum letzten Mal sagen: LocalDateTimeist für das hier vorliegende Problem nicht angemessen. A LocalDateTimeist nicht einen Moment darstellen. A LocalDateTimehat nichts mit einem bestimmten Ort oder einer bestimmten Zeitzone zu tun , obwohl der Name auf den ersten Blick etwas anderes implizieren kann - erfahren Sie mehr über die Absicht und Details dieser Klasse. Die LocalDateTimeKlasse erfüllt einen Zweck, aber nicht den in dieser Frage gezeigten Zweck.
Basil Bourque
2

Funktionsaufruf asStartOfDay()für java.time.LocalDateObjekt gibt ein java.time.LocalDateTimeObjekt zurück

Ahmad Sibai
quelle
0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)
Mohamed.Abdo
quelle
Nützlich, aber scheint die Frage nicht wirklich zu beantworten.
Ole VV
Danke für den Code, aber er hat nichts mit der Frage zu tun.
Refaelio