2016-08-26 85 views
5

Tôi biết rằng một java.sql.Date nên có giờ, phút, giây và mili giây được đặt thành 0, để tuân thủ định nghĩa của ngày SQL chuẩn. Đây là tài liệu here (giống nhau trong Java 8).java.sql.Date trong Java 8 so với Java 6

Tôi cũng biết rằng Oracle DATE type các trường thời gian này của YEAR, MONTH, DAY, HOUR, MINUTE và SECOND. Nhưng không có phân đoạn thứ hai hay múi giờ.

tôi nhận thấy rằng cùng một truy vấn trong Java 6 và trong Java 8 không cư xử như nhau:

private static final String REQUETE_LISTE_CALENDRIER_DATE = 
    " SELECT ID_DATE, JOUR" + 
    " FROM CALENDRIER " + 
    " WHERE ID_DATE = ? "; 

Ràng buộc với PreparedStatement một java.sql.Date "dateCourante" được định nghĩa như thế này (mà lập một giá trị cho các lĩnh vực này thời gian):

GregorianCalendar gregorianCalendar = new GregorianCalendar(); // "now" 
java.sql.Date dateCourante = new java.sql.Date(gregorianCalendar.getTime().getTime()); // date AND time of "now" 
  • với Java 6, tôi tìm thấy một giá trị,
  • với Java 8, tôi thì không.

Trong cơ sở dữ liệu của tôi, ngày có giờ, phút, giây đến 0. Chúng ta có thể kiểm tra với truy vấn sau đây:

select to_char(id_date, 'DD/MM/YYYY HH24:MI:SS') 
from calendrier 
where id_date = to_date('26/08/2016', 'DD/MM/YYYY'); 

cung cấp cho:

26/08/2016 00:00:00

Vì vậy, những gì tôi hiểu, đó là:

  • trong Java 6, các trường thời gian của java.sql.Date được đặt thành 0 trước khi truy vấn được khởi chạy trên cơ sở dữ liệu, trong khi
  • trong Java 8, các trường thời gian của java.sql.Date được để lại như trong truy vấn.

Tôi chưa thể tìm thấy tài liệu về hành vi này.

Ai đó có thể xác nhận hoặc giải thích điều đó không?

Cách giải quyết khác, tôi sử dụng điều này, như được giải thích here: dDate = java.sql.Date.valueOf (dDate.toLocalDate()); // trong đó dDate là java.sql.Date

+5

Điều này tùy thuộc vào trình điều khiển Oracle JDBC ** ** - không phải phiên bản Java theo như tôi biết. Các trình điều khiển mới hơn không tuân thủ các thông số kỹ thuật của JDBC (vì Oracle không quan tâm đến các đặc tả riêng của nó): https://community.oracle.com/message/13398818#13398818 –

+0

Việc triển khai 'java.sql.Date' không cắt ngắn giá trị mili giây cung cấp (và iirc nó không bao giờ có); văn bản trong javadoc là một hướng dẫn cho các nhà phát triển trình điều khiển cách họ phải xử lý nó. Vì vậy, có khả năng vấn đề là làm thế nào trình điều khiển Oracle xử lý nó. –

+0

Ở trên thực sự được ghi chú trong liên kết được tham chiếu trong câu hỏi: "Nếu giá trị mili giây đã cho chứa thông tin thời gian, ** trình điều khiển sẽ đặt ** thành phần thời gian thành [...] tương ứng với số không GMT". – mustaccio

Trả lời

1

Java SE 8 cũng có các lớp cho một số trường hợp sử dụng phổ biến khác.

YearMonth

Có lớp MonthDay, trong đó có một tháng và ngày. Hữu ích cho việc đại diện cho sinh nhật.

MonthDay

Lớp YearMonth bao gồm các trường hợp sử dụng thẻ tín dụng ngày bắt đầu và ngày hết hạn và kịch bản trong đó mọi người có một ngày không có ngày cụ thể.

JDBC 4.2

JDBC trong Java SE 8 sẽ hỗ trợ các loại mới này, nhưng sẽ không có thay đổi API JDBC công khai. Các phương thức setObject và getObject chung hiện có sẽ là đủ.

2

Trong khi tôi không có lời giải thích, ngoại trừ việc nói nhiều người đã báo cáo sự cố và vi phạm JDBC với các thế hệ trình điều khiển Oracle mới nhất, tôi có thể nói rằng bạn đang lạm dụng các lớp đó. Và các lớp học tốt hơn có sẵn.

java.sql.Date là ngày chỉ

Bạn đã chọn lớp sai ở phía Java. Mặc dù lớp java.sql.Date thực sự có thời gian được đặt thành 00:00:00 trong UTC bên trong nội bộ của nó, bạn có nghĩa vụ bỏ qua thực tế đó, theo hướng dẫn của tài liệu lớp học. java.sql.Date chỉ dành cho giá trị chỉ có ngày, không có thời gian trong ngày và không có múi giờ.

Lớp học này là thiết kế kém, hack xấu, kế thừa từ java.util.Date trong khi yêu cầu bạn bỏ qua thực tế thừa kế đó.

java.sql.Timestamp là ngày thời gian

Các java.sql.Timestamp là loại bạn cần trong trường hợp của bạn chứ không phải là java.sql.Date. (Nhưng đọc tiếp để có một lớp học tốt hơn.)

Toàn bộ các lớp ngày tháng cũ từ các phiên bản đầu tiên của Java là một nỗ lực đầu tiên trong việc giải quyết vấn đề xử lý ngày giờ. ngắn. Chúng được thiết kế kém, khó hiểu và rắc rối. Tránh chúng: java.util.Date, java.util.Calendar, java.util.GregorianCalendar, java.text.DateFormat, java.text.SimpleDateFormat. Và nếu có thể, hãy tránh các loại java.sql. Thay vào đó hãy sử dụng các lớp java.time.

JDBC 4.2

Tính đến JDBC 4.2, trình điều khiển JDBC của bạn có thể truy cập trực tiếp java.time loại từ cơ sở dữ liệu của bạn. Các phương thức PreparedStatement::setObjectResultSet::getObject có thể hiển thị các giá trị ngày giờ của bạn từ cơ sở dữ liệu dưới dạng đối tượng java.time.

Instant instant = myResultSet.getObject(1); 

... hoặc có lẽ ...

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

Nếu trình điều khiển của bạn không phải là quá khả năng, sau đó chuyển đổi ngắn gọn cho các loại java.sql và ngay lập tức chuyển sang java.time mình. Làm tất cả logic nghiệp vụ của bạn bằng cách sử dụng java.time. Chỉ định loại java.sql để trao đổi dữ liệu với cơ sở dữ liệu. Để chuyển đổi sang/từ java.time, hãy tìm các phương thức mới được thêm vào các lớp cũ. Ví dụ: java.sql.Timestamp::toInstant.

Ở đây, chúng tôi trích xuất một số java.sql.Timestamp từ số ResultSet và chuyển đổi ngay lập tức thành Instant. Bạn có thể muốn làm điều này trên hai dòng thay vì một dòng kết hợp cho mục đích gỡ lỗi.

Instant instant = myResultSet.getTimestamp(1).toInstant(); 
+0

+1 để được giải thích. Tôi biết về những hạn chế của java.sql.Date và việc sử dụng java.sql.Timesamp. Tôi chưa biết các lớp java.time trông rất thú vị. – Rodjf