จัดรูปแบบทันทีเป็นสตริง


227

ฉันพยายามจัดรูปแบบสตริงเป็นสตริงโดยใช้ java 8 time-api ใหม่และรูปแบบ:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

ใช้รหัสข้างต้นฉันได้รับการยกเว้นซึ่งบ่นว่าฟิลด์ไม่ได้รับการสนับสนุน:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
    at java.time.Instant.getLong(Instant.java:608)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

คำตอบ:


310

เขตเวลา

การจัดรูปแบบโซนเวลาเป็นสิ่งจำเป็น หากไม่มีเขตเวลาตัวจัดรูปแบบจะไม่ทราบวิธีแปลงทันทีเป็นเขตข้อมูลวันที่เป็นมนุษย์ดังนั้นจึงมีข้อผิดพลาดเกิดขึ้นInstant

withZone()The-เขตเวลาสามารถเพิ่มโดยตรงเพื่อจัดรูปแบบโดยใช้

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

กำลังสร้าง String

ตอนนี้ใช้ตัวจัดรูปแบบนั้นเพื่อสร้างการแสดงสตริงของ Instant ของคุณ

Instant instant = Instant.now();
String output = formatter.format( instant );

ถ่ายโอนข้อมูลไปยังคอนโซล

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

เมื่อวิ่ง

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

50
ขอบคุณ!! BTW ข้อยกเว้น "เขตข้อมูลที่ไม่สนับสนุน" ซึ่งชี้ไปที่เช่นปีเป็นสิ่งที่น่าทึ่ง อาจตรวจพบสถานการณ์นี้และข้อยกเว้นที่ชี้ไปยัง id โซนที่หายไปในการค้นหาทันใจควรถูกส่งออกไป!
davidbak

1
ยิ่งแปลกไปกว่านั้นถ้าคุณรวม. withZone (เช่น. withZone (ZoneId.of ("Z"))) และจัดรูปแบบ LocalDateTime โซนนั้นจะไม่สนใจ! ดังนั้นตราบใดที่. withZone () รวมอยู่ด้วยตัวจัดรูปแบบเดียวกันสามารถใช้ทั้งสำหรับ Instant และ LocalDateTime โดยไม่กระทบกับเวลาที่แสดงสำหรับหลัง
เกล็น

1
เหตุใดจึงยากที่จะยอมรับความจริงที่ว่า Instant มีเขตเวลาซึ่งเป็น GMT
Koray Tugay

1
@KorayTugay เพราะในขณะที่ความเห็น "ทันทีทันใดนั้น GMT" อาจเป็นความจริงพวกเขาอยู่ไกลจากความช่วยเหลือเมื่อเผชิญกับข้อยกเว้นการโยนทิ้งเนื่องจากการจัดรูปแบบทันทีโดยไม่ระบุเขตเวลาไม่ทำงาน คงจะดีถ้าตัวจัดรูปแบบเริ่มต้นเป็น GMT แต่ก็ดี
Ti Strga

ตอนนี้ให้yyyy-MM-dd hh:mm:ssรูปแบบ:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

39
public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

3
ในขณะที่รหัสนี้อาจจะตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและเหตุผลที่จะแก้ปัญหาที่เกิดขึ้นจะปรับปรุงคำตอบเป็นระยะยาวคุ้มค่า
อเล็กซานเด

1
ในขณะที่ข้อมูลโค้ดนี้อาจแก้ปัญหาได้รวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ
Rosário Pereira Fernandes

23
DateTimeFormatter.ISO_INSTANT.format(Instant.now())

สิ่งนี้ช่วยให้คุณไม่ต้องแปลงเป็น UTC อย่างไรก็ตามกรอบเวลาของภาษาอื่นอาจไม่สนับสนุนมิลลิวินาทีดังนั้นคุณควรทำ

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

คุณหมายถึงอะไรโดย "กรอบเวลาของภาษาอื่น" ISO_INSTANT.format () จะตัดเป็นวินาทีโดยอัตโนมัติหรือไม่
Guangtong Shen

เฟรมเวิร์กบางตัวคาดว่าจะใช้เวลาเพียงไม่กี่วินาทีเท่านั้นเนื่องจากเฟรมเวิร์กเหล่านี้จะไม่ปฏิบัติตามข้อกำหนด ISO เต็มรูปแบบและจะหยุดพักเมื่อมีมิลลิวินาทีเป็นส่วนหนึ่งของสตริงอินพุต
Archimedes Trajano

21

Instantชั้นไม่ได้มีข้อมูลโซนก็เพียงร้านค้าประทับเวลาในหน่วยมิลลิวินาทีจากยูนิกซ์ยุคคือ 1 มกราคม 1070 จาก UTC ดังนั้นตัวจัดรูปแบบไม่สามารถพิมพ์วันที่ได้เนื่องจากวันที่พิมพ์สำหรับเขตเวลาคอนกรีตเสมอ คุณควรตั้งค่าเขตเวลาเป็นตัวจัดรูปแบบและทุกอย่างจะดีเช่นนี้:

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

4

หรือถ้าคุณยังต้องการใช้ฟอร์แมตเตอร์ที่สร้างจากรูปแบบคุณสามารถใช้ LocalDateTime แทน Instant:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

4

Instants อยู่ใน UTC แล้วและมีรูปแบบวันที่เริ่มต้นเป็น yyyy-MM-ddแล้ว หากคุณพอใจกับสิ่งนี้และไม่ต้องการยุ่งกับเขตเวลาหรือการจัดรูปแบบคุณสามารถทำได้toString():

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


ไม่ต้องการ T และ Z ใช่ไหม (Z หมายถึงวันที่นี้คือ UTC Z ย่อมาจาก "Zulu" aka "offset zero zero" หรือ UTC):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


ต้องการมิลลิวินาทีแทนนาโนวินาทีหรือไม่ (เพื่อให้คุณสามารถใส่ลงในแบบสอบถาม SQL):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

เป็นต้น


-3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

ฉันเชื่อว่าสิ่งนี้อาจช่วยคุณได้คุณอาจต้องใช้รูปแบบ Localdate รูปแบบอื่นแทนการโต้ตอบแบบทันที

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