จะแยก epoch จาก LocalDate และ LocalDateTime ได้อย่างไร


103

ฉันจะแยกค่า epoch Longจากอินสแตนซ์ของLocalDateTimeหรือได้LocalDateอย่างไร ฉันได้ลองทำสิ่งต่อไปนี้แล้ว แต่ให้ผลลัพธ์อื่น ๆ :

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

สิ่งที่ฉันต้องการมีเพียงค่า1391539861สำหรับวันที่และเวลาใน"04.02.2014 19:51:01"เครื่อง เขตเวลาของฉันคือEurope/OsloUTC + 1 พร้อมเวลาออมแสง


โปรดอธิบายหมายเลขที่คุณคาดไว้ 1396468261 ฉันได้รับโดยไม่มีการแก้ไขเขตเวลา: 1391543461 (ดูแก้ไขในคำตอบของฉัน) ความแตกต่าง 57 วัน!
Meno Hochschild

@MenoHochschild ฉันได้อัปเดตคำถามของฉันด้วยข้อมูลเขตเวลาและแก้ไขค่าจริงจาก GTM เป็นเวลาท้องถิ่น มีวิธีที่ง่ายกว่าในการรับยุคของบางอย่างLocalDateTimeนอกเหนือจากการคำนวณด้วยตนเองหรือไม่?

กลับมาจากการหยุดชั่วคราวดูการอัปเดตของฉัน
Meno Hochschild

คำตอบ:


149

ชั้นเรียนLocalDateและLocalDateTimeไม่มีข้อมูลเกี่ยวกับเขตเวลาหรือการชดเชยเวลาและวินาทีเนื่องจากยุคจะมีความสำคัญหากไม่มีข้อมูลนี้ อย่างไรก็ตามวัตถุมีหลายวิธีในการแปลงเป็นวัตถุวันที่ / เวลาด้วยเขตเวลาโดยส่งผ่านZoneIdอินสแตนซ์

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
เป็นไปได้หรือไม่ที่จะหลีกเลี่ยงการใช้ ZoneId หรือใช้กับอินสแตนซ์ ZoneId ที่กำหนดเองและคงที่ (จาก +0 หมายถึง GMT) ฉันถามสิ่งนี้เพราะฉันต้องการให้การคำนวณทั้งหมดเป็นมาตรฐาน นอกจากนี้ฉันจะทำสิ่งที่ตรงกันข้ามได้อย่างไร: แปลงจากเวลาเป็น LocalDate / LocalDateTime (โดยไม่มี ZoneId หรือด้วย GMT one)
นักพัฒนา android

2
ไม่เป็นไร. พบแล้ว:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
นักพัฒนา android

7
แนวทางที่ง่ายกว่านั้นมีlong epoch = time.toEpochSecond(ZoneOffset.UTC)ไว้สำหรับกรณี UTC หรือในกรณีที่คุณรู้จักเขตเวลาอยู่แล้วหรือlong epoch = time.toEpochSecond(ZoneId.systemDefault());หากคุณต้องการไปตามเส้นทางนั้น
Marcus

สิ่งนี้อาจฟังดูไร้สาระ แต่จะแปลงกลับจากยุคเป็น LocalDate, LocalTime และ LocalDateTime ได้อย่างไร
samuel owino

ไม่เป็นไรฉันคิดว่าฉันเจอแล้ว Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino

27

'มิลลิวินาทีตั้งแต่ unix epoch' แทนค่าทันทีดังนั้นคุณควรใช้คลาส Instant:

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

ใช้ไม่ถูกต้องZoneId.systemDefault()เนื่องจาก unix epoch อ้างถึง UTC
ACV

10

การแปลงที่คุณต้องการต้องใช้การชดเชยจาก UTC / Greewich หรือเขตเวลา

หากคุณมีการชดเชยมีวิธีการเฉพาะในLocalDateTimeสำหรับงานนี้:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

หากคุณมีเพียงZoneIdคุณสามารถรับได้ZoneOffsetจากZoneId:

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

แต่คุณอาจพบการแปลงด้วยวิธีที่ZonedDateTimeง่ายกว่า:

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

4
หากคุณสนใจเฉพาะ UTC มีlong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong

2

ดูวิธีนี้เพื่อดูว่าช่องใดได้รับการสนับสนุน คุณจะพบกับ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 

แน่นอนว่าช่อง INSTANT_SECONDS ไม่ได้รับการสนับสนุนเนื่องจากLocalDateTimeไม่สามารถอ้างถึงการประทับเวลาแบบสัมบูรณ์ (ส่วนกลาง) ใด ๆ แต่สิ่งที่มีประโยชน์คือฟิลด์EPOCH_DAYซึ่งนับวันที่ผ่านไปตั้งแต่ 1970-01-01 ความคิดที่คล้ายกันใช้ได้กับประเภทLocalDate(แม้จะมีช่องที่รองรับน้อยกว่าก็ตาม)

หากคุณต้องการรับฟิลด์ millis-since-unix-epoch ที่ไม่มีอยู่คุณต้องมีเขตเวลาสำหรับการแปลงจาก local เป็น global type ด้วย แปลงนี้สามารถทำได้ง่ายมากดูที่อื่น ๆSO-โพสต์

กลับมาที่คำถามของคุณและตัวเลขในรหัสของคุณ:

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 วินาทีตั้งแต่ 1970-01-01T00: 00: 00 (สนใจไม่มีเขตเวลา) จากนั้นคุณสามารถลบออฟเซ็ตเขตเวลา (ระวังการคูณที่เป็นไปได้ด้วย 1,000 หากเป็นมิลลิวินาที)

อัปเดตหลังจากข้อมูลเขตเวลาที่กำหนด:

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

เป็นรหัส JSR-310 ที่มีสองวิธีที่เทียบเท่ากัน:

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
ขอบคุณสำหรับคำอธิบาย มีผลที่เหมาะสมโดยใช้แล้วLocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")); Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

1

แปลงวันที่ที่มนุษย์อ่านได้เป็นยุค :

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

แปลงจากยุคเป็นวันที่มนุษย์อ่านได้ :

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

สำหรับตัวแปลงภาษาอื่น ๆ : https://www.epochconverter.com


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.