我有String格式的日期我需要解析。格式如下,来自世界各地的时区:
String stringDate = "2016-04-29 12:16:49.222+04:30";
String pattern = "yyyy-MM-dd HH:mm:ss.SSSZ";
似乎java.util.Date
不接受:
分隔符的时区。所以我尝试使用 Jodatime库:
DateTime formattedDate = DateTimeFormat.forPattern(pattern).parseDateTime(stringDate);
LocalDateTime formattedDate2 = DateTimeFormat.forPattern(pattern).parseLocalDateTime(stringDate);
MutableDateTime formattedDate3 = DateTimeFormat.forPattern(pattern).parseMutableDateTime(stringDate);
System.out.println(formattedDate);
System.out.println(formattedDate2);
System.out.println(formattedDate3);
这些行输出:
2016-04-29T09:46:49.222+02:00
2016-04-29T12:16:49.222
2016-04-29T09:46:49.222+02:00
据我所知,格式化程序修改输出时区以符合我的要求(我在巴黎的时间,UTC + 2),但我希望输出保持其原始时区。是否可以使用Jodatime库?或者我应该换另一个?
修改:
实际上我需要得到一个Date
对象,时区偏移量为270(stringDate
的时区偏移量:4小时30分钟)代替120(我的本地时区偏移量):< / p>
System.out.println(formattedDate.toDate().getTimezoneOffset()); // I expect 270 but I get 120
答案 0 :(得分:2)
您错过的是DateTimeFormatter#withOffsetParsed
:
返回一个新的格式化程序,它将创建一个日期时间,其时区等于已解析字符串的偏移量。
否则格式化程序会将其解析为您当地的时区(令人惊讶,我知道)。
@Test
public void preserveTimeZone() {
String stringDate = "2016-04-29 12:16:49.222+04:30";
String pattern = "yyyy-MM-dd HH:mm:ss.SSSZ";
DateTime dt = DateTimeFormat.forPattern(pattern).withOffsetParsed().parseDateTime(stringDate);
System.out.println(dt); // prints "2016-04-29T12:16:49.222+04:30"
}
至于您的修改 - java.util.Date
不包含时区信息和仅限弃用的getTimezoneOffset()
方法
返回相对于UTC的本地时区的偏移量(以分钟为单位),该偏移量适合此
Date
个对象所代表的时间。
因此,您最好使用Joda Time或java.time
类来正确处理时区。
答案 1 :(得分:0)
当我运行您发布的相同代码时,我最终会使用
2016-04-29T02:46:49.222-05:00
2016-04-29T12:16:49.222
2016-04-29T02:46:49.222-05:00
如果您注意到,则具有不同的小时值和时区值。但是,如果你看看他们的毫秒:
System.out.println(formattedDate.getMillis());
System.out.println(formattedDate2.toDateTime().getMillis());
System.out.println(formattedDate3.getMillis());
您将看到输出
1461916009222
1461950209222
1461916009222
所以他们有相同的纪元时间,但印刷方式不同。这是由于DateTime对象上toString()
的机制,以及它们的解释方式。
DateTime和LocalDateTime(MutableDateTime只是DateTime的可变版本)以不同的方式处理相同的纪元时间。 LocalDateTime 总是假设纪元时间是UTC时间(按javadoc for LocalDateTime),而DateTime将假设纪元在它所拥有的年代表的时区中表示(按{{ 3}})。如果在构造时未指定TimeZone,则Chronology将假定您需要默认Locale 的时区,该时区由JVM设置。在您的情况下,默认的Locale是Paris France,而我的是St. Louis USA。巴黎目前的时区偏移+2:00,而圣路易斯的时区偏差为-5:00,当我们打印它时会导致不同的时区表示。
为了让人更烦恼,这些偏移会随着时间的推移而改变。如果我在6个月后回来并尝试再次回答这个问题,我的价值将显示为-6:00(愚蠢的夏令时!)
要记住的重要一点是,这两个日期具有相同的纪元时间:我们正在谈论同一时刻,我们只是在打印出时以不同的方式表示时间。 / p>
如果要使用其他时区来表示解析结果的输出,则可以使用DateTimeFormat.withZone()
或DateTimeFormat.withLocale
格式化期间设置DateTimeZone:< / p>
DateTimeFormatter sdf = DateTimeFormat.forPattern(pattern).withZone(DateTimeZone.forOffsetHoursMinutes(4,30));
System.out.println(formattedDate.getMillis());
System.out.println(formattedDate2.toDateTime().getMillis());
System.out.println(formattedDate3.getMillis());
将打印
2016-04-29 12:16:49.222+0430
2016-04-29 12:16:49.222
2016-04-29 12:16:49.222+0430
请注意,LocalDateTime版本仍会在没有TimeZone的情况下打印出来。这是LocalDateTime的一种功能:无需处理所有这些业务就可以代表它。
这就是为什么你的印刷价值看起来很奇怪的原因。要进一步解决从解析的DateTime对象中获取java.util.Date
对象的问题:toDate
将为您提供代表相同纪元时间的java.util.Date
。但是,java.util.Date
的行为与DateTime
类似,除非另有说明,否则它将使用默认语言环境的TimeZone。如果您提前了解区域设置,则可以使用toDate(Locale)
方法确保使用该区域设置的TimeZone偏移量。
如果你没有提前知道TimeZone,那就太难了;在过去,我必须手工解析TimeZone小时和分钟偏移量,以确定要使用的TimeZone。在这个完全的情况下,这并不太难,因为最后6个字符格式非常合理且规则(当然,除非它们不是:))。