Làm cách nào để trích xuất epoch từ LocalDate và LocalDateTime?


102

Làm cách nào để trích xuất giá trị kỷ nguyên Longtừ các trường hợp của LocalDateTimehoặc LocalDate? Tôi đã thử những cách sau, nhưng nó cho tôi kết quả khác:

LocalDateTime time = LocalDateTime.parse("04.02.2014  19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy  HH:mm:ss"));
System.out.println(time.getLong(ChronoField.SECOND_OF_DAY)); // gives 71461
System.out.println(time.getLong(ChronoField.EPOCH_DAY)); // gives 16105

Những gì tôi muốn chỉ đơn giản là giá trị 1391539861cho ngày giờ địa phương "04.02.2014 19:51:01". Múi giờ của tôi là Europe/OsloUTC + 1 với thời gian tiết kiệm ánh sáng ban ngày.


Vui lòng giải thích số dự kiến ​​của bạn 1396468261. Tôi nhận được mà không cần chỉnh sửa múi giờ: 1391543461 (xem chỉnh sửa trong câu trả lời của tôi). 57 ngày chênh lệch!
Meno Hochschild

@MenoHochschild Tôi đã cập nhật câu hỏi của mình với thông tin múi giờ và sửa giá trị thực từ GTM thành localtime. Có cách nào dễ dàng hơn để có được kỷ nguyên của một số LocalDateTimekhác ngoài việc tính toán nó theo cách thủ công không?

Trở lại sau thời gian tạm dừng của tôi, hãy xem cập nhật của tôi.
Meno Hochschild

Câu trả lời:


147

Các lớp LocalDateLocalDateTimekhông chứa thông tin về múi giờ hoặc chênh lệch thời gian và giây kể từ kỷ nguyên sẽ rất lớn nếu không có thông tin này. Tuy nhiên, các đối tượng có một số phương pháp để chuyển đổi chúng thành các đối tượng ngày / giờ với múi giờ bằng cách chuyển một ZoneIdthể hiện.

LocalDate

LocalDate date = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = date.atStartOfDay(zoneId).toEpochSecond();

LocalDateTime

LocalDateTime time = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = time.atZone(zoneId).toEpochSecond();

2
Có thể tránh sử dụng ZoneId hoặc sử dụng với phiên bản ZoneId không đổi, tùy chỉnh (của +0, nghĩa là GMT) không? Tôi hỏi điều này vì tôi muốn tất cả các tính toán được chuẩn hóa cho nó. Ngoài ra, làm cách nào để làm ngược lại: chuyển đổi từ epoch time sang LocalDate / LocalDateTime (cũng không có ZoneId hoặc với GMT)?
nhà phát triển android

2
Đừng bận tâm. Tìm thấy nó:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
nhà phát triển android

7
Một cách tiếp cận đơn giản hơn chỉ long epoch = time.toEpochSecond(ZoneOffset.UTC)dành cho các trường hợp UTC hoặc nơi bạn đã biết múi giờ hoặc long epoch = time.toEpochSecond(ZoneId.systemDefault());nếu bạn muốn đi theo tuyến đường đó.
Marcus

Điều này nghe có vẻ vô lý nhưng làm thế nào về việc chuyển đổi trở lại từ epoch thành LocalDate, LocalTime & LocalDateTime
samuel owino

Đừng bận tâm, tôi nghĩ rằng tôi đã tìm thấy nó; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino

27

'Millis kể từ kỷ nguyên unix' đại diện cho tức thì, vì vậy bạn nên sử dụng lớp Instant:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}

nó không chính xác để sử dụng ZoneId.systemDefault()vì kỷ nguyên unix đề cập đến UTC
ACV

10

Chuyển đổi bạn cần yêu cầu chênh lệch từ UTC / Greewich hoặc múi giờ.

Nếu bạn có một bù đắp, có một phương pháp chuyên dụng trên LocalDateTimecho công việc này:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Nếu bạn chỉ có một ZoneIdthì bạn có thể lấy ZoneOffsettừ ZoneId:

ZoneOffset zoneOffset = ZoneId.of("Europe/Oslo").getRules().getOffset(ldt);

Nhưng bạn có thể thấy chuyển đổi ZonedDateTimeđơn giản hơn:

long epochSec = ldt.atZone(zoneId).toEpochSecond();

4
Nếu bạn chỉ quan tâm đến UTC, thì cólong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong

2

Nhìn vào phương pháp này để xem trường nào được hỗ trợ. Bạn sẽ tìm thấy LocalDateTime:

NANO_OF_SECOND 
NANO_OF_DAY 
MICRO_OF_SECOND 
MICRO_OF_DAY 
MILLI_OF_SECOND 
MILLI_OF_DAY 
SECOND_OF_MINUTE 
SECOND_OF_DAY 
MINUTE_OF_HOUR 
MINUTE_OF_DAY 
HOUR_OF_AMPM 
CLOCK_HOUR_OF_AMPM 
HOUR_OF_DAY 
CLOCK_HOUR_OF_DAY 
AMPM_OF_DAY 
DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Trường INSTANT_SECONDS - tất nhiên - không được hỗ trợ vì a LocalDateTimekhông thể tham chiếu đến bất kỳ dấu thời gian tuyệt đối (toàn cầu) nào. Nhưng điều hữu ích là trường EPOCH_DAY tính số ngày đã trôi qua kể từ 1970-01-01. Các suy nghĩ tương tự có giá trị đối với loại LocalDate(với các trường được hỗ trợ thậm chí ít hơn).

Nếu bạn định lấy trường mili-do-unix-epoch không tồn tại, bạn cũng cần múi giờ để chuyển đổi từ kiểu cục bộ sang kiểu chung. Việc chuyển đổi này có thể được thực hiện đơn giản hơn nhiều, hãy xem các bài đăng SO khác .

Quay lại câu hỏi của bạn và các số trong mã của bạn:

The result 1605 is correct
  => (2014 - 1970) * 365 + 11 (leap days) + 31 (in january 2014) + 3 (in february 2014)
The result 71461 is also correct => 19 * 3600 + 51 * 60 + 1

16105L * 86400 + 71461 = 1391543461 giây kể từ 1970-01-01T00: 00: 00 (chú ý, không có múi giờ) Sau đó, bạn có thể trừ chênh lệch múi giờ (coi chừng có thể nhân với 1000 nếu tính bằng mili giây).

CẬP NHẬT sau thông tin múi giờ nhất định:

local time = 1391543461 secs
offset = 3600 secs (Europe/Oslo, winter time in february)
utc = 1391543461 - 3600 = 1391539861

Là mã JSR-310 với hai cách tiếp cận tương đương:

long secondsSinceUnixEpoch1 =
  LocalDateTime.of(2014, 2, 4, 19, 51, 1).atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

long secondsSinceUnixEpoch2 =
  LocalDate
    .of(2014, 2, 4)
    .atTime(19, 51, 1)
    .atZone(ZoneId.of("Europe/Oslo"))
    .toEpochSecond();

1
Cảm ơn vì lời giải thích. Có kết quả phù hợp bằng cách sử dụng LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));và sau đó Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.

1

Chuyển đổi từ ngày có thể đọc của con người thành kỷ nguyên :

long epoch = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").parse("01/01/1970 01:00:00").getTime() / 1000;

Chuyển đổi từ kỷ nguyên sang ngày có thể đọc được của con người :

String date = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").format(new java.util.Date (epoch*1000));

Đối với công cụ chuyển đổi ngôn ngữ khác: https://www.epochconverter.com


0

Đây là một cách mà không cần sử dụng múi giờ:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
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.