47

我想在运行时更改 Java 日历实例中的 TIMEZONE 值。我在下面试过。但是两种情况下的输出是相同的:

    Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    System.out.println(cSchedStartCal.getTime().getTime());
    cSchedStartCal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
    System.out.println(cSchedStartCal.getTime().getTime());

输出:
1353402486773
1353402486773

我也试过这个,但输出仍然是一样的:

    Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    System.out.println(cSchedStartCal.getTime());

    Calendar cSchedStartCal1 = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
    cSchedStartCal1.setTime(cSchedStartCal.getTime());
    System.out.println(cSchedStartCal.getTime());

在 API 中,我看到了以下评论,但我无法理解其中的大部分内容:

     * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
     * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
     * generally, a call to setTimeZone() affects calls to set() BEFORE AND
     * AFTER it up to the next call to complete().

请你帮助我好吗?

一种可能的解决方案:

    Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    long gmtTime = cSchedStartCal.getTime().getTime();

    long timezoneAlteredTime = gmtTime + TimeZone.getTimeZone("Asia/Calcutta").getRawOffset();
    Calendar cSchedStartCal1 = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
    cSchedStartCal1.setTimeInMillis(timezoneAlteredTime);

这个解决方案好吗?

4

2 回答 2

59

在 Java 中,日期在内部以自纪元以​​来的 UTC 毫秒表示(因此不考虑时区,这就是为什么你得到相同的结果,因为getTime()给你提到的毫秒)。
在您的解决方案中:

Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
long gmtTime = cSchedStartCal.getTime().getTime();

long timezoneAlteredTime = gmtTime + TimeZone.getTimeZone("Asia/Calcutta").getRawOffset();
Calendar cSchedStartCal1 = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
cSchedStartCal1.setTimeInMillis(timezoneAlteredTime);

您只需将 GMT 的偏移量添加到指定的时区(在您的示例中为“亚洲/加尔各答”),以毫秒为单位,所以这应该可以正常工作。

另一种可能的解决方案是利用Calendar类的静态字段:

//instantiates a calendar using the current time in the specified timezone
Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
//change the timezone
cSchedStartCal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
//get the current hour of the day in the new timezone
cSchedStartCal.get(Calendar.HOUR_OF_DAY);

有关更深入的说明,请参阅stackoverflow.com/questions/7695859/ 。

于 2012-11-20T11:25:54.613 回答
16
  1. 该类Date/Timestamp表示自 1970 年 1 月 1 日 00:00:00 GMT 以来的特定时刻,精度为毫秒。因此,无论时区如何,这个时间差(从纪元到当前时间)在全世界所有计算机中都是相同的。

  2. Date/Timestamp不知道给定时间在哪个时区。

  3. 如果我们想要基于时区的时间,我们应该使用 java 中的 Calendar 或 SimpleDateFormat 类。

  4. 如果您尝试使用 打印 Date/Timestamp 对象toString(),它将使用您机器的默认时区转换和打印时间。

  5. 所以我们可以说 (Date/Timestamp).getTime() 对象将始终具有 UTC(以毫秒为单位的时间)

  6. 总结 Date.getTime()将给出 UTC 时间,但toString()在区域设置特定时区,而不是 UTC。

现在我将如何在指定时区创建/更改时间?

下面的代码为您提供了具有指定时区的日期(以毫秒为单位的时间)。这里唯一的问题是你必须以字符串格式给出日期。

   DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
   dateFormatLocal.setTimeZone(timeZone);
   java.util.Date parsedDate = dateFormatLocal.parse(date);

用于dateFormat.format将输入日期(始终为 UTC)、时区和返回日期作为字符串。

如何在数据库中存储 UTC/GMT 时间:

如果您打印parsedDate对象,时间将采用默认时区。但是您可以将 UTC 时间存储在 DB 中,如下所示。

        Calendar calGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        Timestamp tsSchedStartTime = new Timestamp (parsedDate.getTime());
        if (tsSchedStartTime != null) {
            stmt.setTimestamp(11, tsSchedStartTime, calGMT );
        } else {
            stmt.setNull(11, java.sql.Types.DATE);
        }
于 2012-12-22T11:20:40.830 回答