java - جافا 8 التاريخ والوقت: تحليل سلسلة ISO 8601 دون النقطتين في الإزاحة




datetime iso8601 (3)

إذا كنت ترغب في تحليل جميع التنسيقات الصالحة للإزاحات ( Z و ±hh:mm و ±hhmm و ±hh ) ، فإن أحد البدائل هو استخدام java.time.format.DateTimeFormatterBuilder اختيارية (unfortunatelly ، يبدو أنه لا يوجد مفردة رسالة نمط لمطابقة لهم جميعا):

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // date/time
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // offset (hh:mm - "+00:00" when it's zero)
    .optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
    // offset (hhmm - "+0000" when it's zero)
    .optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
    // offset (hh - "Z" when it's zero)
    .optionalStart().appendOffset("+HH", "Z").optionalEnd()
    // create formatter
    .toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));

جميع الحالات الأربع المذكورة أعلاه سوف يتم تحليلها إلى 2022-03-17T23:00Z .

يمكنك أيضًا تحديد نمط سلسلة مفرد إذا أردت ، وذلك باستخدام [] لتحديد الأقسام الاختيارية:

// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");

يعمل هذا المنسق أيضًا مع جميع الحالات ، تمامًا مثل المنسق السابق أعلاه. تحقق من javadoc للحصول على مزيد من التفاصيل حول كل نمط.

ملاحظات:

  • يعد التنسيق مع أقسام اختيارية مثل ما سبق مفيدًا للتحليل ، ولكن ليس للتنسيق. عند التنسيق ، ستقوم بطباعة جميع الأقسام الاختيارية ، مما يعني أنها ستطبع الإزاحة عدة مرات. لذلك ، لتنسيق التاريخ ، فقط استخدم منسق آخر.
  • يقبل التنسيق الثاني 3 أرقام بالضبط بعد .SSS العشرية (بسبب .SSS ). من ناحية أخرى ، ISO_LOCAL_DATE_TIME أكثر مرونة: الثواني والثانية من النانو اختيارية ، كما تقبل من 0 إلى 9 أرقام بعد العلامة العشرية. اختر أفضل ما يناسب بيانات الإدخال الخاصة بك.

نحاول تحليل ISO 8601 DateTime String التالية مع إزاحة المنطقة الزمنية:

final String input = "2022-03-17T23:00:00.000+0000";

OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);

تفشل كلتا الطريقتين (الأمر المنطقي حيث OffsetDateTime أيضًا DateTimeFormatter.ISO_OFFSET_DATE_TIME ) بسبب النقطتين في إزاحة المنطقة الزمنية.

java.time.format.DateTimeParseException: تعذر تحليل النص '2022-03-17T23: 00: 00.000 + 0000' في الفهرس 23

ولكن وفقًا لـ Wikipedia يوجد 4 تنسيقات صالحة لإزاحة المنطقة الزمنية:

<time>Z 
<timehh:mm 
<timehhmm 
<timehh

يمكن أن ISO8601Utils الأطر / اللغات الأخرى هذه السلسلة دون أي مشاكل ، على سبيل المثال ، Date() Javascript Date() أو Jacksons ISO8601Utils (يناقشون هذه المشكلة here )

الآن يمكننا كتابة DateTimeFormatter الخاصة بنا مع RegEx معقد ، ولكن في رأيي ، يجب أن تكون مكتبة java.time قادرة على تحليل سلسلة ISO 8601 الصالحة هذه افتراضيًا لأنها سلسلة صالحة.

في الوقت الحالي ، نستخدم Jacksons ISO8601DateFormat ، لكننا نفضل استخدام مكتبة date.time الرسمية للعمل معها. ماذا سيكون نهجكم لمعالجة هذه المشكلة؟


لا تحتاج إلى كتابة regex معقدة - يمكنك إنشاء DateTimeFormatter التي ستعمل مع هذا التنسيق بسهولة:

DateTimeFormatter formatter =
    DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);

OffsetDateTime odt = OffsetDateTime.parse(input, formatter);

سوف يقبل أيضًا "Z" بدلاً من "0000". لن يقبل "+00: 00" (مع النقطتين أو ما شابه ذلك. هذا أمر مثير للدهشة نظرًا للوثائق ، ولكن إذا كانت القيمة الخاصة بك تحتوي دائمًا على إزاحة UTC بدون النقطتين ، فيجب أن تكون على ما يرام.


نظرًا لأنه بدون نقطتين ، يمكنك استخدام سلسلة التنسيق الخاصة بك:

final String input = "2022-03-17T23:00:00.000+0000";

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    Date parsed = df.parse(input);
    System.out.println(parsed);




datetime-parsing