Converta LocalDate em LocalDateTime ou java.sql.Timestamp

126

Estou usando o JodaTime 1.6.2.

Eu tenho um LocalDateque eu preciso converter para um (Joda) LocalDateTimeou um java.sqlTimestamppara ormapping.

A razão para isso é que eu descobri como converter entre a LocalDateTimee 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));

Portanto, se eu puder apenas converter entre LocalDatee LocalDateTime, então eu posso fazer a conversão contínua para java.sql.Timestamp. Obrigado por qualquer cutucada na direção certa!

IAmYourFaja
fonte
Para sua informação, o projeto Joda-Time agora está no modo de manutenção , com a equipe aconselhando a migração para as classes java.time . Consulte o Tutorial da Oracle . Além disso, a java.sql.Timestampclasse agora é herdada, substituída pelas classes java.time , especificamente por Instant.
Basil Bourque

Respostas:

269

JodaTime

Para converter JodaTime org.joda.time.LocalDatepara java.sql.Timestamp, basta fazer

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

Para converter JodaTime org.joda.time.LocalDateTimepara java.sql.Timestamp, basta fazer

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

JavaTime

Para converter Java8 java.time.LocalDatepara java.sql.Timestamp, basta fazer

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

Para converter Java8 java.time.LocalDateTimepara java.sql.Timestamp, basta fazer

Timestamp timestamp = Timestamp.valueOf(localDateTime);
BalusC
fonte
Cuidado ao converter LocalDateTimepara DateTimecomo nem todos os LocalDateTimes são válidos DateTime. Fonte: joda-time.sourceforge.net/faq.html#illegalinstant e apenas encontrando isso.
Christophe De Troyer
obteve erro de compilação no argumento, pois valueOf () aceita uma string.
Patriótico
@ Patriótico: isso só acontecerá se você não estiver usando o Java SE 1.8 ou mais recente. Conforme indicado na resposta e nos links fornecidos para o Javadoc (os textos em azul na resposta acima são na verdade links, você pode clicar neles para detalhar o Javadoc), o Timestamp#valueOf()método aceita, já que o Java SE 1.8 também a LocalDateTime.
BalusC 03/07
60

A melhor maneira de usar a API do Java 8:

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

Para uso com o JPA inserido no seu modelo ( 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();
    }
}

Portanto, agora é o tempo independente do fuso horário relativo. Além disso, é fácil fazer:

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

Formatação:

 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 etc entendem a API do Java 8 Time sem nenhuma conversa!

Grigory Kislin
fonte
17

tl; dr

O projeto Joda-Time está no modo de manutenção, agora substituído pelas classes java.time .

  • Basta usarjava.time.Instant classe.
  • Não há necessidade de:
    • LocalDateTime
    • java.sql.Timestamp
    • Cordas

Capture o momento atual no UTC.

Instant.now()  

Para armazenar esse momento no banco de dados:

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

Para recuperar esse momento da base de dados:

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

Para ajustar a hora do relógio de parede com a de um fuso horário específico.

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

LocalDateTime é a classe errada

Outras respostas estão corretas, mas não apontam que essa LocalDateTimeé a classe errada para o seu propósito.

No java.time e no Joda-Time , um LocalDateTimepropositalmente não possui qualquer conceito de fuso horário ou deslocamento do UTC. Como tal, não representa um momento e não é um ponto na linha do tempo. A LocalDateTimerepresenta uma idéia aproximada de momentos em potencial ao longo de um período de 26 a 27 horas.

Use a LocalDateTimepara quando a zona / deslocamento for desconhecida (não é uma boa situação) ou quando o deslocamento da zona for indeterminado. Por exemplo, "O Natal começa no primeiro momento de 25 de dezembro de 2018" seria representado como a LocalDateTime.

Use a ZonedDateTimepara representar um momento em um fuso horário específico. Por exemplo, o Natal começando em qualquer zona específica, como Pacific/Aucklandou America/Montrealseria representada com um ZonedDateTimeobjeto.

Por um momento sempre no UTC, use Instant.

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

Aplique um fuso horário. Mesmo momento, mesmo ponto na linha do tempo, mas visualizado com uma hora diferente do relógio de parede.

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

Então, se eu puder converter entre LocalDate e LocalDateTime,

Não, estratégia errada. Se você possui um valor somente de data e deseja um valor de data e hora, deve especificar uma hora do dia. Essa hora do dia pode não ser válida nessa data para uma zona específica - nesse caso, a ZonedDateTimeclasse ajusta automaticamente a hora do dia, conforme necessário.

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

Se você deseja o primeiro momento do dia como sua hora do dia, deixe java.time determinar esse momento. Não assuma que o dia começa às 00:00:00. Anomalias como horário de verão (DST) significam que o dia pode começar em outro horário, como 01:00:00.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp é a classe errada

O java.sql.Timestampfaz parte dos incômodos aulas de data e hora de idade que estão agora legado, suplantaram inteiramente pelos java.time classes. Essa classe foi usada para representar um momento no UTC com uma resolução de nanossegundos . Esse propósito agora é servido java.time.Instant.

JDBC 4.2 com getObject/setObject

A partir do JDBC 4.2 e posterior, seu driver JDBC pode trocar diretamente objetos java.time com o banco de dados chamando:

Por exemplo:

myPreparedStatement.setObject(  , instant ) ;

... e ...

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

Converter legado ⬌ moderno

Se você precisar interagir com o código antigo ainda não atualizado para java.time , converta-o usando os novos métodos adicionados às classes antigas.

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

…e…

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

Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade de java.sql.*classes.

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações do pacote Android das classes java.time.
    • Para anteriormente Android (<26), o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

O projeto ThreeTen-Extra estende java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
5

Dependendo do fuso horário, você pode perder alguns minutos (1650-01-01 00:00:00 passa a 1649-12-31 23:52:58)

Use o código a seguir para evitar que

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

Desde Joda é se desvaneceu, alguém pode querer converter LocaltDatea LocalDateTimeem Java 8. Em Java 8 LocalDateTimevai dar um jeito de criar uma LocalDateTimeinstância usando um LocalDatee LocalTime. Confira aqui.

public static LocalDateTime of (LocalDate date, LocalTime time)

A amostra seria,

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

Apenas para referência, para obter a época segundos abaixo pode ser usado,

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

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
prime
fonte
Não há necessidade de usar LocalDateTimetudo aqui. Essa classe propositalmente não possui qualquer conceito de fuso horário ou deslocamento do UTC. Portanto, não serve para nada aqui. Em vez disso: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()não assuma que o dia começa às 00:00, nem sempre é o caso.
Basil Bourque
O que você quer dizer com não assuma que o dia começa às 00:00
prime
1
Anomalias como o horário de verão (DST) significam que em algumas datas em alguns locais o dia pode começar em outro horário, como 01:00:00. Portanto, em vez de supor, deixe java.time determinar o primeiro momento chamando java.time.LocalDate.atStartOfDaypara obter a ZonedDateTime. Veja exemplos na minha resposta . Como comentei, a LocalDateTimeclasse é inútil e contraproducente em tudo isso.
Basil Bourque
Então, com LocalDateTimedevemos usar um ZoneId?
Primeiro-
Eu acho que você perdeu todos os meus pontos. Releia minha resposta nesta página. Pesquise o Stack Overflow para aprender mais com muitos outros exemplos e discussões. Mas direi pela última vez aqui: nãoLocalDateTime é apropriado para o problema em questão aqui. Um não não representam um momento. A não tem nada a ver com nenhuma localidade ou fuso horário específico, embora o nome possa implicar à primeira vista - aprenda mais sobre a intenção e os detalhes dessa classe. A classe serve a um propósito, mas não ao objetivo visto nesta pergunta. LocalDateTimeLocalDateTimeLocalDateTime
Basil Bourque
2

chamada de função asStartOfDay()no java.time.LocalDateobjeto retorna um java.time.LocalDateTimeobjeto

Ahmad sibai
fonte
0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)
Mohamed.Abdo
fonte
Útil, mas realmente não parece responder à pergunta.
VV Ole
Obrigado pelo código, mas não tem nada a ver com a pergunta.
refaelio 21/01/19