Chuyển đổi từ lâu thành ngày tháng trong Java trả về năm 1970


118

Tôi có danh sách với các giá trị dài (ví dụ: 1220227200, 1220832000, 1221436800 ...) mà tôi đã tải xuống từ dịch vụ web. Tôi phải chuyển đổi nó thành Ngày. Thật không may theo cách này, ví dụ:

Date d = new Date(1220227200);

trả về ngày 1 tháng 1 năm 1970. Có ai biết cách khác để chuyển đổi nó một cách chính xác không?


Bạn có thể cho biết những giá trị mà bạn mong đợi? Câu hỏi về giây / mili giây có thể là một câu hỏi hợp lệ, nhưng 1220227200 không phải là 1/1/1970. Có vẻ như bạn đang chuyển 0 cho hàm tạo. Một số mã khác có thể hữu ích.
SJuan76

1
@mmmiki - bạn nên chấp nhận câu trả lời
Stewart

nó trả về ngày 15 tháng 1 năm 1970, ở đây, không phải ngày 1 tháng 1.
njzk2

FYI, khủng khiếp sai lầm lớp ngày thời gian như java.util.Date, java.util.Calendarjava.text.SimpleDateFormatbây giờ là di sản , thay thế bởi sự java.time class built vào Java 8 và sau đó.
Basil Bourque

Câu trả lời:


161

Hàm Datetạo (nhấp vào liên kết!) Chấp nhận thời gian tính longbằng mili giây , không phải giây. Bạn cần nhân nó với 1000 và đảm bảo rằng bạn cung cấp nó là long.

Date d = new Date(1220227200L * 1000);

Điều này hiển thị ở đây

Chủ nhật ngày 31 tháng 8 20:00:00 GMT-04: 00 2008


22
Hoặc cách khác, sử dụng dung Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L));dịch sạch hơn và ít ma thuật hơn .
Priidu Neemre

56

tl; dr

java.time.Instant                    // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L )     // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.

Biết dữ liệu của bạn

Mọi người sử dụng các giới hạn khác nhau để theo dõi thời gian như một con số kể từ một kỷ nguyên . Vì vậy, khi bạn có được một số số được hiểu là số đếm kể từ một kỷ nguyên, bạn phải xác định:

  • Kỷ nguyên nào?
    Nhiều kỷ nguyên ngày đã được sử dụng trong các hệ thống khác nhau. Thường được sử dụng là thời gian POSIX / Unix , trong đó kỷ nguyên là thời điểm đầu tiên của năm 1970 theo giờ UTC. Nhưng bạn không nên cho rằng kỷ nguyên này.
  • Độ chính xác nào?
    Chúng ta đang nói chuyện giây, mili giây , micro giây hay nano giây kể từ kỷ nguyên?
  • Múi giờ nào?
    Thông thường, một số đếm vì kỷ nguyên nằm trong múi giờ UTC / GMT, tức là không có độ lệch múi giờ nào cả. Nhưng đôi khi, khi liên quan đến các lập trình viên thiếu kinh nghiệm hoặc thiếu hiểu biết về ngày giờ, có thể có một múi giờ ngụ ý.

Trong trường hợp của bạn, như những người khác đã lưu ý, bạn dường như đã có vài giây kể từ kỷ nguyên Unix. Nhưng bạn đang chuyển những giây đó cho một phương thức khởi tạo dự kiến ​​là mili giây. Vì vậy, giải pháp là nhân với 1.000.

Bài học kinh nghiệm:

  • Xác định, không giả định, ý nghĩa của dữ liệu nhận được.
  • Đọc tài liệu .

Biểu đồ hiển thị các độ phân giải chi tiết khác nhau trong hệ thống ngày-giờ bao gồm cả giây, mili giây, micro giây và nano giây.

Dữ liệu của bạn

Dữ liệu của bạn dường như chỉ trong vài giây. Nếu chúng ta giả sử một kỷ nguyên là đầu năm 1970 và nếu chúng ta giả định múi giờ UTC, thì đó 1,220,227,200là thời điểm đầu tiên của ngày đầu tiên của tháng 9 năm 2008.

Joda-Time

Các lớp java.util.Date và .Calendar đi kèm với Java nổi tiếng là rắc rối. Tránh chúng. Thay vào đó, hãy sử dụng thư viện Joda-Time hoặc gói java.time mới được đóng gói trong Java 8 (và lấy cảm hứng từ Joda-Time).

Lưu ý rằng không giống như juDate, DateTimetrong Joda-Time thực sự biết múi giờ được chỉ định của chính nó . Vì vậy, trong ví dụ về mã Joda-Time 2.4 bên dưới, hãy lưu ý rằng trước tiên chúng tôi phân tích cú pháp mili giây bằng cách sử dụng giả định mặc định là UTC. Sau đó, thứ hai, chúng tôi chỉ định múi giờ của Paris để điều chỉnh. Cùng một thời điểm trong dòng thời gian của Vũ trụ, nhưng thời gian trên đồng hồ treo tường khác nhau . Để trình diễn, chúng tôi điều chỉnh lại thành UTC. Hầu như luôn luôn tốt hơn để chỉ định rõ ràng múi giờ mong muốn / dự kiến ​​của bạn hơn là dựa vào một mặc định ngầm (thường là nguyên nhân gây ra rắc rối trong công việc hẹn giờ).

Chúng ta cần mili giây để tạo DateTime. Vì vậy, hãy lấy số giây đầu vào của bạn và nhân với một nghìn. Lưu ý rằng kết quả phải là 64-bit longvì chúng ta sẽ làm tràn 32-bit int.

long input = 1_220_227_200L;  // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".

Cung cấp số mili giây đó cho hàm tạo. Phương thức khởi tạo cụ thể đó giả định số đếm là từ kỷ nguyên Unix năm 1970. Vì vậy, hãy điều chỉnh múi giờ như mong muốn, sau khi xây dựng.

Sử dụng tên múi giờ thích hợp , kết hợp giữa lục địa và thành phố / khu vực. Không bao giờ sử dụng mã 3 hoặc 4 chữ cái ESTvì chúng không được tiêu chuẩn hóa và không phải là duy nhất.

DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );

Để trình diễn, hãy điều chỉnh lại múi giờ.

DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );

Đổ vào bảng điều khiển. Lưu ý rằng ngày khác ở Montréal như thế nào, vì ngày mới đã bắt đầu ở châu Âu nhưng chưa ở Mỹ.

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );

Khi chạy.

dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00

java.time

Các nhà sản xuất của Joda-Time đã yêu cầu chúng tôi chuyển sang phần mềm thay thế của nó, khuôn khổ java.time ngay khi thuận tiện. Trong khi Joda-Time tiếp tục được hỗ trợ tích cực, tất cả sự phát triển trong tương lai sẽ được thực hiện trên các lớp java.time và các phần mở rộng của chúng trong dự án ThreeTen-Extra.

Khung thời gian java được định nghĩa bởi JSR 310 và được tích hợp vào Java 8 trở lên. Các lớp java.time đã được chuyển ngược sang Java 6 & 7 trong dự án ThreeTen-Backport và cho Android trong dự án ThreeTenABP .

An Instantlà một thời điểm trên dòng thời gian tính theo giờ UTC với độ phân giải là nano giây. Kỷ nguyên của nó là thời điểm đầu tiên của năm 1970 theo giờ UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Áp dụng giá trị chênh lệch từ UTC ZoneOffset để nhận được OffsetDateTime.

Tốt hơn, nếu biết, hãy áp dụng múi giờ ZoneIdđể lấy a ZonedDateTime.

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

Bảng tất cả các loại ngày-giờ trong Java, cả hiện đại và kế thừa


1
Cổ vũ bạn thân. Lời giải thích tuyệt vời. Tôi đã nhận được DateTime mới (<số dài>) từ năm 1970 khi tôi nhận ra rằng tôi đã cho nó trong vài giây và yêu cầu trong mili giây
Suyash Dixit

40

Có vẻ như thời gian dài của bạn là giây chứ không phải mili giây. Hàm tạo ngày có thời gian là mili, vì vậy

Date d = new Date(timeInSeconds * 1000);

4
@ f1sh: Tôi không phản đối, nhưng câu trả lời ban đầu thì khác. Anh ấy đã chỉnh sửa nó trong thời gian gia hạn 5 phút.
BalusC

Cảm ơn bạn đã làm rõ. Đó là nhược điểm ownly SO có ...: - /
f1sh

11

Chỉ đặt thời gian theo đơn vị trên đối tượng Lịch

Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());

9

Đó có thể là các dấu thời gian tính bằng giây chứ không phải mili giây được yêu cầu đối với hàm tạo Date (long) của java new. Chỉ cần nhân chúng với 1000 và bạn sẽ ổn.


23
đúng hơn là quá chậm 30000 mili giây
SJuan76

5

Các giá trị dài, rất có thể, tương ứng với dấu thời gian của Epoch và các giá trị là:

1220227200 = Thứ Hai, ngày 1 tháng 9 năm 2008 00:00:00 GMT

1220832000 = Thứ Hai, ngày 8 tháng 9 năm 2008 00:00:00 GMT

1221436800 = Thứ Hai, ngày 15 tháng 9 năm 2008 00:00:00 GMT

Người ta có thể chuyển đổi các giá trị dài này thành java.util.Date , có tính đến thực tế java.util.Date sử dụng mili giây - như đã gợi ý trước đây, nhưng có một số lỗ hổng - như thế này:

// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L); 

Bây giờ, để hiển thị ngày một cách chính xác, người ta có thể sử dụng java.text.DateFormat như được minh họa sau đây:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));

Dưới đây là kết quả hiển thị giá trị dài đã chuyển đổi thành java.util.Date mà không sử dụng DateFormat:

Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC

4

Thử cái này:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());

2

1220227200 tương ứng với ngày 15 tháng 1 năm 1980 (và thực sự là Ngày mới (1220227200) .toString () trả về "Thứ ba ngày 15 tháng 1 03:57:07 CET 1970"). Nếu bạn chuyển một giá trị dài cho một ngày, tức là trước ngày 01/01/1970 thì trên thực tế, nó sẽ trả về ngày 01/01/1970. Đảm bảo rằng các giá trị của bạn không ở trong trường hợp này (thấp hơn 82800000).


2

Hãy thử điều này với việc điều chỉnh định dạng ngày.

long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);

Lưu ý: Kiểm tra chu kỳ 24 giờ hoặc 12 giờ.


0

Ngày mới (số) trả về một ngày number mili giây sau ngày 1 tháng 1 năm 1970. Tỷ lệ cược là định dạng ngày của bạn không hiển thị giờ, phút và giây để bạn thấy rằng nó chỉ sau ngày 1 tháng 1 năm 1970 một chút.

Bạn cần phân tích cú pháp ngày theo định tuyến phân tích cú pháp chính xác. Tôi không biết 1220227200 là gì, nhưng nếu nó là giây sau ngày 1 tháng 1 năm 1970, thì hãy nhân nó lên để thu được mili giây. Nếu không, hãy chuyển đổi nó theo một cách nào đó thành mili giây sau năm 1970 (nếu bạn muốn tiếp tục sử dụng java.util.Date).


0

Làm việc cho tôi. Bạn có thể muốn đa vạch nó với 1000, vì những gì bạn nhận được là giây từ năm 1970 và bạn phải vượt qua mili giây từ tháng 1 năm 1970

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.