DateTimeParseException: ошибка на одном хосте, работает на другом, тот же JDK - PullRequest
3 голосов
/ 10 июля 2019

Я абсолютно сбит с толку. Я использую OpenJdk 11.0.3 как локально, так и на моем рабочем хосте. Один разбирает дату, а другой нет. Любые идеи о том, что может быть причиной разницы?

Редактировать: в конце отмечена хакерская работа вокруг

Тот же JDK:

kesselc:~/openjdk-11.0.3+7/bin$ ./java -version
openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment 18.9 (build 11.0.3+7)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.3+7, mixed mode)

prodhost: # java -version
openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment (build 11.0.3+7-Ubuntu-1ubuntu218.04.1)
OpenJDK 64-Bit Server VM (build 11.0.3+7-Ubuntu-1ubuntu218.04.1, mixed mode, sharing)

Различные результаты:

kesselc:$ ~/openjdk-11.0.3+7/bin/java DateTest
2019-07-10T09:48-06:00[America/Denver]

prodhost: # java DateTest
Exception in thread "main" java.time.format.DateTimeParseException: Text '948 AM MDT Wed Jul 10 2019' could not be parsed: null
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
    at DateTest.main(DateTest.java:13)
Caused by: java.lang.NullPointerException
    at java.base/java.time.format.DateTimeFormatterBuilder$PrefixTree.prefixLength(DateTimeFormatterBuilder.java:4527)
    at java.base/java.time.format.DateTimeFormatterBuilder$PrefixTree.add0(DateTimeFormatterBuilder.java:4396)
    at java.base/java.time.format.DateTimeFormatterBuilder$PrefixTree.add(DateTimeFormatterBuilder.java:4391)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.getTree(DateTimeFormatterBuilder.java:4138)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneIdPrinterParser.parse(DateTimeFormatterBuilder.java:4249)
    at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.parse(DateTimeFormatterBuilder.java:2370)
    at java.base/java.time.format.DateTimeFormatter.parseUnresolved0(DateTimeFormatter.java:2107)
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2036)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 2 more

Вот простой тестовый класс, на котором я работаю:

public class DateTest {
    private static final DateTimeFormatter hhmm_a_zzz_EEE_MMM_dd_yyyy = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("hmm a zzz EEE MMM d yyyy")
            .toFormatter();

    public static void main(String[] args) {
        System.out.println(ZonedDateTime.parse("948 AM MDT Wed Jul 10 2019", hhmm_a_zzz_EEE_MMM_dd_yyyy));
    }
}

Редактировать: мое решение, своего рода. В этом случае я анализирую прогнозы NOAA, которые конкретно ориентированы на США. Итак, я взломал свой собственный эквивалент ZoneId.of ("MDT"), чтобы сопоставить смещение для 17 часовых поясов, отмеченных здесь: https://www.timetemperature.com/abbreviations/united_states_time_zone_abbreviations.shtml

Я чувствую себя немного грязно и стыдно, но этот конкретный анализатор даты специфичен для этого конкретного источника, поэтому я назову его достаточно хорошим.

Я до сих пор не знаю, почему две системы вели себя по-разному, но теперь проблема не имеет значения.

Вот дамп System.getProperties на двух системах.

Хорошо (kesselc):

{sun.desktop = gnome, awt.toolkit = sun.awt.X11.XToolkit, java.specification.version = 11, sun.cpu.isalist =, sun.jnu.encoding = UTF-8, java.class .path =., java.vm.vendor = Oracle Corporation, sun.arch.data.model = 64, java.vendor.url = http://java.oracle.com/, user.timezone =, os.name = Linux, java.vm .specification.version = 11, sun.java.launcher = SUN_STANDARD, user.country = US, sun.boot.library.path = / home / kesselc / .sdkman /андидаты / java / 11.0.2-open / lib, sun .java.command = DateTest, jdk.debug = release, sun.cpu.endian = little, user.home = / home / kesselc, user.language = en, java.specification.vendor = Oracle Corporation, java.version.date = 2019-01-15, java.home = / home / kesselc / .sdkman /андидаты / java / 11.0.2-open, file.separator = /, java.vm.compressedOopsMode = на основе нуля, line.separator = , java.specification.name = Спецификация API платформы Java, java.vm.specification.vendor = Oracle Corporation, java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment, sun.management.compiler = HotSpot 64-разрядные многоуровневые компиляторы, java. runtime.version = 11.0.2 + 9, user.name = kesselc, path.separator = :, os.version = 4.4.0-154-generic, java.runtime.name = OpenJDK среда выполнения, file.encoding = UTF- 8, java.vm.name = OpenJDK 64-разрядная серверная виртуальная машина, java.vendor.version = 18,9, java.vendor.url.bug = http://bugreport.java.com/bugreport/, java.io.tmpdir = / tmp, java.version = 11.0.2, user.dir = / home / kesselc / Проекты / flex / weather / out / production / classes, os.arch = amd64, java.vm.specification.name = Спецификация виртуальной машины Java, java.awt.printerjob = sun.print.PSPrinterJob, sun.os.patch.level = неизвестно, java.library.path = / usr / java / packages / lib: / usr / lib64: / lib64: / lib: / usr / lib, java.vendor = Oracle Corporation, java.vm.info = смешанный режим, java.vm.version = 11.0.2 + 9, sun.io.unicode.encoding = UnicodeLittle, java.class.version = 55.0}

Сбой (prodhost):

{awt.toolkit = sun.awt.X11.XToolkit, java.specification.version = 11, sun.cpu.isalist =, sun.jnu.encoding = ANSI_X3.4-1968, java.class.path =. , java.vm.vendor = Oracle Corporation, sun.arch.data.model = 64, java.vendor.url = http://java.oracle.com/, user.timezone =, os.name = Linux, java.vm.specification.version = 11, sun.java.launcher = SUN_STANDARD, user.country = US, sun.boot.library.path = / usr / lib / jvm / java-11-openjdk-amd64 / lib, sun.java.command = DateTest, jdk.debug = release, sun.cpu.endian = little, user.home = / root, user.language = en, java.specification.vendor = Oracle Corporation, java.version.date = 2019-04-16, java. home = / usr / lib / jvm / java-11-openjdk-amd64, file.separator = /, java.vm.compressedOopsMode = 32-разрядный, line.separator =, java.specification.name = Спецификация API платформы Java, java.vm.specification.vendor = Oracle Corporation, java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment, sun.management.compiler = HotSpot 64-разрядные многоуровневые компиляторы, java. runtime.version = 11.0.3 + 7-Ubuntu-1ubuntu218.04.1, user.name = root, path.separator = :, os.version = 4.4.0-1079-aws, java.runtime.name = OpenJDK Runtime Environment, file.encoding = ANSI_X3.4-1968, java.vm.name = OpenJDK 64-битная виртуальная машина сервера, java.vendor.url.bug = http://bugreport.java.com/bugreport/, java.io.tmpdir = / tmp, java.version = 11.0.3, user.dir = / opt / ct / deploy, os.arch = amd64, java.vm.specification.name = Спецификация виртуальной машины Java, java.awt.printerjob = sun.print.PSPrinterJob, sun.os. patch.level = неизвестно, java.library.path = / usr / java / packages / lib: / usr / lib / x86_64-linux-gnu / jni: / lib / x86_64-linux-gnu: / usr / lib / x86_64- linux-gnu: / usr / lib / jni: / lib: / usr / lib, java.vendor = Oracle Corporation, java.vm.info = смешанный режим, совместное использование, java.vm.version = 11.0.3 + 7-Ubuntu -1ubuntu218.04.1, sun.io.unicode.encoding = UnicodeLittle, java.class.version = 55,0} * 1 043 *

Ответы [ 3 ]

3 голосов
/ 10 июля 2019

Действительно, это загадочно. То, что null как часть попытки вызвать ошибку, кажется странным. Я не могу воспроизвести вашу проблему, попробовав 2 среды с Java 8 и 12.

У меня есть несколько предложений:

  • Всегда указывайте Locale при разборе текста, например, имени дня или названия месяца.
  • В отдельном методе упростите свой код до абсолютного минимума, чтобы избежать побочных эффектов.
  • Дамп информации о вашей среде JVM с помощью вызова System.getProperties().

Код:

package work.basil.example;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class App {
    public static void main ( String[] args ) {
        System.out.println ( "Hello World!" );
        App app = new App ();
        app.doIt ();
    }

    private void doIt ( ) {


        DateTimeFormatterBuilder builder =
                new DateTimeFormatterBuilder ()
                        .parseCaseInsensitive ()
                        .appendPattern ( "hmm a zzz EEE MMM d yyyy" );

        Locale locale = Locale.US;
        DateTimeFormatter f = builder.toFormatter ( locale );

        String input = "948 AM MDT Wed Jul 10 2019";
        ZonedDateTime zdt = ZonedDateTime.parse ( input , f );

        System.out.println ( "zdt.toString() = " + zdt );

        System.out.println ( System.getProperties () );

    }
}

Я успешно запустил это:

  • Мой собственный Mac Mini (2018) с macOS Mojave 10.14.5 с использованием Java 12.0.1 + 12 из AdoptOpenJDK с HotSpot.
  • IdeOne.com запускает java.version = 1.8.0_112 из Oracle JDK с HotSpot. Смотрите этот код запуска в реальном времени .
  • Ubuntu 18.04.1 LTS с OpenJDK 11.0.3 + 7 от AdoptOpenJDK.net (работает в виртуальной машине Parallels на Mac).
  • Ubuntu 18.04.2 LTS с Oracle JDK 11.0.3 + 12 из сайта Oracle .

Одинаковый результат для всех из них.

zdt.toString () = 2019-07-10T09: 48-06: 00 [Америка / Денвер]

Свойства системы

Mac

{awt.toolkit = sun.lwawt.macosx.LWCToolkit, java.specification.version = 12, sun.jnu.encoding = UTF-8, java.class.path = / Users / basilbourque / IdeaProjects / Demo / target /classes:/Users/basilbourque/.m2/repository/org/threeten/threeten-extra/1.5.0/threeten-extra-1.5.0.jar, java.vm.vendor = AdoptOpenJDK, sun.arch.data.model = 64, java.vendor.url = https://adoptopenjdk.net/, java.vm.specification.version = 12, os.name = Mac OS X, sun.java.launcher = SUN_STANDARD, user.country = US, sun.boot .library.path = / Библиотека / Java / JavaVirtualMachines / accepttopenjdk-12.jdk / Contents / Home / lib, sun.java.command = work.basil.example.App, http.nonProxyHosts = local | .local | 169.254 / 16 | .169.254 / 16, jdk.debug = release, sun.cpu.endian = little, user.home = / Users / basilbourque, user.language = en, java.specification.vendor = Oracle Corporation, java.version.date = 2019-04-16, java.home = / Library / Java / JavaVirtualMachines / accepttopenjdk-12.jdk / Contents / Home, file.separator = /, java.vm.compressedOopsMode = на основе нуля, строка. сепаратор = , java.vm.specification.vendor = Oracle Corporation, java.specification.name = Спецификация API платформы Java, java.awt.graphicsenv = sun.awt.CGraphicsEnvironment, sun.management.compiler = 64-разрядные многоуровневые компиляторы HotSpot, ftp. nonProxyHosts = local | .local | 169.254 / 16 | .169.254 / 16, java.runtime.version = 12.0.1 + 12, user.name = basilbourque, path.separator = :, os.version = 10.14.5, java.runtime.name = среда выполнения OpenJDK, file.encoding = UTF-8, java.vm.name = OpenJDK 64-битная виртуальная машина сервера, java.vendor.version = AdoptOpenJDK, java.vendor.url.bug = https://github.com/AdoptOpenJDK/openjdk-build/issues, java.io.tmpdir = / var / folder / qk / grjjffnj7ml_r54rrb1c2pbw0000gn / T /, java.version = 12.0.1, user.dir = / Users / basilbourque / IdeaProjects / Demo, os.arch = x86_64, java.vm.specification.name = Спецификация виртуальной машины Java, java.library.path = / Пользователи / basilbourque / Библиотека / Java / Расширения: / Библиотека / Java / Расширения: / Сеть / Библиотека / Java / Расширения: / Система / Библиотека / Java / Расширения: / usr / lib / java:., Java.vm.info = смешанный режим, совместное использование, java.vendor = AdoptOpenJDK, java.v m.version = 12.0.1 + 12, sun.io.unicode.encoding = UnicodeBig, socksNonProxyHosts = local | .local | 169.254 / 16 | .169.254 / 16, java.class.version = 56.0}

IdeOne.com

{java.runtime.name = Java (TM) среда выполнения SE, sun.boot.library.path = / opt / jdk / jre / lib / amd64, java.vm.version = 25.112-b15, java.vm .vendor = Oracle Corporation, java.vendor.url = http://java.oracle.com/, path.separator = :, java.vm.name = Java HotSpot (TM) Виртуальная 64-битная виртуальная машина Java, file.encoding.pkg = sun.io , user.country = US, sun.java.launcher = SUN_STANDARD, sun.os.patch.level = неизвестно, java.vm.specification.name = Спецификация виртуальной машины Java, user.dir = / home / uXdFYs, java.runtime .version = 1.8.0_112-b15, java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment, java.endorsed.dirs = / opt / jdk / jre / lib / одобрено, os.arch = amd64, java.io.tmpdir = / tmp, line.separator = , java.vm.specification.vendor = Oracle Corporation, os.name = Linux, sun.jnu.encoding = ANSI_X3.4-1968, java.library.path = / usr / java / packages / lib / amd64: / usr / lib64: / lib64: / lib: / usr / lib, java.specification.name = Спецификация API платформы Java, java.class.version = 52.0, sun.management.compiler = HotSpot 64-разрядные многоуровневые компиляторы, os.version = 3.16 .0-4-amd64, user.home = ?, user.timezone =, java.awt.printerjob = sun.print.PSPrinterJob, file.encoding = UTF-8, java.specification.version = 1.8, java.class. путь = test.zip, user.name = ?, java.vm.specification.version = 1.8, sun.java.command = test.zip, java.home = / opt / jdk / jre, sun.arch.data.model = 64, user.language = ru, java.specification.vendor = Oracle Corporation, awt.toolkit = sun.awt.X11.XToolkit, java.vm.info = смешанный режим, java.version = 1.8.0_112, java.ext .dirs = / opt / jdk / lib, sun.boot.class.path = / opt / jdk / jre / lib / resources.jar: /opt/jdk/jre/lib/rt.jar: / opt / jdk / jre /lib/sunrsasign.jar:/opt/jdk/jre/lib/jsse.jar:/opt/jdk/jre/lib/jce.jar:/opt/jdk/jre/lib/charsets.jar:/opt/jdk / JRE / lib / jfr.jar: / opt / jdk / jre / classes, java.vendor = Oracle Corporation, file.separator = /, java.vendor.url.bug = http://bugreport.sun.com/bugreport/, sun.io.unicode.encoding = UnicodeLittle, sun.cpu.endian = little, sun.cpu.isalist =}

3 голосов
/ 11 июля 2019

Я искал в исходном коде DateTimeFormatterBuilder, и я далеко не уверен, но мне кажется, что возможной причиной вашего NullPointerException является отсутствие обозначения нулевого часового пояса в некоторых данных локали.Это может заставить DateTimeFormatterBuilder.ZoneTextPrinterParser.getTree() передать ноль в DateTimeFormatterBuilder.PrefixTree.add(), что, в свою очередь, не ожидает ноль.В этом случае разное поведение может быть вызвано сочетанием разных часовых поясов и разных локалей.Обратите внимание, что часовой пояс и локаль независимы.

Редактировать: спрашивающий сообщил, что мое предложение не решает эту конкретную проблему.Я оставляю это в силе, потому что я думаю, что возможность указания предпочтительных часовых поясов для анализа аббревиатуры часовых поясов может быть полезна для некоторых других.

Я не воспроизвел ваше исключение, поэтому не могу дать точный способ исправить, но я хотел бы предложить вам попробовать:

    Set<ZoneId> preferredZones = Set.of(ZoneId.of("America/Goose_Bay"),
            ZoneId.of("America/Moncton"), ZoneId.of("America/New_York"),
            ZoneId.of("America/Chicago"), ZoneId.of("America/Denver"),
            ZoneId.of("America/Los_Angeles"), ZoneId.of("America/Anchorage"),
            ZoneId.of("Pacific/Honolulu"), ZoneId.of("America/Adak"),
            ZoneId.of("Pacific/Pago_Pago"), ZoneId.of("Pacific/Guam"));
    DateTimeFormatter hhmm_a_zzz_EEE_MMM_dd_yyyy = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("hmm a ")
            .appendZoneText(TextStyle.SHORT, preferredZones)
            .appendPattern(" EEE MMM d yyyy")
            .toFormatter(Locale.US);

Предпочтительные зоны выбраны в соответствии с 17 сокращениями, на которые вы ссылаетесь:

AST        America/Goose_Bay, America/Moncton
EST EDT    America/New_York
CST CDT    America/Chicago
MST MDT    America/Denver
PST PDT    America/Los_Angeles
AKST AKDT  America/Anchorage
HST        Pacific/Honolulu
HAST HADT  America/Adak
SST SDT    Pacific/Pago_Pago
CHST       Pacific/Guam

Возможно, вы захотите проверить,У меня правильные отображения.

Кроме того, как уже предлагали другие, я указал Locale.US для форматера.

2 голосов
/ 10 июля 2019

У меня раньше была такая же проблема, что работало для меня, менял .toFormatter() на .toFormatter(Locale.US).Я не уверен, что вызывает эту проблему, это должно быть что-то с часовыми поясами машин.Посмотрите, работает ли это для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...