PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Quel doit être le type de paramètre en Java lorsqu'il s'agit d'un horodatage sans fuseau horaire dans postgresql ?

tl;dr

Pour SQL utilisant la période semi-ouverte :
"SELECT * FROM tbl WHERE when !< ? AND when < ? ; "

myPreparedStatement.setObject(       // Use a prepared statement so you can pass smart objects rather than dumb strings.
    1 ,                              // Specify which placeholder is being fulfilled.
    LocalDate                        // Represent a date-only value, without time-of-day and without time zone or offset-from-UTC.
    .parse( "2014-11-20" )           // Parse an input string in standard ISO 8601 format to get a `LocalDate` object.
    .atStartOfDay()                  // Determine the first moment of the day on that date. Returns a `LocalDateTime` object representing a date with time-of-day but lacking any concept of time zone or offset-from-UTC.
) ;
myPreparedStatement.setObject( 
    2 , 
    LocalDate
    .parse( "2014-11-21" )
    .atStartOfDay()
) ;

Attention :je suppose que vous utilisez le mauvais type pour votre colonne dans votre base de données. Les moments ne peuvent être suivis qu'avec TIMESTAMP WITH TIME ZONE , pas TIMESTAMP WITHOUT TIME ZONE . Recherchez Stack Overflow pour plus d'informations.

Pas un instant

La réponse de Jens est désormais dépassée. De nos jours, vous devriez utiliser le moderne java.time classes qui ont supplanté les anciennes classes date-heure gênantes.

Ce type de données à la fois sur Postgres et sur le standard SQL manque délibérément du contexte d'un décalage par rapport à UTC ou d'un fuseau horaire. Alors, attention, ce type ne peut pas représenter un moment, n'est pas un point sur la chronologie.

Non, mauvais type de données. En plus d'être hérité et d'être terriblement défectueux dans la conception, le java.sql.Timestamp classe représente un moment, un point précis sur la chronologie. Il s'agit donc d'une incompatibilité avec votre colonne de type TIMESTAMP WITHOUT TIME ZONE .

LocalDateTime

Vous devriez plutôt utiliser le LocalDateTime classer. Cette classe représente une date avec une heure du jour mais sans aucun concept de décalage ou de fuseau horaire.

Pour récupérer une valeur de la base de données.

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

Pour envoyer une valeur à la base de données.

myPreparedStatement.setObject( … , ldt ) ;

Début de journée

Vous avez une autre incompatibilité ici. Vous fournissez une valeur de date uniquement, mais votre colonne contient des valeurs de date avec heure du jour.

Autre problème :vous utilisez des chaînes stupides là où vous devriez utiliser des objets intelligents. Depuis JDBC 4.2, nous pouvons échanger java.time objets avec la base de données. Utiliser un PreparedStatement avec des espaces réservés, et passez des objets via le `set

Pour résoudre le problème de la date avec l'heure du jour, nous devons déterminer le début de la journée. Avec LocalDateTime , nous n'avons aucune anomalie de fuseau horaire à prendre en compte. Ainsi, la journée commence toujours à 00:00. Néanmoins, nous devrions prendre l'habitude de demander java.time pour déterminer le début de la journée.

LocalDate startDate = LocalDate.parse( "2014-11-20" ) ;
LocalDate stopDate = LocalDate.parse( "2014-11-21" ) ;

LocalDateTime start = startDate.atStartOfDay() ;
LocalDateTime stop = stopDate.atStartOfDay() ;

Écrivez-vous SQL avec des espaces réservés.

Je vous suggère de changer votre façon de penser pour prendre l'habitude de l'approche semi-ouverte pour définir la durée. Dans Half-Open, le début est inclusif tandis que la fin est exclusive . Ainsi, pour la seule journée entière du 20, recherchez des dates égales ou ultérieures au 20, et allant jusqu'au, mais pas compris, le 21. En ce qui concerne cette première partie, une manière plus courte de dire "égal à ou ultérieur" est "pas avant", nous utilisons donc !< .

String sql = "SELECT * FROM tbl WHERE when !< ? AND when < ? ; " ;

Alimentez ce sql chaîne à votre instruction préparée. Passez ensuite les deux LocalDateTime objets pour les espaces réservés.

myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;