将字符串转换为 GregorianCalendar

Posted

技术标签:

【中文标题】将字符串转换为 GregorianCalendar【英文标题】:Convert a string to GregorianCalendar 【发布时间】:2010-09-19 10:10:09 【问题描述】:

我有一个来自电子邮件标题的字符串,例如 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

【问题讨论】:

次要:您应该使用 Calendar.getInstance() 而不是直接实例化 GregorianCalendar。这仍然很灵活,因此当您的应用在印度(例如)运行时,您不必更改所有代码。 @Daniel:不一定。这取决于在印度运行的应用程序是否与印度人、ISO 日期格式、其他未本地化的流程或您有什么交互。 虽然我同意您应该使用 Calendar.getInstance(并且您应该使用通用类型 Calendar,而不是 GregorianCalendar)... getInstance() 仅在您的语言/国家是泰语时返回非 GregorianCalendar /泰国! 【参考方案1】:

如果可以的话,我建议您查看 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();

我希望这会有所帮助。

【讨论】:

如果你正在做任何远程复杂的日期和时间操作,听起来你就是这样,我也强烈推荐 Joda Time 库。它是我见过的设计和实现最好的库之一,它使日期/时间处理尽可能简单(但并不简单)。 嘿杰克,这是一个很好的答案!它只有一个错误——这是正确的行。更新,我会接受的。 DateTimeFormat.forPattern("你的模式").withOffsetParsed();【参考方案2】:

对于最快的——这将无法正常工作...... 因为它将时区标准化为 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);

输出:

解析日期:2008 年 10 月 27 日星期一 11:33:29 EDT

这在技术上是正确的,因为我的系统时区是 EDT / UTC 减去四个小时(比你的时间早三个小时)。如果您将时间表示为自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数(Date 对象如何存储它的日期/时间),那么这些日期/时间是相等的,它只是 TimeZone不一样。

您的问题确实是如何将日期/日历转换为我的时区?为此,请查看我对上一个问题How to handle calendar TimeZones using Java?的回复

【讨论】:

【参考方案3】:

java.time

解决方案使用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

GregorianCalendar 上调用getTime() 会转换为没有时区的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。

【讨论】:

这个问题的现代答案早就应该了。感谢您提供!

以上是关于将字符串转换为 GregorianCalendar的主要内容,如果未能解决你的问题,请参考以下文章

java 将Date转换为GregorianCalendar以传递给cxf客户端/服务器

如何将公历字符串转换为公历?

如何格式化 GregorianCalendar

将 NSDateComponents 与整数进行比较(或将 NSDateComponents 转换为整数)

Android - GregorianCalendar 显示错误的月份

日历 System.Globalization.GregorianCalendar 不支持字符串