Chuyển đổi LocalDate thành LocalDateTime hoặc java.sql.Timestamp


126

Tôi đang sử dụng JodaTime 1.6.2.

Tôi có một LocalDatecái mà tôi cần phải chuyển đổi thành (Joda) LocalDateTimehoặc java.sqlTimestampđể lập bản đồ.

Lý do cho điều này là tôi đã tìm ra cách chuyển đổi giữa a LocalDateTimevà 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));

Vì vậy, nếu tôi chỉ có thể chuyển đổi giữa LocalDateLocalDateTime, thì tôi có thể thực hiện chuyển đổi tiếp tục java.sql.Timestamp. Cảm ơn cho bất kỳ ảnh khỏa thân đúng hướng!


FYI, dự án Joda-Time hiện đang ở chế độ bảo trì , với nhóm tư vấn di chuyển đến các lớp java.time . Xem Hướng dẫn của Oracle . Ngoài ra, java.sql.Timestamplớp hiện là di sản, được thay thế bởi các lớp java.time , đặc biệt bởi Instant.
Basil Bourque

Câu trả lời:


269

Thời gian

Để chuyển đổi JodaTime org.joda.time.LocalDatethành java.sql.Timestamp, chỉ cần làm

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

Để chuyển đổi JodaTime org.joda.time.LocalDateTimethành java.sql.Timestamp, chỉ cần làm

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

Thời gian Java

Để chuyển đổi Java8 java.time.LocalDatethành java.sql.Timestamp, chỉ cần làm

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

Để chuyển đổi Java8 java.time.LocalDateTimethành java.sql.Timestamp, chỉ cần làm

Timestamp timestamp = Timestamp.valueOf(localDateTime);

Coi chừng khi chuyển đổi LocalDateTimethành DateTimekhông phải tất cả LocalDateTimes đều hợp lệ DateTime. Nguồn: joda-time.sourceforge.net/faq.html#illegalinstant và chỉ cần chạy vào đây.
Barshe De Troyer

có lỗi biên dịch trên đối số khi valueOf () chấp nhận một chuỗi.
Yêu nước

@Patriotic: Điều đó sẽ chỉ xảy ra nếu bạn thực sự không sử dụng Java SE 1.8 hoặc mới hơn. Như đã chỉ ra trong câu trả lời và trong các liên kết được cung cấp cho Javadoc (các văn bản màu xanh trong câu trả lời ở trên thực sự là các liên kết, bạn có thể nhấp vào chúng để đi sâu vào Javadoc), Timestamp#valueOf()phương thức chấp nhận vì Java SE 1.8 cũng a LocalDateTime.
BalusC

60

Cách tốt nhất để sử dụng API thời gian Java 8:

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

Để sử dụng với JPA, hãy đưa vào mô hình của bạn ( https://weblogs.java.net/blog/montanajava/archive/2014/06/17/USE-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();
    }
}

Vì vậy, bây giờ nó là thời gian độc lập tương đối múi giờ. Ngoài ra, thật dễ dàng để làm:

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

Định dạng:

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

CẬP NHẬT: postgres 9.4.1208, HSQLDB 2.4.0, v.v ... hiểu API thời gian Java 8 mà không cần bất kỳ cuộc hội thoại nào!


17

tl; dr

Các Joda thời gian dự án là trong duy trì chế độ, bây giờ thay thế bởi java.time lớp.

  • Chỉ cần sử dụngjava.time.Instant lớp học.
  • Không cần:
    • LocalDateTime
    • java.sql.Timestamp
    • Dây

Ghi lại khoảnh khắc hiện tại trong UTC.

Instant.now()  

Để lưu trữ khoảnh khắc đó trong cơ sở dữ liệu:

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

Để lấy lại khoảnh khắc đó từ cơ sở dữ liệu:

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

Để điều chỉnh thời gian đồng hồ treo tường theo múi giờ cụ thể.

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

LocalDateTime là lớp sai

Các câu trả lời khác là đúng, nhưng chúng không chỉ ra rằng đó LocalDateTimelà lớp sai cho mục đích của bạn.

Trong cả java.timeJoda-Time , một LocalDateTimecách cố ý thiếu bất kỳ khái niệm nào về múi giờ hoặc offset-từ-UTC. Như vậy, nó không đại diện cho một khoảnh khắc, và không phải là một điểm trên dòng thời gian. A LocalDateTimeđại diện cho một ý tưởng sơ bộ về những khoảnh khắc tiềm năng trong khoảng 26-27 giờ.

Sử dụng một LocalDateTimetrong hai khi không xác định vùng / bù (không phải là tình huống tốt) hoặc khi bù vùng không xác định. Ví dụ, Giáng sinh bắt đầu vào thời điểm đầu tiên của ngày 25 tháng 12 năm 2018, sẽ được biểu diễn dưới dạng a LocalDateTime.

Sử dụng a ZonedDateTimeđể thể hiện một khoảnh khắc trong một múi giờ cụ thể. Ví dụ: Giáng sinh bắt đầu ở bất kỳ khu vực cụ thể nào như Pacific/Aucklandhoặc America/Montrealsẽ được đại diện với một ZonedDateTimeđối tượng.

Trong một khoảnh khắc luôn luôn trong UTC, sử dụng Instant.

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

Áp dụng một múi giờ. Cùng một thời điểm, cùng một điểm trên dòng thời gian, nhưng được xem với thời gian đồng hồ treo tường khác nhau.

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

Vì vậy, nếu tôi chỉ có thể chuyển đổi giữa LocalDate và LocalDateTime,

Không, sai chiến lược. Nếu bạn có giá trị chỉ theo ngày và bạn muốn giá trị theo ngày, bạn phải chỉ định thời gian trong ngày. Thời gian đó có thể không hợp lệ vào ngày đó đối với một khu vực cụ thể - trong trường hợp đó, ZonedDateTimelớp sẽ tự động điều chỉnh thời gian trong ngày khi cần thiết.

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

Nếu bạn muốn khoảnh khắc đầu tiên trong ngày là thời gian trong ngày của mình, hãy để java.time xác định thời điểm đó. Đừng cho rằng ngày bắt đầu lúc 00:00:00. Sự bất thường như Giờ tiết kiệm ánh sáng ban ngày (DST) có nghĩa là ngày có thể bắt đầu vào một thời điểm khác, chẳng hạn như 01:00:00.

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp là lớp sai

Đây java.sql.Timestamplà một phần của các lớp thời gian cũ rắc rối hiện đang là di sản, được thay thế hoàn toàn bởi các lớp java.time . Lớp đó được sử dụng để thể hiện một khoảnh khắc trong UTC với độ phân giải nano giây . Mục đích đó bây giờ được phục vụ với java.time.Instant.

JDBC 4.2 với getObject/setObject

Kể từ JDBC 4.2 trở lên, trình điều khiển JDBC của bạn có thể trao đổi trực tiếp các đối tượng java.time với cơ sở dữ liệu bằng cách gọi:

Ví dụ:

myPreparedStatement.setObject(  , instant ) ;

Giáo dục và Giáo dục

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

Chuyển đổi di sản ⬌ hiện đại

Nếu bạn phải giao diện với mã cũ chưa được cập nhật lên java.time , hãy chuyển đổi qua lại bằng các phương thức mới được thêm vào các lớp cũ.

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

Giáo dục và Giáo dục

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

Giới thiệu về java.time

Các java.time khung được xây dựng vào Java 8 và sau đó. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Để tìm hiểu thêm, xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của bạn. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần chuỗi, không cần java.sql.*lớp.

Nơi để có được các lớp java.time?

  • Java SE 8 , Java SE 9 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với việc triển khai đi kèm.
    • Java 9 thêm một số tính năng nhỏ và sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng java.time được chuyển ngược lại sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản sau của triển khai gói Android của các lớp java.time.
    • Đối với Android trước đó (<26), các ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP .

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho các bổ sung có thể trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval, YearWeek, YearQuarter, và nhiều hơn nữa .


5

Tùy thuộc vào múi giờ của bạn, bạn có thể mất vài phút (1650-01-01 00:00:00 trở thành 1649-12-31 23:52:58)

Sử dụng mã sau đây để tránh điều đó

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

3

Vì Joda đang bị mờ dần, ai đó có thể muốn chuyển đổi LocaltDatesang LocalDateTimeJava 8. Trong Java 8, LocalDateTimenó sẽ đưa ra một cách để tạo một LocalDateTimecá thể bằng cách sử dụng a LocalDateLocalTime. Kiểm tra tại đây.

công khai LocalDateTime của (ngày LocalDate, thời gian LocalTime)

Mẫu sẽ là,

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

Chỉ để tham khảo, để có được các giây kỷ nguyên dưới đây có thể được sử dụng,

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

    // If you only care about UTC
    long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);

Không cần phải sử dụng LocalDateTimeở đây. Lớp đó cố tình thiếu bất kỳ khái niệm nào về múi giờ hoặc bù từ UTC. Vì vậy, nó không phục vụ mục đích hữu ích ở đây. Thay vào đó: LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond()Đừng cho rằng ngày bắt đầu lúc 00:00, không phải lúc nào cũng như vậy.
Basil Bourque

Whay làm bạn có ý nghĩa bởi không mang bắt đầu ngày tại 00.00
Thủ

1
Sự bất thường như Giờ tiết kiệm ánh sáng ban ngày (DST) có nghĩa là vào một số ngày ở một số nơi, ngày có thể bắt đầu vào một thời điểm khác, chẳng hạn như 01:00:00. Vì vậy, thay vì giả định, hãy để java.time xác định khoảnh khắc đầu tiên bằng cách gọi java.time.LocalDate.atStartOfDayđể có được a ZonedDateTime. Xem ví dụ trong câu trả lời của tôi . Như tôi đã nhận xét, LocalDateTimelớp học là vô dụng và phản tác dụng trong tất cả điều này.
Basil Bourque

Vậy với LocalDateTimeta phải dùng a ZoneId?
nguyên tố

Tôi nghĩ rằng bạn đã bỏ lỡ tất cả các điểm của tôi. Đọc lại câu trả lời của tôi trên trang này. Tìm kiếm Stack Overflow để tìm hiểu thêm từ nhiều ví dụ và thảo luận. Nhưng tôi sẽ nói lần cuối cùng ở đây: LocalDateTimekhông thích hợp cho vấn đề trong tầm tay ở đây. Một LocalDateTimekhông không đại diện cho một thời điểm. Một LocalDateTime để làm với bất kỳ địa phương đặc biệt là khu vực hoặc thời gian mặc dù tên có thể hàm ý khác ở cái nhìn đầu tiên - tìm hiểu thêm về mục đích và các chi tiết của lớp này. Các LocalDateTimelớp không phục vụ một mục đích, nhưng không phải là mục đích nhìn thấy trong Câu hỏi này.
Basil Bourque

2

gọi hàm asStartOfDay()trên java.time.LocalDateđối tượng trả về một java.time.LocalDateTimeđối tượng


0

Java8 +

import java.time.Instant;
Instant.now().getEpochSecond(); //timestamp in seconds format (int)
Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)

Hữu ích, nhưng dường như không thực sự trả lời câu hỏi.
Ole VV

Cảm ơn mã, nhưng nó không liên quan gì đến câu hỏi.
refaelio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.