Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Xử lý múi giờ trong ứng dụng web

Đọc các phương pháp hay nhất về tiết kiệm ánh sáng ban ngày và múi giờ cho câu hỏi. Của bạn về cơ bản là một bản sao.

Máy chủ ở UTC

Có, thông thường các máy chủ phải đặt hệ điều hành của chúng thành UTC làm múi giờ hoặc nếu không được cung cấp, hãy sử dụng GMT hoặc múi giờ Reykjavík Iceland. Việc triển khai Java của bạn có thể chọn cài đặt này làm múi giờ mặc định hiện tại của riêng nó.

Chỉ định múi giờ

Nhưng không phụ thuộc vào múi giờ được đặt thành UTC. Một sysadmin có thể thay đổi nó. Và bất kỳ mã Java nào trong bất kỳ chuỗi nào của bất kỳ ứng dụng nào trong JVM của bạn đều có thể thay đổi múi giờ mặc định hiện tại của JVM tại thời gian chạy bằng cách gọi TimeZone.setDefault . Vì vậy, thay vào đó, hãy tạo thói quen luôn chỉ định múi giờ mong muốn / mong muốn bằng cách chuyển đối số tùy chọn trong mã Java của bạn.

Tôi coi đó là một lỗ hổng thiết kế mà bất kỳ khuôn khổ ngày-giờ nào cũng có thể làm cho múi giờ trở thành tùy chọn. Việc trở thành tùy chọn tạo ra vô số nhầm lẫn bởi vì các lập trình viên, giống như mọi người khác, suy nghĩ một cách vô thức về múi giờ cá nhân của họ trừ khi được nhắc nhở. Vì vậy, tất cả quá thường xuyên trong công việc hẹn giờ không chú ý đến vấn đề này. Thêm vào vấn đề là mặc định JVM khác nhau. Nhân tiện, ditto cho Locale , các vấn đề tương tự, phải luôn được chỉ định rõ ràng.

UTC

Logic kinh doanh, lưu trữ dữ liệu và trao đổi dữ liệu của bạn hầu như luôn phải được thực hiện trong UTC. Gần như mọi cơ sở dữ liệu đều có tính năng điều chỉnh bất kỳ đầu vào nào vào UTC và lưu trữ trong UTC.

Khi hiển thị ngày-giờ cho người dùng, hãy điều chỉnh theo múi giờ dự kiến. Khi tuần tự hóa một giá trị ngày-giờ, hãy sử dụng các định dạng chuỗi ISO 8601. Xem Câu trả lời của VickyArora cụ thể cho Oracle (Tôi là người Postgres). Đảm bảo đọc kỹ tài liệu và thực hành bằng cách thử nghiệm để hiểu đầy đủ hành vi của cơ sở dữ liệu của bạn. Về vấn đề này, đặc tả SQL không chính xác lắm và hành vi rất khác nhau.

java.sql

Hãy nhớ rằng khi sử dụng Java và JDBC, bạn sẽ sử dụng java.sql.Timestamp và các kiểu dữ liệu liên quan. Chúng luôn ở trạng thái UTC, một cách tự động. Trong tương lai, bạn sẽ thấy các trình điều khiển JDBC được cập nhật để sử dụng trực tiếp các kiểu dữ liệu mới được xác định trong khung java.time được tích hợp trong Java 8 trở lên.

java.time

Các lớp cũ được java.time sửa chữa. Học cách sử dụng java.time đồng thời tránh sử dụng java.util.Date/.Calendar cũ và làm cho cuộc sống lập trình của bạn dễ chịu hơn nhiều.

Cho đến khi trình điều khiển JDBC của bạn được cập nhật, bạn có thể sử dụng các phương pháp chuyển đổi tiện lợi được tích hợp trong java.time. Xem các ví dụ tiếp theo, trong đó Instant là một thời điểm trong UTC và ZonedDateTime là một Instant được điều chỉnh thành một múi giờ.

Instant instant = myJavaSqlTimestamp.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Để đi theo hướng khác.

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( zdt.toInstant() );

Nếu bạn cần múi giờ gốc, hãy lưu trữ nó

Nếu các yêu cầu kinh doanh của bạn coi múi giờ của dữ liệu đầu vào ban đầu là quan trọng cần được ghi nhớ, thì hãy lưu trữ rõ ràng múi giờ đó dưới dạng một cột riêng biệt trong bảng cơ sở dữ liệu của bạn. Bạn có thể sử dụng offset-from-UTC, nhưng điều đó không cung cấp đầy đủ thông tin. Múi giờ là khoảng lệch cộng một bộ quy tắc để xử lý các hiện tượng bất thường trong quá khứ, hiện tại và tương lai, chẳng hạn như Giờ tiết kiệm ánh sáng ban ngày. Vì vậy, một tên múi giờ thích hợp là thích hợp nhất, chẳng hạn như America/Montreal .

Chỉ ngày là không rõ ràng

Bạn cho biết bạn thu thập nhiều giá trị chỉ ngày, không có thời gian trong ngày và không có múi giờ. Lớp cho điều đó trong java.time là LocalDate . Như với LocalTimeLocalDateTime , phần “Địa phương…” có nghĩa là không có địa phương cụ thể, do đó không có múi giờ và do đó không phải là một điểm trên dòng thời gian - không có ý nghĩa thực sự.

Hãy nhớ rằng giá trị chỉ ngày là không rõ ràng theo định nghĩa. Tại bất kỳ thời điểm nào, ngày khác nhau trên khắp thế giới. Ví dụ, ngay sau nửa đêm ở Paris, Pháp là một ngày mới nhưng ở Montréal Québec, ngày vẫn là “ngày hôm qua”.

Thông thường trong kinh doanh, múi giờ nào đó là tiềm ẩn, thậm chí là trực giác một cách vô thức. Trực giác vô thức về các điểm dữ liệu có xu hướng không hoạt động tốt trong thời gian dài, đặc biệt là trong phần mềm. Tốt hơn nên làm rõ ràng múi giờ dự định. Bạn có thể lưu trữ vùng dự định cùng với ngày, chẳng hạn như một cột khác trong bảng cơ sở dữ liệu hoặc bạn có thể đưa ra nhận xét trong mã lập trình của mình. Tôi tin rằng việc lưu trữ giá trị ngày-giờ sẽ tốt hơn và an toàn hơn rất nhiều. Vậy làm cách nào để chuyển đổi ngày chỉ thành ngày giờ?

Thường thì một ngày mới là thời điểm sau nửa đêm, thời điểm đầu tiên trong ngày. Bạn có thể nghĩ rằng điều đó có nghĩa là 00:00:00.0 thời gian trong ngày nhưng không phải lúc nào cũng vậy. Giờ tiết kiệm ánh sáng ban ngày (DST) và có thể là các hiện tượng bất thường khác có thể đẩy khoảnh khắc đầu tiên sang một thời điểm đồng hồ treo tường khác. Hãy để java.time xác định thời gian chính xác trong ngày cho khoảnh khắc đầu tiên qua LocalDate lớp và atStartOfDay của nó phương pháp.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
ZonedDateTime todayStart = today.atStartOfDay( zoneId );

Trong một số bối cảnh kinh doanh, một ngày mới có thể được xác định (hoặc giả định) là giờ làm việc. Ví dụ:giả sử một nhà xuất bản ở New York có nghĩa là 9 giờ sáng theo giờ địa phương của họ khi họ nói “bản thảo sách sẽ đến hạn trước ngày 2 tháng 1”. Hãy lấy thời gian trong ngày đó cho ngày đó theo múi giờ đó.

ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.of( 2016 , 1 , 2 , 9 , 0 , 0 , 0 , zoneId );

Điều đó có ý nghĩa gì đối với tác giả làm việc tại New Zealand? Điều chỉnh múi giờ cụ thể của cô ấy để thuyết trình với cô ấy bằng cách gọi withZoneSameInstant .

ZoneId zoneId_Pacific_Auckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt_Pacific_Auckland = zdt.withZoneSameInstant( zoneId_Pacific_Auckland );

Cơ sở dữ liệu

Để lưu trữ cơ sở dữ liệu, chúng tôi chuyển đổi thành Instant (một khoảnh khắc trên dòng thời gian ở UTC) và chuyển dưới dạng java.sql.Timestamp như đã thấy ở trên.

java.sql.Timestamp ts = java.sql.Timestamp.from( zdt.toInstant() );

Khi được truy xuất từ ​​cơ sở dữ liệu, hãy chuyển đổi trở lại ngày-giờ ở New York. Chuyển đổi từ java.sql.Timestamp tới một Instant , sau đó áp dụng múi giờ ZoneId để nhận ZonedDateTime .

Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Nếu trình điều khiển cơ sở dữ liệu của bạn tuân thủ JDBC 4.2 trở lên, bạn có thể chuyển / tìm nạp các loại java.time trực tiếp thay vì chuyển đổi sang / từ các loại java.sql. Hãy thử PreparedStatement::setObjectResultSet::getObject các phương pháp.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-01017 Tên người dùng / Mật khẩu không hợp lệ khi kết nối với cơ sở dữ liệu 11g từ ứng dụng khách 9i

  2. Làm cách nào để đếm số từ trong một chuỗi trong Oracle?

  3. Oracle nhận giá trị tổng kiểm tra cho một đoạn dữ liệu được xác định bởi một mệnh đề chọn

  4. Cách bật tính năng theo dõi trong ứng dụng oracle r12

  5. Phân vùng động bảng Oracle