วิธีรับ UTC + 0 date ใน Java 8


108

ฉันมีปัญหากับคลาส Date ใน Java คลาสวันที่ส่งคืนวันที่เครื่องในเครื่อง แต่ฉันต้องการ UTC-0

ฉัน googled และพบวิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับ JavaScript แต่สำหรับ Java ไม่มีประโยชน์อะไร

วิธีรับ UTC + 0 date ใน Java 8


12
java.util.Dateไม่เคยเป็นวันที่เครื่องท้องถิ่น จะกำหนดเป็นมิลลิวินาทีที่ผ่านไปเสมอตั้งแต่ 1970-01-01 เทียบกับ UTC + 00: 00 บางทีพฤติกรรมของวิธีการนี้อาจtoString()ทำให้คุณสับสนซึ่งใช้การเป็นตัวแทนในเขตเวลาท้องถิ่น
Meno Hochschild

สามารถพบคำตอบที่น่าจะเป็นไปได้ในคำถาม: stackoverflow.com/questions/45350095/…
Priya Jain

คำตอบ:


146

ด้วย Java 8 คุณสามารถเขียน:

OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

ในการตอบความคิดเห็นของคุณคุณสามารถแปลงเป็นวันที่ (เว้นแต่คุณจะขึ้นอยู่กับรหัสเดิมฉันไม่เห็นเหตุผลใด ๆ ) หรือเป็นมิลลิวินาทีตั้งแต่ยุค:

Date date = Date.from(utc.toInstant());
long epochMillis = utc.toInstant().toEpochMilli();

1
ขอบคุณ. เป็นไปได้ที่จะแปลง ZonedDateTime เป็น Date หรือ long (ms)?
ทำเครื่องหมาย

7
แม้ว่าโค้ดของคำตอบนี้จะใช้งานได้ในทางเทคนิค แต่มันจะไม่เหมาะสมที่จะใช้OffsetDateTimeมากกว่าที่จะZonedDateTimeระบุว่าเรากำลังทำงานกับเพียงออฟเซ็ตจาก UTC แทนที่จะเป็นเขตเวลาเต็ม
Basil Bourque

1
จะไม่utc.toInstant().toEpochMilli()เป็นการแปลงเป็นมิลลิวินาทีที่แม่นยำกว่านี้หรือ?
iwat0qs

181

tl; dr

Instant.now()

java.time

คลาสวันเวลาเก่าที่มีปัญหาซึ่งมาพร้อมกับ Java เวอร์ชันแรกสุดถูกแทนที่ด้วยคลาสjava.time ที่สร้างไว้ใน Java 8 และใหม่กว่า ดูออราเคิลกวดวิชา มากของการทำงานที่ได้รับกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับไปและต่อไปปรับใช้กับ Android ในThreeTenABP

Instant

Instantหมายถึงช่วงเวลาบนไทม์ไลน์ในส่วนUTCที่มีความละเอียดถึงนาโนวินาที

Instant instant = Instant.now();

toStringวิธีการสร้างวัตถุสตริงที่มีข้อความที่เป็นตัวแทนของค่าวันเวลาโดยใช้หนึ่งในมาตรฐานISO 8601รูปแบบ

String output = instant.toString();  

2016-06-27T19: 15: 25.864Z

Instantชั้นเป็นชั้นอาคารบล็อกพื้นฐานใน java.time นี่ควรเป็นชั้นเรียนของคุณเมื่อจัดการกับวันที่ - เวลาโดยทั่วไปแนวทางปฏิบัติที่ดีที่สุดคือการติดตามจัดเก็บและแลกเปลี่ยนค่าวันที่ - เวลาใน UTC

OffsetDateTime

แต่Instantมีข้อ จำกัด เช่นไม่มีตัวเลือกการจัดรูปแบบสำหรับการสร้างสตริงในรูปแบบอื่น สำหรับความยืดหยุ่นมากขึ้นแปลงจากไปInstant OffsetDateTimeระบุชดเชยจาก UTC ใน java.time นั่นหมายถึงZoneOffsetวัตถุ ที่นี่เราต้องการติดกับ UTC (00) ZoneOffset.UTCเพื่อให้เราสามารถใช้อย่างต่อเนื่องสะดวก

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );

2016-06-27T19: 15: 25.864Z

หรือข้ามInstantชั้นเรียน.

OffsetDateTime.now( ZoneOffset.UTC )

ขณะนี้มีOffsetDateTimeวัตถุอยู่ในมือคุณสามารถใช้DateTimeFormatterสร้างวัตถุ String พร้อมข้อความในรูปแบบอื่นได้ ค้นหา Stack DateTimeFormatterมากเกินหลายตัวอย่างของการใช้

ZonedDateTime

เมื่อคุณต้องการที่จะแสดงเวลาผนังนาฬิกาสำหรับโซนเวลาบางอย่างโดยเฉพาะอย่างยิ่งใช้จะได้รับZoneIdZonedDateTime

ในตัวอย่างนี้เราใช้เขตเวลามอนทรีออล ในช่วงฤดูร้อนภายใต้การปรับเวลาตามฤดูกาล (DST)-04:00เรื่องไร้สาระโซนได้ชดเชย ดังนั้นสังเกตว่าเวลาของวันเร็วกว่าสี่ชั่วโมงในผลลัพธ์อย่างไร15แทนที่จะเป็น19ชั่วโมง InstantและZonedDateTimeทั้งสองแสดงถึงช่วงเวลาที่เกิดขึ้นพร้อมกันเพียงแค่มองผ่านเลนส์สองตัวที่แตกต่างกัน

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

2016-06-27T15: 15: 25.864-04: 00 [อเมริกา / มอนทรีออล]

กำลังแปลง

แม้ว่าคุณควรหลีกเลี่ยงคลาสวันเวลาแบบเก่า แต่คุณต้องสามารถแปลงโดยใช้วิธีการใหม่ที่เพิ่มเข้ามาในคลาสเก่าได้ ที่นี่เราใช้java.util.Date.from( Instant )และjava.util.Date::toInstant.

java.util.Date utilDate = java.util.Date.from( instant );

และไปทางอื่น

Instant instant= utilDate.toInstant();

ในทำนองเดียวกันการมองหาวิธีการใหม่ที่เพิ่มGregorianCalendar(subclass ของCalendar) java.time.ZonedDateTimeเพื่อแปลงไปและกลับจาก

ตารางประเภทของคลาสวันเวลาใน java.time สมัยใหม่เทียบกับระบบเดิม

เกี่ยวกับjava.time

java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date, และCalendarSimpleDateFormat

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310

โครงการJoda-Timeขณะนี้อยู่ในโหมดการบำรุงรักษาแนะนำการโยกย้ายไปยังคลาสjava.time

คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องมีสตริงไม่จำเป็นต้องมีjava.sql.*คลาส Hibernate 5 & JPA 2.2 สนับสนุนjava.time

จะหาคลาส java.time ได้ที่ไหน?

  • Java SE 8 , Java SE 9 , Java SE 10 , Java SE 11และใหม่กว่า - เป็นส่วนหนึ่งของ Java API มาตรฐานพร้อมการใช้งานแบบรวม
    • Java 9นำเสนอคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ Java SE 7
    • ส่วนใหญ่ของjava.timeการทำงานจะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android

3
ขอบคุณที่บอกว่า DST เป็นสิ่งที่ไม่สมเหตุสมผล :-)
prash

ดังนั้นถ้าไม่มี DST ก็ไม่ZonedDateTimeจำเป็นเพราะทั้งหมดZoneIdจะจับคู่กับสิ่งที่ZoneOffsetเราสามารถใช้ได้OffsetDateTime?
wilmol

1
@wilmol ไม่เวลาออมแสง (DST) เป็นเพียงหนึ่งในหลาย ๆ เหตุผลที่นักการเมืองเลือกที่จะกำหนดขอบเขตเขตเวลาใหม่และการชดเชยภายในโซนเหล่านั้น เมื่อเร็ว ๆ นี้เกาหลีเหนือเปลี่ยนนาฬิกาครึ่งชั่วโมงเพื่อซิงค์กับเกาหลีใต้ด้วยเหตุผลทางการทูต ในสงครามผู้รุกราน / ผู้ครอบครองอาจเปลี่ยนค่าชดเชยให้ตรงกับของประเทศบ้านเกิด ปัจจุบันมีแฟชั่นใหม่ที่รัฐบาลกำลังเลือกที่จะหยุดการเปลี่ยนแปลง DST แต่จะคงอยู่บน DST อย่างถาวรแทนที่จะย้อนกลับไปใช้เวลามาตรฐานเดิม วางแผนชดเชยทุกโซนที่เปลี่ยนไปเสมอมิฉะนั้นแอปของคุณจะพังในที่สุด
Basil Bourque

1
คำตอบสุดวิเศษ! ฉันรู้สึกขอบคุณเวลาที่คุณใส่ลงไปในเรื่องนี้ :)
drognisep

ZoneId.of ("อเมริกา / มอนทรีออล"); ทำไมบางคนถึงคิดค้นสิ่งนี้ใน jdk? มันน่าเกลียดน่าขยะแขยงไม่บอกว่ามีอะไรผิดปกติหรือไม่จนกว่าจะถึงเวลาทำงานใครจะจำรหัสยากเหล่านั้นได้ทั้งหมด ทำไมไม่บอกมันในคลาส ENUM
workplaylifecycle

4

ใน java8 ฉันจะใช้Instantคลาสที่อยู่ในUTCแล้วและสะดวกในการทำงานด้วย

import java.time.Instant;

Instant ins = Instant.now();
long ts = ins.toEpochMilli();

Instant ins2 = Instant.ofEpochMilli(ts)

หรือคุณสามารถใช้สิ่งต่อไปนี้:

import java.time.*;

Instant ins = Instant.now(); 

OffsetDateTime odt = ins.atOffset(ZoneOffset.UTC);
ZonedDateTime zdt = ins.atZone(ZoneId.of("UTC"));

กลับไปยัง Instant

Instant ins4 = Instant.from(odt);

3
ไม่มีความInstantเป็นได้ในเวลาท้องถิ่น Instantโดยความหมายอยู่ใน UTC ดังนั้นไม่จำเป็นต้องใช้เครื่องจักรที่เห็นในคำตอบนี้เพื่อพยายามเข้าสู่ UTC Instantแล้วเป็นเวลา UTC ดูคำตอบของฉันสำหรับข้อมูลเพิ่มเติมและรหัสที่ง่ายกว่ามาก
Basil Bourque

ขอบคุณสำหรับความคิดเห็น
Abel Terefe


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