Định dạng ngày này là gì? 2011-08-12T20: 17: 46.384Z


383

Tôi có ngày sau : 2011-08-12T20:17:46.384Z. Định dạng này là gì? Tôi đang cố phân tích cú pháp với Java 1.4 thông qua DateFormat.getDateInstance().parse(dateStr)và tôi đang nhận được

java.text.PudeException: Ngày không thể phát hiện: "2011-08-12T20: 17: 46.384Z"

Tôi nghĩ rằng tôi nên sử dụng SimpleDateFormat để phân tích cú pháp, nhưng trước tiên tôi phải biết chuỗi định dạng. Tất cả những gì tôi có cho đến nay là yyyy-MM-ddbởi vì tôi không biết ý Tnghĩa của chuỗi này - thứ gì đó liên quan đến múi giờ? Chuỗi ngày này đến từ lcmis:downloadedOnthẻ được hiển thị trên loại phương tiện lịch sử tải xuống Tệp CMIS .



3
@TomaszNurkiewicz, không phải vậy. ISO8601 cuối cùng không có Z.
t1gor

4
Doe ISO8601 cho phép Z ở cuối. Xem liên kết ở trên, tìm kiếm UTC.
Jonathan Rosenne

2
@ t1gor Các Zở cuối là viết tắt của Zuluvà phương tiện UTC . Định dạng này chắc chắn một phần của bộ sưu tập định dạng văn bản theo thời gian tiêu chuẩn ISO 8601 . Nhân tiện, các định dạng tiêu chuẩn này được sử dụng theo mặc định trong các lớp java.time .
Basil Bourque

3
FYI, các lớp thời gian cũ rắc rối như java.util.Date, java.util.Calendarjava.text.SimpleDateFormathiện là di sản , được thay thế bởi các lớp java.time được tích hợp trong Java 8 & Java 9. Xem Hướng dẫn của Oracle .
Basil Bourque

Câu trả lời:


512

Chữ T chỉ là một nghĩa đen để tách ngày khỏi thời gian và chữ Z có nghĩa là "bù giờ 0" còn được gọi là "thời gian Zulu" (UTC). Nếu chuỗi của bạn luôn có "Z", bạn có thể sử dụng:

SimpleDateFormat format = new SimpleDateFormat(
    "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

Hoặc sử dụng Joda Time , bạn có thể sử dụng ISODateTimeFormat.dateTime().


7
Tại sao chúng ta cần các trích dẫn duy nhất xung quanh TZ?
Maroun

7
@MarounMaroun: Về cơ bản chúng tôi muốn những nhân vật theo nghĩa đen . Có thể không cần thiết cho T(Tôi không thể nhớ cách SimpleDateFormat xử lý các chỉ định không xác định) nhưng Zchúng tôi muốn nó là ký tự 'Z' thay vì "giá trị bù UTC" (ví dụ: "00").
Jon Skeet

2
@nyedidikeke: Trong trang Wikipedia mà bạn đã liên kết, nó hiển thị "múi giờ Zulu" cho UTC. Tôi không chắc những gì bạn tin rằng bạn đang sửa chữa.
Jon Skeet

9
@JonSkeet: nó có thể tạo ra một cuộc tranh luận không cần thiết; không tranh chấp câu trả lời của bạn nhưng có ý định thu hút sự chú ý của chữ Z có chữ cái đầu tiên từ "zero UTC offset". Chữ Z được gọi là "Zulu" trong bảng chữ cái ngữ âm của NATO . Đổi lại, cách tiếp cận quân sự để đề cập đến phần bù UTC bằng 0 được neo trên chữ Z mà họ xác định là Zulu, lấy tên mã hóa của họ: múi giờ Zulu. Điều quan trọng cần lưu ý là Z không bị mất nghĩa và vẫn là công cụ chỉ định vùng cho phần bù UTC bằng 0 vì múi giờ Zulu (từ Z) chỉ đơn giản là một ngôn ngữ được mã hóa để chỉ về nó.
nyedidikeke

2
@nyedidikeke: Tôi vẫn không đồng ý về việc liệu có ai khác quan tâm đến sự khác biệt có liên quan đến câu trả lời của tôi không, nhưng tôi đã cập nhật nó. Tôi sẽ không đi vào tất cả các chi tiết, vì lịch sử rộng rãi không liên quan đến câu trả lời.
Jon Skeet

86

tl; dr

Tiêu chuẩn ISO 8601 định dạng được sử dụng bởi chuỗi đầu vào của bạn.

Instant.parse ( "2011-08-12T20:17:46.384Z" ) 

ISO 8601

Định dạng này được xác định bởi tiêu chuẩn thực tế hợp lý, ISO 8601 .

Phần Ttách biệt phần ngày với phần thời gian trong ngày. Kết Zthúc có nghĩa là UTC (nghĩa là độ lệch từ UTC là 0 giờ-phút-giây). Các Zđược phát âm là “Zulu” .

java.time

Các lớp thời gian cũ đi kèm với các phiên bản Java sớm nhất đã được chứng minh là được thiết kế kém, khó hiểu và rắc rối. Tránh chúng.

Thay vào đó, hãy sử dụng khung java.time được tích hợp trong Java 8 trở lên. Các lớp java.time thay thế cả các lớp thời gian cũ và thư viện Joda-Time rất thành công.

Các lớp java.time sử dụng ISO 8601 theo mặc định khi phân tích / tạo các biểu diễn văn bản của các giá trị thời gian.

Các Instantlớp đại diện cho một thời điểm trên Timeline trong UTC với độ phân giải nano giây . Lớp đó có thể phân tích trực tiếp chuỗi đầu vào của bạn mà không cần xác định mẫu định dạng.

Instant instant = Instant.parse ( "2011-08-12T20:17:46.384Z" ) ;

Bảng các loại thời gian trong Java, cả hiện đại và di sản


Giới thiệu về java.time

các java.time khung được xây dựng vào Java 8 và sau đó. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Để tìm hiểu thêm, xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Nơi để có được các lớp java.time?

  • Java SE 8 , Java SE 9 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với việc triển khai đi kèm.
    • Java 9 thêm một số tính năng nhỏ và sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng java.time được chuyển ngược sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản sau của triển khai gói Android của các lớp java.time.
    • Đối với Android trước đó, ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP .

Bảng mà thư viện java.time sẽ sử dụng với phiên bản Java hoặc Android nào

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho các bổ sung có thể trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval, YearWeek, YearQuarter, và nhiều hơn nữa .


3
@star Các Zulu Cảnh xuất phát từ truyền thống quân sự và hàng không trong đó 25 chữ cái của bảng chữ cái AZ (không có "J"), mỗi chữ cái có một tên có thể phát âm, đại diện cho phiên bản múi giờ của chúng . Vùng "Zulu" được bù 0 giờ so với UTC. Xem nàynày .
Basil Bourque

27

Không chắc chắn về phân tích cú pháp Java, nhưng đó là ISO8601: http://en.wikipedia.org/wiki/ISO_8601


Đây có phải là "2016-01-27T17: 44: 55UTC", ISO8601 không?
dùng1997292

Tôi không tin như vậy. Nó gần nhưng UTC là hậu tố không được phép. Nó phải là Z hoặc phần bù múi giờ, ví dụ: +0100. Tuy nhiên, Z và UTC có cùng một nghĩa, do đó, việc thay đổi UTC thành Z sẽ mang lại ISO 8601 hợp lệ
smparkes

9

Có nhiều cách khác để phân tích nó hơn là câu trả lời đầu tiên. Để phân tích cú pháp:

(1) Nếu bạn muốn lấy thông tin về ngày và giờ, bạn có thể phân tích nó thành một đối tượng ZonedDatetime(kể từ Java 8 ) hoặc Date(cũ):

// ZonedDateTime's default format requires a zone ID(like [Australia/Sydney]) in the end.
// Here, we provide a format which can parse the string correctly.
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2011-08-12T20:17:46.384Z", dtf);

hoặc là

// 'T' is a literal.
// 'X' is ISO Zone Offset[like +01, -08]; For UTC, it is interpreted as 'Z'(Zero) literal.
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

// since no built-in format, we provides pattern directly.
DateFormat df = new SimpleDateFormat(pattern);

Date myDate = df.parse("2011-08-12T20:17:46.384Z");

(2) Nếu bạn không quan tâm đến ngày và giờ và chỉ muốn coi thông tin là một khoảnh khắc tính bằng nano giây, thì bạn có thể sử dụng Instant:

// The ISO format without zone ID is Instant's default.
// There is no need to pass any format.
Instant ins = Instant.parse("2011-08-12T20:17:46.384Z");

1

Nếu các bạn đang tìm kiếm một giải pháp cho Android, bạn có thể sử dụng đoạn mã sau để lấy epoch giây từ chuỗi dấu thời gian.

public static long timestampToEpochSeconds(String srcTimestamp) {
    long epoch = 0;

    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            Instant instant = Instant.parse(srcTimestamp);
            epoch = instant.getEpochSecond();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'", Locale.getDefault());
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date date = sdf.parse(srcTimestamp);
            if (date != null) {
                epoch = date.getTime() / 1000;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return epoch;
}

Đầu vào mẫu: 2019-10-15T05: 51: 31.537979Z

Sản lượng mẫu: 1571128673


0

Bạn có thể sử dụng ví dụ sau.

    String date = "2011-08-12T20:17:46.384Z";

    String inputPattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    String outputPattern = "yyyy-MM-dd HH:mm:ss";

    LocalDateTime inputDate = null;
    String outputDate = null;


    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern, Locale.ENGLISH);
    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern, Locale.ENGLISH);

    inputDate = LocalDateTime.parse(date, inputFormatter);
    outputDate = outputFormatter.format(inputDate);

    System.out.println("inputDate: " + inputDate);
    System.out.println("outputDate: " + outputDate);

Bạn không nên đặt dấu nháy đơn xung quanh Z. Điều đó có nghĩa là mong đợi nhưng bỏ qua bức thư đó. Nhưng lá thư đó không nên bỏ qua. Bức thư đó cung cấp thông tin có giá trị, thực tế là chuỗi được dành cho UTC, phần bù bằng 0. Định dạng của bạn đang loại bỏ sự thật quan trọng này. Hơn nữa, không cần phải bận tâm đến việc xác định mẫu định dạng này. Một định dạng cho mẫu này được xây dựng.
Basil Bourque

-1

Kỹ thuật này dịch java.util.Date sang định dạng UTC (hoặc bất kỳ định dạng nào khác) và quay lại.

Xác định một lớp như vậy:

import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class UtcUtility {

public static DateTimeFormatter UTC = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZoneUTC();


public static Date parse(DateTimeFormatter dateTimeFormatter, String date) {
    return dateTimeFormatter.parseDateTime(date).toDate();
}

public static String format(DateTimeFormatter dateTimeFormatter, Date date) {
    return format(dateTimeFormatter, date.getTime());
}

private static String format(DateTimeFormatter dateTimeFormatter, long timeInMillis) {
    DateTime dateTime = new DateTime(timeInMillis);
    String formattedString = dateTimeFormatter.print(dateTime);
    return formattedString;
}

}

Sau đó sử dụng nó như thế này:

Date date = format(UTC, "2020-04-19T00:30:07.000Z")

hoặc là

String date = parse(UTC, new Date())

Bạn cũng có thể xác định các định dạng ngày khác nếu bạn yêu cầu (không chỉ UTC)


Cả hai java.util.Datevà dự án Joda-Time đã được thay thế từ nhiều năm trước bởi các lớp java.time hiện đại được định nghĩa trong JSR 310. Lời khuyên ở đây đã lỗi thời từ lâu.
Basil Bourque

java.time đã được giới thiệu trong Java 8. Câu hỏi này đặc biệt tham khảo Java 1.4 và do đó tôi đã cố tình tránh sử dụng các lớp mới hơn. Giải pháp này phục vụ cho các cơ sở mã cũ. Tôi cho rằng tác giả có thể chuyển cơ sở mã của mình sang Java 8 nhưng điều đó không phải lúc nào cũng đơn giản, hiệu quả hoặc cần thiết.
Gapmeister66

-1

@ John-Skeet đã cho tôi manh mối để khắc phục vấn đề của riêng tôi xung quanh vấn đề này. Là một lập trình viên trẻ, vấn đề nhỏ này rất dễ bỏ sót và khó chẩn đoán. Vì vậy, tôi chia sẻ nó với hy vọng nó sẽ giúp được ai đó.

Vấn đề của tôi là tôi muốn phân tích chuỗi sau đây chống lại dấu thời gian từ JSON Tôi không có ảnh hưởng và đặt nó vào các biến hữu ích hơn. Nhưng tôi cứ bị lỗi.

Vì vậy, đưa ra những điều sau đây (chú ý đến tham số chuỗi bên trong ofPotype ();

String str = "20190927T182730.000Z"

LocalDateTime fin;
fin = LocalDateTime.parse( str, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ") );

Lỗi:

Exception in thread "main" java.time.format.DateTimeParseException: Text 
'20190927T182730.000Z' could not be parsed at index 19

Vấn đề? Chữ Z ở cuối Mẫu cần được bọc trong 'Z' giống như 'T'. Thay đổi "yyyyMMdd'T'HHmmss.SSSZ"để "yyyyMMdd'T'HHmmss.SSS'Z'"và nó hoạt động.

Việc loại bỏ Z khỏi mẫu hoàn toàn cũng dẫn đến lỗi.

Thành thật mà nói, tôi mong đợi một lớp Java đã dự đoán điều này.


1
Điều này đã được hỏi và trả lời ở đâyở đây . Và giải pháp của bạn là sai. Trong khi Tlà một nghĩa đen và cần được trích dẫn, Zlà một phần bù (bằng 0) và cần được phân tích cú pháp như vậy, nếu không bạn sẽ nhận được kết quả sai. Tôi không biết ý của bạn là nó không được dự đoán trước, tôi tin rằng nó có.
Ole VV

1
Không, không, không, đừng bỏ qua Z. Bạn đang loại bỏ thông tin có giá trị. Xử lý giá trị thời gian trong khi bỏ qua múi giờ hoặc bù từ UTC giống như xử lý một lượng tiền trong khi bỏ qua tiền tệ!
Basil Bourque

1
Việc Tchỉ tách phần ngày với phần thời gian trong ngày và không có ý nghĩa gì. Mặt Zkhác chắc chắn thêm ý nghĩa.
Basil Bourque

Ole, cảm ơn vì các liên kết. Ill chắc chắn đọc những cái đó. Và tôi chấp nhận rằng tôi chắc chắn có thể sai khi còn trẻ. Tất cả những gì tôi nói là việc gói Z trong dấu ngoặc đơn giống như ký tự trong mẫu đã giải quyết lỗi. Sự chỉ trích của tôi là bất cứ ai thiết kế một phần "mẫu" của lớp đều có thể mã hóa xung quanh sự hiện diện hay vắng mặt của 'Z' (hoặc múi giờ khác?) Và 'T' có được bọc trong '' hay không. Bởi vì họ không độc đáo. Định dạng tôi xử lý xuất phát từ JSON từ một API thương mại được phân tích cú pháp thành một chuỗi. Nhưng tôi cần phân tích tất cả những điều đó vào lịch thời gian vv để làm cho chúng hữu ích hơn.
spencemw
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.