Java GregorianCalendar 更改时区

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12137428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:44:31  来源:igfitidea点击:

Java GregorianCalendar change TimeZone

javadatetimezone

提问by Alexander Allakhverdiyev

I'm trying to set HOUR_OF_DAY field and change Timezone of the GregorianCalendar date object.

我正在尝试设置 HOUR_OF_DAY 字段并更改 GregorianCalendar 日期对象的时区。

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
//date.get(Calendar.HOUR_OF_DAY);
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));

Output:

输出:

HOUR: 16
HOUR: 23

For some reason value of HOUR_OF_DAY does not change after setting different timezone. But if I uncomment date.get for HOUR_OF_DAY, everything works exactly as it should

由于某种原因,HOUR_OF_DAY 的值在设置不同的时区后不会改变。但是如果我在 HOUR_OF_DAY 取消注释 date.get,则一切都完全正常

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
date.get(Calendar.HOUR_OF_DAY); // uncommenting this line will is changing the output
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));

Output:

输出:

HOUR: 16
HOUR: 13

How is this possible? Why .get method is changing object behaviour?

这怎么可能?为什么 .get 方法正在改变对象行为?

回答by Bill the Lizard

The GregorianCalendarclass inherits its getmethod from Calendar, which has the following side effect:

GregorianCalendar类继承其get从方法Calendar,其具有以下副作用:

In lenient mode, all calendar fields are normalized.

在宽松模式下,所有日历字段都被标准化。

This means that the timevalue and all fields are recomputed when getis called on a Calendarobject. This can lead to some unpredictable behavior, particularly when coupled with setTimeZone, which has some documented buggy behaviorof its own.

这意味着在对象上调用time时会重新计算值和所有字段。这可能会导致一些不可预测的行为,特别是当与 结合使用时,它本身有一些记录在案的错误行为getCalendarsetTimeZone

回答by Basil Bourque

tl;dr

tl;博士

OffsetDateTime.now( ZoneOffset.ofHours( 10 )  ).withHour( 23 )

Avoid legacy date-time classes

避免遗留的日期时间类

The legacy date-time classes including GregorianCalendarare a confusing. awkward, poorly-design mess. Avoid them. Now supplanted by the java.timeclasses. Specifically, GregorianCalendaris replaced by ZonedDateTime.

遗留的日期时间类包括GregorianCalendar令人困惑。尴尬,设计糟糕的一团糟。避开它们。现在被java.time类取代。具体来说,GregorianCalendar由 代替ZonedDateTime

Offset-from-UTC

UTC 偏移量

You apparently want a moment with an offset-from-UTCof ten hours ahead of UTC. Define your desired offset.

您显然想要比UTC早十小时的UTC偏移量。定义所需的偏移量。

ZoneOffset offset = ZoneOffset.ofHours( 10 ) ;

offset.toString(): +10:00

offset.toString(): +10:00

Get the current moment as an OffsetDateTimewith that offset.

获取OffsetDateTime具有该偏移量的当前时刻。

OffsetDateTime odt = OffsetDateTime.now( offset ) ;

odt.toString(): 2018-02-15T16:44:44.216642+10:00

odt.toString(): 2018-02-15T16:44:44.216642+10:00

You want to override the hour to be 23.

您想将小时覆盖为23

OffsetDateTime odt23 = odt.withHour( 23 ) ;

odt23.toString(): 2018-02-15T23:44:44.216642+10:00

odt23.toString(): 2018-02-15T23:44:44.216642+10:00

Time zone

时区

I'm trying to set HOUR_OF_DAY field and change Timezone of the GregorianCalendar date object.

我正在尝试设置 HOUR_OF_DAY 字段并更改 GregorianCalendar 日期对象的时区。

Nope, you are changing the offset-from-UTC, not the time zone.

不,您正在更改offset-from-UTC,而不是time zone

Always better to use a time zone rather than a mere offset, if you know for certainthe intended zone. A time zone is a history of past, present, and future changes to the offset used by the people of a certain region. With a time zone you can always determine the offset, but not vice-versa.

如果您知道特定的预期区域,那么使用时区而不是单纯的偏移总是更好。时区是某个地区的人们使用的偏移量的过去、现在和未来变化的历史。使用时区,您始终可以确定偏移量,但反之则不然。

Specify a proper time zone namein the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as ESTor ISTas they are nottrue time zones, not standardized, and not even unique(!).

以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;  

Capture the current moment in a wall-clock time seen by the people of that zone.

在该区域的人们看到的挂钟时间中捕捉当前时刻。

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

Override the hour-of-day.

覆盖一天中的小时。

ZonedDateTime zdt23 = zdt.withHour( 23 ) ;


About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

Using a JDBC drivercompliant with JDBC 4.2or later, you may exchange java.timeobjects directly with your database. No need for strings nor java.sql.* classes.

使用符合JDBC 4.2或更高版本的JDBC 驱动程序,您可以直接与您的数据库交换java.time对象。不需要字符串或 java.sql.* 类。

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多