在Java中将UTC时间转换为本地时区

时间:2010-06-09 21:20:13

标签: java datetime date calendar timezone

我知道这个话题已被打死,但在搜索了几个小时后我不得不问这个问题。

我的问题:根据客户端应用程序(iphone)的当前时区对服务器上的日期进行计算。客户端应用程序会在几秒钟内告诉服务器它的时区离GMT有多远。我想使用此信息对服务器中的日期进行计算。服务器上的日期都存储为UTC时间。 所以我希望在将UTC Date对象转换为此本地时区后获得它的HOUR。

我目前的尝试:

int hours = (int) Math.floor(secondsFromGMT / (60.0 * 60.0));
int mins = (int) Math.floor((secondsFromGMT - (hours * 60.0 * 60.0)) / 60.0);
String sign = hours > 0 ? "+" : "-";

Calendar now = Calendar.getInstance();
TimeZone t = TimeZone.getTimeZone("GMT" + sign + hours + ":" + mins);
now.setTimeZone(t);

now.setTime(someDateTimeObject);

int hourOfDay = now.get(Calendar.HOUR_OF_DAY);

变量小时和分钟表示当地时区远离GMT的小时和分钟。调试此代码后 - 变量小时,分钟和符号都是正确的。

问题是hourOfDay没有返回正确的小时 - 它返回UTC时间而不是当地时间的小时。想法?

2 个答案:

答案 0 :(得分:3)

您的时区字符串配置错误。试试这个,

String sign = secondsFromGMT > 0 ? "+" : "-";
secondsFromGMT = Math.abs(secondsFromGMT);      
int hours = secondsFromGMT/3600;
int mins = (secondsFromGMT%3600)/60;
String zone = String.format("GMT%s%02d:%02d", sign, hours, mins);          
TimeZone t = TimeZone.getTimeZone(zone);

答案 1 :(得分:0)

TL;博士

  

获取UTC Date对象转换为此本地时区后的HOUR

区域(首选)

ZonedDateTime.now(
    ZoneId.of( "Africa/Tunis" )  // Use a zone rather than a mere offset-from-UTC whenever possible.
).getHour()
  

23

<强>偏移

OffsetDateTime.now(
    ZoneOffset.ofTotalSeconds( secondsFromGMT )  // Use a mere offset-from-UTC only when the appropriate zone is unavailable AND you have been assured this particular offset is correct for your input data.
).getHour()
  

23

避免遗留日期时间类

你正在使用现在遗留下来的麻烦的旧日期时间类,取而代之的是现代业界领先的java.time类。

java.time

以UTC Instant获取当前UTC时刻。 Instant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

Instant instant = Instant.now() ;

调整到特定时区。

Specify a [proper time zone name](https://en.wikipedia.org/wiki/List_of_tz_zones_by_name) in the format of `continent/region`, such as [`America/Montreal`](https://en.wikipedia.org/wiki/America/Montreal), [`Africa/Casablanca`](https://en.wikipedia.org/wiki/Africa/Casablanca), or `Pacific/Auckland`. Never use the 3-4 letter abbreviation such as `EST` or `IST` as they are *not* true time zones, not standardized, and not even unique(!). 

ZoneId z = ZoneId.of( "America/Montreal" );

如果在运行时您想要JVM的当前默认时区,请询问它。请记住,这可以随时改变 。因此,如果关键,您应该向用户询问或确认。

ZoneId z = ZoneId.systemDefault() ;

应用时区以生成ZonedDateTime对象。

ZonedDateTime zdt = instant.atZone( z ) ;

你说你只想从这个划定日期的时间开始。询问特定方法。

int hourOfDay = zdt.getHour() ;

顺便说一句,您可能会发现LocalTime类很有用。

LocalTime lt = zdt.toLocalTime() ;

偏移与区域

  

变量小时和分钟表示当地时区远离GMT的小时和分钟

不,不是时区。 您已将带有偏移的区域合并。理解这种区别非常重要。

  • 偏移
    offset-from-UTC是UTC(GMT)之前/之后小时数,分钟数和秒数。没有更多,没有更少。
  • 区域
    {A time zone是特定区域人民使用的各种偏移的历史记录。区域表示偏移量随时间变化的所有变化,过去,现在和接近未来。世界各地的政治家都表现出了经常改变他们时区偏移的倾向。

特殊偏移可能在多个地方巧合使用。例如,有时候都柏林,伦敦,卡萨布兰卡,拉各斯和布拉柴维尔都会在UTC前一小时共享相同的+01:00偏移量。但在其他时候,他们可能不会,例如在今年冬天,当拉各斯比UTC早一个小时,而其他三个在UTC之前切换到零时(即UTC本身)。

使用区域和片刻,您可以确定偏移量。但不是朝另一个方向走;如果只有偏移,则无法可靠地确定区域。

所以你的小时和分钟数只是一个补偿。对于输入的特定日期,您的区域的偏移量可能不正确。所以总是喜欢时区而不仅仅是偏移。

OffsetDateTime

如果您因某种原因而被卡住了,您确定对于您的指定输入是正确的,但您不知道时区,请使用ZoneOffset&amp; OffsetDateTime而不是ZoneId&amp; ZonedDateTime。但是,如果可能的话,使用区域而不是偏移,如上所述。

ZoneOffset offset = ZoneOffset.ofTotalSeconds( secondsFromGMT ) ;
OffsetDateTime odt = OffsetDateTime.now( offset ) ;

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore