从CST到GMT的日期格式转换不起作用



我在CST(24小时(中有一个日期字符串,我想将其转换为GMT(12小时(。我有下面的Java方法,当我的系统时间是加尔各答时间时,它可以正常工作。(我运行Java方法的系统(但是当我的系统在上海时间时,GMT时间不正确。

String inputDate = "01-19-2017 06:01 CST";
SimpleDateFormat inputFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm Z");
parsedInput = inputFormatter.parse(inputDate);
// parsedInput -> Tue Jan 19 06:01:00 CST 2017   -> When system time is Shanghai time
// parsedInput -> Thu Jan 19 17:31:00 IST 2017   -> When system time is Kolkata time

SimpleDateFormat formatter = new SimpleDateFormat("MM-dd-yyyy hh:mm a Z");
TimeZone gmt = TimeZone.getTimeZone("GMT");
formatter.setTimeZone(gmt);
String formattedDate = formatter.format(parsedInput);
// formattedDate -> 01-18-2017 10:01 PM +0000   -> When system time is Shanghai time (Incorrect)
// formattedDate -> 01-19-2017 12:01 PM +0000   -> When system time is Kolkata time

避免伪时区

3-4字母时区缩写(例如CST(是不是实际时区。他们不是标准化。他们甚至都不是唯一的!

您的CST可能是"中国标准时间",或者可能是美洲的"中央标准时间",或者可能是其他的。无法知道哪一个。

另一个示例:IST可能是指"印度标准时间"或"爱尔兰标准时间"或其他人。

解密这些伪区是不可能的。Joda Time图书馆有明智的政策,即拒绝尝试。不幸的是,Java.Time课程在解析时会猜测,但结果可能不是您期望的区域。

因此,永远不要使用这些无用的伪区。在continent/region的格式中使用适当的时区名称,例如America/ChicagoAsia/KolkataPacific/Auckland

避免旧日期时间类

您正在使用遗产的麻烦的旧日期类别,该课程由Java.Time类取代。

解决方案

如果您知道所有输入均针对同一时区域,则将伪区域掉落并作为LocalDateTime处理,将预期区域应用于ZoneId,以产生ZonedDateDate。从中您可以在UTC时间提取Instant

String input = "01-19-2017 06:01".replace( " " , "T" ) ;  // Insert a “T” to comply with standard ISO 8601 format used by default in java.time.
LocalDateTime ldt = LocalDateTime.parse( input );  // Lacks any concept of time zone or offset-from-UTC. So *not* an actual moment on the timeline.
ZoneId z = ZoneId.of( "America/Chicago" ); // Assuming “CST” meant this zone in North America.
ZonedDateTime zdt = ldt.atZone( z );  // Assign a time zone to determine an actual moment on the timeline. 
Instant instant = zdt.toInstant();  // Extract a value in UTC.

您可能会选择通过印度的墙壁锁定时间看到同一时刻。

ZonedDateTime zdtKolkata = zdt.withZoneSameInstant( ZoneId.of( "Asia/Kolkata" ) ) ;

永远不要依赖默认区域

可以随时通过在该JVM内执行的任何应用程序中的任何代码更改JVM的当前默认时区。由于这种情况可以随时改变,因此您不能依靠某个值。

当您省略时区的可选参数时,日期时间类默默地默默地应用当前默认时区。因此,解决方案很简单:始终指定预期/所需的时区

请注意,上面的代码示例如何在每个机会中指定区域。

(顺便说一句, Locale的同上。明确指定而不是依赖当前默认值。(

您的问题是CST的歧义。在大多数情况下,SimpleDateFormat将CST视为您预期的中心标准时间。但是,当您的计算机运行上海时间时,这将成为格式化日历的时区,然后突然将CST理解为中国标准时间,与上海时间相同。

因此,Darshan Mehta的解决方案将inputFormatter的时区设置为中国标准时间以外的其他方案。我不知道为什么它不起作用(我将其设置为TimeZone.getTimeZone("America/Chicago")以匹配CST的预期解释(。

不过,正确且良好的解决方案是完全避免三个字母时区缩写。您的只是许多造成麻烦的例子。如果可以

    String inputDate = "01-19-2017 06:01 -0600";

现在,无论计算机的时区设置如何,您的代码都可以正常工作。图案字符串中的Z您已经具有匹配的-0600很好。

所有这些都说,如果您可以使用Java 8日期和时间课,您可以帮自己切换到它们。我犹豫称它们为" Java 8日期和时间班",因为它们也已被退回到Java 6和7,因此,如果您可以与图书馆的依赖生活在一起,直到您到达Java 8,则应该有机会。较新的课程更加友好地友好,可以方便地使用。一个简单的示例可以让您开始:

    String inputDate = "01-19-2017 06:01 -0600";
    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm Z");
    ZonedDateTime parsedInput = ZonedDateTime.parse(inputDate, inputFormatter);
    OffsetDateTime gmtTime = parsedInput.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-yyyy hh:mm a Z");
    String formattedDate = gmtTime.format(formatter);
    System.out.println(formattedDate); // prints 01-19-2017 12:01 PM +0000

尝试将TimeZone设置为inputFormatter,例如:

SimpleDateFormat inputFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm Z");
inputFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));

如果未指定时区,则将默认值计入帐户,即Asia/Shanghai,因此,结果不正确。

您可以通过在上述Snippett中用Asia/Shanghai替换GMT在当前系统中复制它。

相关内容

  • 没有找到相关文章

最新更新