【问题标题】:Convert a string to GregorianCalendar将字符串转换为 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 /泰国!

标签: java calendar timezone


【解决方案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.timemodern 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 desugaringHow to use ThreeTenABP in Android Project

    【讨论】:

    • 这个问题的现代答案早就应该了。感谢您提供!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-10
    • 2019-01-05
    • 2015-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多