简体   繁体   English

如何更改 java.util.Calendar/Date 的 TIMEZONE

[英]How to change TIMEZONE for a java.util.Calendar/Date

I would like to change the TIMEZONE value in a Java Calendar instance at runtime.我想在运行时更改 Java 日历实例中的 TIMEZONE 值。 I tried below.我在下面试过。 But the output is the same in both instances:但是两种情况下的输出是相同的:

    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());

OUTPUT:输出:
1353402486773 1353402486773
1353402486773 1353402486773

I have tried this also but the output is still the same:我也试过这个,但输出仍然是一样的:

    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());

In the API I am seeing the below comment but I am not able to understand much of it:在 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().

Could you please help me?请你帮助我好吗?

One Possible Solution :一种可能的解决方案:

    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);

Is this solution ok?这个解决方案好吗?

In Java, Dates are internally represented in UTC milliseconds since the epoch (so timezones are not taken into account, that's why you get the same results, as getTime() gives you the mentioned milliseconds).在 Java 中,日期在内部以自纪元以​​来的 UTC 毫秒表示(因此不考虑时区,这就是为什么您会得到相同的结果,因为getTime()会为您提供提到的毫秒数)。
In your solution:在您的解决方案中:

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);

you just add the offset from GMT to the specified timezone ("Asia/Calcutta" in your example) in milliseconds, so this should work fine.您只需将 GMT 的偏移量添加到指定的时区(在您的示例中为“亚洲/加尔各答”),以毫秒为单位,所以这应该可以正常工作。

Another possible solution would be to utilise the static fields of the Calendar class:另一种可能的解决方案是利用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);

Refer to stackoverflow.com/questions/7695859/ for a more in-depth explanation.有关更深入的说明,请参阅stackoverflow.com/questions/7695859/

  1. The class Date/Timestamp represents a specific instant in time, with millisecond precision, since January 1, 1970, 00:00:00 GMT. Date/Timestamp类表示自 1970 年 1 月 1 日 00:00:00 GMT 以来的特定时刻,精度为毫秒。 So this time difference (from epoch to current time) will be same in all computers across the world with irrespective of Timezone.因此,无论时区如何,这个时间差(从纪元到当前时间)在全世界所有计算机中都是相同的。

  2. Date/Timestamp doesn't know about the given time is on which timezone. Date/Timestamp不知道给定时间在哪个时区。

  3. If we want the time based on timezone we should go for the Calendar or SimpleDateFormat classes in java.如果我们想要基于时区的时间,我们应该使用 java 中的 Calendar 或 SimpleDateFormat 类。

  4. If you try to print a Date/Timestamp object using toString() , it will convert and print the time with the default timezone of your machine.如果您尝试使用toString()打印 Date/Timestamp 对象,它将使用您机器的默认时区转换和打印时间。

  5. So we can say (Date/Timestamp).getTime() object will always have UTC (time in milliseconds)所以我们可以说 (Date/Timestamp).getTime() 对象将始终具有 UTC(以毫秒为单位的时间)

  6. To conclude Date.getTime() will give UTC time, but toString() is on locale specific timezone, not UTC.总而言之Date.getTime()将给出 UTC 时间,但toString()位于特定于区域设置的时区,而不是 UTC。

Now how will I create/change time on specified timezone?现在我将如何在指定时区创建/更改时间?

The below code gives you a date (time in milliseconds) with specified timezones.下面的代码为您提供了具有指定时区的日期(以毫秒为单位的时间)。 The only problem here is you have to give date in string format.这里唯一的问题是你必须以字符串格式给出日期。

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

Use dateFormat.format for taking input Date (which is always UTC), timezone and return date as String.使用dateFormat.format将输入日期(始终为 UTC)、时区和返回日期作为字符串。

How to store UTC/GMT time in DB:如何在数据库中存储 UTC/GMT 时间:

If you print the parsedDate object, the time will be in default timezone.如果您打印parsedDate对象,则时间将采用默认时区。 But you can store the UTC time in DB like below.但是您可以将 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);
        }

Even though this is a very old question, it still seems relevant, for example on Android where you never really know what a timestamp means (or rather where it comes from).尽管这是一个非常古老的问题,但它似乎仍然相关,例如在 Android 上,您永远不知道时间戳的含义(或者更确切地说它来自哪里)。 It also seems to me that the other answers didn't understand the question completely (although the accepted answer did, but the code in second half will not work with all timezones).在我看来,其他答案也没有完全理解这个问题(尽管接受的答案确实如此,但后半部分的代码不适用于所有时区)。

The problem is that a timestamp carries no timezone information, so if a device lives in a timezone but is unaware of it, the timestamp it reports for any given moment is different than it would've been if the device was in GMT, or if it knew it isn't and added the offset.问题是时间戳不携带时区信息,因此如果设备处于时区但不知道它,那么它报告的任何给定时刻的时间戳不同于设备处于 GMT 时的时间戳,或者如果它知道它不是并添加了偏移量。 And of course this works the other way too, if we have a timestamp that we know is in GMT, but we want to work with the time in the timezone of the device, we need to take the offset into account as well.当然,这也适用于另一种方式,如果我们知道时间戳是 GMT 格式,但我们想使用设备时区中的时间,我们还需要考虑偏移量。

So yes, the solution provided in the question should work.所以是的,问题中提供的解决方案应该有效。 In my case I do it roughly as follows:就我而言,我大致如下:

TimeZone timeZone = TimeZone.getDefault(); // the local timezone, may as well be TimeZone.getTimeZone("Asia/Calcutta") 
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestampInGmt);
calendar.add(Calendar.MILLISECOND, timeZone.getOffset(timestamp))
long timestampInLocalTimeZone = calendar.getTimeInMillis()

To do it the opposite way, I simply subtract the offset.相反,我只需减去偏移量。 And instantiate timeZone as TimeZone.getTimeZone("GMT");并将timeZone实例化为TimeZone.getTimeZone("GMT");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM