2017-04-20 26 views
1

我在CST(24小时)中有一个日期字符串,我想将它转换为GMT(12小时)。 我有一个像下面的java方法,当我的系统时间是加尔各答时间时工作正常。 (我运行java方法的系统) 但是,当我的系统在上海时,GMT时间不正确。从CST到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 
+0

*“周二1月19日6时01分00秒CST 2016 - >当系统时间为上海时间” * < - 那是只是一个错字或它真的改变年份到2016年? –

+1

这里“24小时”是什么意思?请注意,您在输入和输出中都使用'hh'(12小时制)... –

+4

另请注意,许多时区缩写都非常模糊。 *您希望CST在这种情况下表示什么? –

回答

4

避免伪时区

的3-4个字母时区缩写如CST实际时间重现它在你当前的系统区域。他们不是标准化的。他们甚至不是独一无二的!

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

另一个例子:IST可能意味着“印度标准时间”或“爱尔兰标准时间”或其他。

可靠地解密这些伪区域是不可能的。乔达时间图书馆有一个拒绝甚至尝试的明智政策。不幸的是,java.time类在解析时会做出猜测,但结果可能不是您期望的区域。

所以千万不要使用这些无用的伪区域。使用格式为continent/regionproper time zone name,如America/Chicago,Asia/Kolkata,Pacific/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,顺便说一句。通过显式指定,而不是依赖于当前的默认。)

0

尝试设置TimeZoneinputFormatter为好,如:

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

如果不指定时区,它采用默认值考虑进去,这是你的情况Asia/Shanghai,因此,结果不正确。

您可以在上面snippett与Asia/Shanghai更换GMT

+0

解析前设置inputFormatter的时区不会影响任何内容..它仍然是相同的。 –

2

你的问题是CST的模糊性。在大多数情况下,SimpleDateFormat将CST理解为您预期的中央标准时间。但是,当您的电脑运行上海时间时,这将成为格式化程序日历的时区,然后突然将CST理解为中国标准时间,与上海时间相同。

因此Darshan Mehta’s solution,将inputFormatter的时区设置为中国标准时间以外的其他时间,在我的电脑上运行。我不知道为什么它不适合你(我把它设置为TimeZone.getTimeZone("America/Chicago")以符合CST的预期解释)。

但是,正确和优秀的解决方案是完全避免三个和四个字母的时区缩写。你们只是造成问题的一个例子。如果可以,给你的输入字符串以明确区UTC的偏移量,这样是绝不含糊:

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