DateTimeParseException:在一台主机上失败,在另一台相同的JDK上运行

时间:2019-07-10 18:52:15

标签: java date

我绝对感到困惑。我在本地和生产主机上都使用OpenJdk 11.0.3。一个解析日期,一个不解析。关于可能导致差异的任何想法吗?

编辑:hacky解决方法在最后

相同的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 / candidates / 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 / candidates / java / 11.0.2-open,file.separator = /,java.vm.compressedOopsMode =基于零的line.separator =   ,java.specification.name = Java平台API规范,java.vm.specification.vendor = Oracle公司,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位服务器VM,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 / Projects / 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 =发行版,sun.cpu.endian =小,user.home = / root,user.language = zh-CN,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 = Java平台API规范,java.vm.specification.vendor = Oracle公司,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运行时环境, file.encoding = ANSI_X3.4-1968,java.vm.name = OpenJDK 64位服务器VM,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.c lass.version = 55.0}

5 个答案:

答案 0 :(得分:3)

的确,这很神秘。尝试生成错误的一部分null似乎很奇怪。在Java 8和12中尝试了2种环境后,我无法复制您的问题。

我有一些建议:

  • 在分析诸如日期或月份名称之类的文本时,始终指定Locale
  • 在另一种方法中,将代码简化到绝对最低限度,以确保没有副作用。
  • 通过调用System.getProperties()转储有关JVM环境的信息。

代码:

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,使用带有HotSpot的AdoptOpenJDK的Java 12.0.1 + 12。
  • 从Microsoft JDK和HotSpot运行java.version = 1.8.0_112的
  • IdeOne.com。参见此code run live
  • 来自AdoptOpenJDK.net的带有OpenJDK 11.0.3 + 7的Ubuntu 18.04.1 LTS(在Mac上的Parallels虚拟机中运行)。
  • 来自the Oracle site的带有Oracle JDK 11.0.3 + 12的Ubuntu 18.04.2 LTS。

所有结果都相同。

  

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 = / Library / Java / JavaVirtualMachines / adoptopenjdk-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 = zh-CN,java.specification.vendor = Oracle Corporation ,java.version.date = 2019-04-16,java.home = / Library / Java / JavaVirtualMachines / adoptopenjdk-12.jdk / Contents / Home,file.separator = /,java.vm.compressedOopsMode =基于零的行.separator =   ,java.vm.specification.vendor = Oracle公司,java.specification.name = Java平台API规范,java.awt.graphicsenv = sun.awt.CGraphicsEnvironment,sun.management.compiler = HotSpot 64位分层编译器,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位服务器VM,java.vendor.version = AdoptOpenJDK,java.vendor.url。 bug = {https://github.com/AdoptOpenJDK/openjdk-build/issues,java.io.tmpdir = / var / folders / 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 / Library / Java / Extensions:/ Library / Java / Extensions:/ Network / Library / Java / Extensions:/系统/库/ Java /扩展:/ usr / lib / java:。,java.vm.info =混合模式,共享,java.vendor = AdoptOpenJDK,java.vm.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 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位服务器VM,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 / endorsed,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 = Java平台API规范,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。 path = tested.zip,user.name = ?、 java.vm.specification.version = 1.8,sun.java.command = tested.zip,java.home = / opt / jdk / jre,sun.arch.data.model = 64,user.language = zh-CN,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 =小,sun.cpu.isalist =}

答案 1 :(得分:3)

我一直在寻找DateTimeFormatterBuilder的源代码,但我不确定,但是在我看来,您的NullPointerException的可能原因是在其中使用了空时区缩写一些语言环境数据。这可能会导致DateTimeFormatterBuilder.ZoneTextPrinterParser.getTree()DateTimeFormatterBuilder.PrefixTree.add()传递一个null,这反过来就不会期望null。如果是这样,则不同的行为可能是由不同的时区和不同的区域组合造成的。请注意,时区和语言环境是独立的。

编辑:提问者报告说,我的建议无法解决此特定问题。之所以如此,是因为我认为指定用于解析时区缩写的首选时区的可能性可能会对其他几个方面有所帮助。

我没有复制您的异常,因此无法给出确定的解决方法,但是我建议您尝试:

    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 :(得分:2)

我以前遇到过同样的问题,对我有用的是将.toFormatter()更改为.toFormatter(Locale.US)。我不确定是什么原因导致了此问题,这一定与机器的时区有关。看看这是否适合您。

答案 3 :(得分:2)

这终于是一个已知的问题,已在Fedora中解决,尚未在Redhat中解决:

https://bugzilla.redhat.com/show_bug.cgi?id=1837376 https://bugzilla.redhat.com/show_bug.cgi?id=1838229

问题出在/usr/share/javazi-1.8/tzdb.dat。

答案 4 :(得分:1)

在CentOS上,仅发行版中打包的jvm 11和14失败。 它们被标识为:

// doc.CreateOn is a DateTime 
Timestamp.FromDateTime(DateTime.SpecifyKind(doc.CreatedOn, DateTimeKind.Utc));

或:

openjdk version "11.0.7" 2020-04-14 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.7+10-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.7+10-LTS, mixed mode, sharing)

从AdoptOpenJDK下载,一切正常:

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment 20.3 (build 14.0.1+7)
OpenJDK 64-Bit Server VM 20.3 (build 14.0.1+7, mixed mode, sharing)

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.1+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.1+7, mixed mode, sharing)

在Mac上,我还拥有几乎所有自1.8以来的JVM。他们都很好。

测试的格式为:

openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)

(编辑) 该代码接近所示示例:

private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d HH:mm:ss zzz", Locale.ENGLISH);

还有带有JVM 14的堆栈:

import java.time.*;
import java.time.format.*;
import java.util.Locale;

public class DateTest {
    private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d HH:mm:ss zzz", Locale.ENGLISH);

    public static void main(String[] args) {
        System.out.println(dtf.parse("Jul 15 11:20:01 CEST"));
    }
}