我有一个来自电子邮件标题的字符串,例如Date: Mon, 27 Oct 2008 08:33:29 -0700
。我需要的是GregorianCalendar的一个实例,它将代表同一时刻。就这么简单 - 我该怎么做?
对于最快的 - 无法正常工作:
SimpleDateFormat format = ... // whatever you want
Date date = format.parse(myString)
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date)
因为它会将时区标准化为UTC(或您的本地计算机时间,具体取决于Java版本)。我需要的是calendar.getTimeZone()。getRawOffset()来返回-7 * milisInAnHour
。
答案 0 :(得分:15)
我建议您查看Joda Time库,如果这是一个选项。当核心平台提供类似功能时,我通常反对使用第三方库,但我之所以这样做是因为Joda Time的作者也落后于JSR310,而Joda Time基本上将最终归入Java 7。
http://joda-time.sourceforge.net/
所以无论如何,如果Joda Time是一个选项,像这样的应该工作:
DateTimeFormatter formatter =
DateTimeFormat.forPattern("your pattern").withOffsetParsed();
DateTime dateTime = formatter.parseDateTime("your input");
GregorianCalendar cal = dateTime.toGregorianCalendar();
我希望这会有所帮助。
答案 1 :(得分:6)
对于最快的 - 这不能正常工作...... 因为它会将时区标准化为UTC(或您的本地计算机时间,具体取决于Java版本)。我需要的是calendar.getTimeZone()。getRawOffset()返回-7 * milisInAnHour。
从技术上讲,这确实有效,因为虽然它会返回TimeZone等于当前系统TimeZone的对象,但会修改时间以说明偏移量。
此代码:
String dateString = "Mon, 27 Oct 2008 08:33:29 -0700";
DateFormat df = new SimpleDateFormat("E, dd MMM yyyy hh:mm:ss Z");
Date parsed = df.parse(dateString);
System.out.println("parsed date: " + parsed);
Calendar newCalendar = Calendar.getInstance();
newCalendar.setTime(parsed);
输出:
解析日期:星期一10月27日晚上11:33:29美国东部时间2008
技术上是正确的,因为我的系统时区是EDT / UTC减去四小时(比你的提前三小时)。如果你把时间表示为自1970年1月1日00:00:00 GMT以来的毫秒数(这是Date
对象存储它的日期/时间的方式),那么这些日期/时间是相等的,它只是TimeZone与众不同。
您的问题确实是如何将日期/日历转换为我的时区?为此,请查看我对上一个问题的回复How to handle calendar TimeZones using Java?
答案 2 :(得分:3)
使用 java.time
、modern date-time API 的解决方案:
现代日期时间 API 提供 OffsetDateTime
来表示具有时区偏移量的日期时间对象。它可以转换为 Instant
,代表时间线上的一个瞬时点。 Instant
独立于任何时区,即它具有 +00:00
小时的时区偏移,在 ISO 8601 标准中指定为 Z
。
Instant#toEpochMilli
将此瞬间转换为自 1970-01-01T00:00:00Z 纪元以来的毫秒数。可以将此值设置为 GregorianCalendar
的对象,然后该对象将代表同一时刻。
演示:
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Mon, 27 Oct 2008 08:33:29 -0700";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime, DateTimeFormatter.RFC_1123_DATE_TIME);
System.out.println(odt);
// In case you want a time zone neutral object, convert to Instant
Instant instant = odt.toInstant();
System.out.println(instant);
// Edit: If the requirement is a GregorianCalendar having the offset from
// the string — typically for an old API not yet upgraded to java.time:
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, DateTimeFormatter.RFC_1123_DATE_TIME);
GregorianCalendar gc = GregorianCalendar.from(zdt);
System.out.println("As Date: " + gc.getTime());
System.out.println("Time zone ID: " + gc.getTimeZone().getID());
System.out.println("Hour of day: " + gc.get(Calendar.HOUR_OF_DAY));
// ...
}
}
输出:
2008-10-27T08:33:29-07:00
2008-10-27T15:33:29Z
As Date: Mon Oct 27 15:33:29 GMT 2008
Time zone ID: GMT-07:00
Hour of day: 8
在 getTime()
上调用 GregorianCalendar
会转换为没有时区的 Date
(另一个旧的且容易出错的类),因此偏移量丢失。打印时区 ID 和一天中的小时表明偏移量和一天中的时间都保留在 GregorianCalendar
中。
从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。