从CST到GMT的日期格式转换不起作用
我在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
避免伪时区
的3-4个字母时区缩写如CST
是不实际时间重现它在你当前的系统区域。他们不是标准化的。他们甚至不是独一无二的!
您的CST
可能是“中国标准时间”,或者可能是美洲的“中央标准时间”,或可能是其他内容。有无法知道哪一个。
另一个例子:IST
可能意味着“印度标准时间”或“爱尔兰标准时间”或其他。
可靠地解密这些伪区域是不可能的。乔达时间图书馆有一个拒绝甚至尝试的明智政策。不幸的是,java.time类在解析时会做出猜测,但结果可能不是您期望的区域。
所以千万不要使用这些无用的伪区域。使用格式为continent/region
的proper 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
,顺便说一句。通过显式指定,而不是依赖于当前的默认。)
尝试设置TimeZone
到inputFormatter
为好,如:
SimpleDateFormat inputFormatter = new SimpleDateFormat("MM-dd-yyyy hh:mm Z");
inputFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
如果不指定时区,它采用默认值考虑进去,这是你的情况Asia/Shanghai
,因此,结果不正确。
您可以在上面snippett与Asia/Shanghai
更换GMT
解析前设置inputFormatter的时区不会影响任何内容..它仍然是相同的。 –
你的问题是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
*“周二1月19日6时01分00秒CST 2016 - >当系统时间为上海时间” *
这里“24小时”是什么意思?请注意,您在输入和输出中都使用'hh'(12小时制)... –
另请注意,许多时区缩写都非常模糊。 *您希望CST在这种情况下表示什么? –