Định dạng tức thì thành chuỗi


227

Tôi đang cố gắng định dạng Instant thành Chuỗi bằng cách sử dụng java 8 time-api mới và một mẫu:

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

Sử dụng mã ở trên tôi nhận được một Ngoại lệ khiếu nại trường không được hỗ trợ:

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

Câu trả lời:


310

Múi giờ

Để định dạng một Instantmột múi giờ là bắt buộc. Không có múi giờ, trình định dạng không biết cách chuyển đổi tức thời sang trường thời gian của con người và do đó ném ra một ngoại lệ.

Múi giờ có thể được thêm trực tiếp vào bộ định dạng bằng cách sử dụng withZone().

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

Tạo chuỗi

Bây giờ sử dụng trình định dạng đó để tạo biểu diễn Chuỗi của Instant của bạn.

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

Đổ vào bàn điều khiển.

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

Khi chạy.

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
Cảm ơn bạn!! BTW, "trường không được hỗ trợ" ngoại lệ, chỉ vào năm, là một sự ngoạn mục. Có lẽ tình huống này sẽ được phát hiện và một ngoại lệ trỏ trực tiếp vào id vùng bị thiếu trong Instant sẽ bị ném!
davidbak

1
Kỳ lạ hơn, nếu bạn bao gồm .withZone (ví dụ: .withZone (ZoneId.of ("Z"))) và định dạng LocalDateTime, khu vực này được IGNORED! Vì vậy, miễn là .withZone () được bao gồm, cùng một bộ định dạng có thể được sử dụng cho cả Instant và LocalDateTime, mà không ảnh hưởng đến thời gian hiển thị cho lần sau.
Glenn

1
Tại sao rất khó chấp nhận thực tế là Instant có TimeZone là GMT?
Koray Tugay

1
@KorayTugay Bởi vì mặc dù các bình luận "Instant đã là GMT" có thể đúng, nhưng chúng không hữu ích khi phải đối mặt với một dấu vết ngoại lệ vì định dạng Instant mà không chỉ định múi giờ không hoạt động. Sẽ thật tuyệt nếu bộ định dạng mặc định là GMT, nhưng ồ.
Ti Strga

Bây giờ điều này cung cấp cho bạn yyyy-MM-dd hh:mm:ssđịnh dạng: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
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thứclý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Alexander

1
Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
Rosário Pereira Fernandes

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

Điều này giúp bạn không phải chuyển đổi sang UTC. Tuy nhiên, khung thời gian của một số ngôn ngữ khác có thể không hỗ trợ mili giây vì vậy bạn nên làm

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

Bạn có ý nghĩa gì bởi "một số khung thời gian của ngôn ngữ khác"? ISO_INSTANT.format () sẽ tự động cắt ngắn thành giây?
Guangtong Shen

Một số khung chỉ mong đợi thời gian tăng lên đến giây vì chúng không tuân theo quy ước ISO đầy đủ và bị phá vỡ khi có một phần nghìn giây là một phần của chuỗi đầu vào.
Archimedes Trajano

21

Các Instantlớp không chứa thông tin Zone, nó chỉ cửa hàng đánh dấu thời gian trong mili giây từ UNIX kỷ nguyên, tức là ngày 01 tháng 1 năm 1070 từ UTC. Vì vậy, trình định dạng không thể in ngày vì ngày luôn được in theo múi giờ cụ thể. Bạn nên đặt múi giờ để định dạng và tất cả sẽ ổn, như thế này:

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

Hoặc nếu bạn vẫn muốn sử dụng trình định dạng được tạo từ mẫu, bạn chỉ có thể sử dụng LocalDateTime thay vì Instant:

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

4

Các phần tử đã có trong UTC và đã có định dạng ngày mặc định là yyyy-MM-dd . Nếu bạn hài lòng với điều đó và không muốn gây rối với múi giờ hoặc định dạng, bạn cũng có thể toString():

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


Bạn không muốn T và Z? (Z cho biết ngày này là UTC. Z là viết tắt của "Zulu" hay còn gọi là "Không giờ bù giờ" hay còn gọi là UTC):

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


Muốn mili giây thay vì nano giây? (Vì vậy, bạn có thể đặt nó vào một truy vấn sql):

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

Vân vân.


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

Tôi tin rằng điều này có thể giúp ích, bạn có thể cần phải sử dụng một số loại biến thể cục bộ thay vì ngay lập tức

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.