当您只有一个偏移量时(从 GMT)向用户显示当地时间 [英] Displaying local time to a user when all you have is an offset (from GMT)

查看:44
本文介绍了当您只有一个偏移量时(从 GMT)向用户显示当地时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在给定时区 GMT 偏移量的情况下(例如太平洋夏令时间为 -7 小时),向用户显示当地时间非常容易.

但是,如果我想在很长一段时间内(比如 1 年)继续显示正确​​的当地时间怎么办.给定与 GMT 的偏移量,您不知道用户所在的时区.例如给定 -7,用户可能居住在美国或加拿大(或其他一些国家).这些国家/地区在一年中的不同时间点有不同的当地时间(例如,如果美国在 3 月更改为夏令时,而在 4 月更改为加州时间).

我的问题是,上面的段落正确吗?是否有一种标准方法可以采用 GMT 偏移量并很好地猜测用户所在的时区?

解决方案

您的结论是正确的:没有可靠的方法来识别 时区来自offset-from-UTC.

对于您的 -07:00 偏移量示例,我在 当前列表 包括:美国/博伊西美国/奇瓦瓦美国/埃德蒙顿.

时区实际上是偏移量的集合,记录随着时间​​的推移所做的更改,该区域在特定时间段内使用了特定偏移量,但随后又发生了变化另一个特定的时间段.

例如,在 America/Los_Angeles 中,每年的一部分有 -08:00 的偏移量,而一年中的另一部分有 -07:00.因此,该时区每年累积至少两次偏移的历史记录.相比之下,使用时区America/Phoenix 的邻近地区没有累积其偏移量的变化,保留了相同的-07:00抵消了几十年.

所以我们在偏移量和时区之间有一个多对多的关系.偏移量可能出现在一个或多个时区.每个时区都可以有一个或多个偏移量(随着历史的变化而改变).

包括时区名称

这就是 java.time 类的设计者 ZonedDateTime 冒昧地拥有它的 toString 方法扩展了标准 ISO 8601 格式,仅使用偏移量还在方括号中附加时区名称.

例如,该类不是简单地生成标准格式:2007-12-03T10:15:30+01:00,而是生成 2007-12-03T10:15:30+01:00[欧洲/巴黎] 带有区域名称 欧洲/巴黎 附加.

ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ).toString()

<块引用>

2007-12-03T10:15:30+01:00[欧洲/巴黎]

我希望这种附加时区名称的做法能流行起来.标准委员会在设计 ISO 8601 方面做得非常出色,因此缺少时区名称是一个令人惊讶的遗漏.

您可以使用业务场景上下文中的线索猜测时区.但我建议不要这样做.猜测是有风险的,尤其是因为世界各地的政治家都喜欢频繁地重新定义时区.

UTC

存储、序列化和交换日期时间值的最佳做法通常是调整为 UTC.假设日期时间库的 tzdata 是最新的,调整为 UTC 提供了可靠的始终正确且明确的值.

例如,在 Java 中,这意味着使用或提取 Instant 对象.即时 class 代表 UTC 时间轴上的一个时刻,分辨率为 纳秒(最多九 (9) 位小数).

Instant Instant = Instant.now();

…或…

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );瞬间瞬间 = zdt.toInstant();

表示此类值的标准 ISO 8601 格式字符串使用 Z 作为 Zulu 的缩写,表示 UTC.

<块引用>

2007-12-03T09:15:30Z

OffsetDateTime

如果给你一个表示日期时间的字符串,只有一个偏移量,请将其解析为 OffsetDateTime 对象.

OffsetDateTime odt = OffsetDateTime.parse("2007-12-03T10:15:30+01:00");

<块引用>

odt.toString(): 2007-12-03T10:15:30+01:00

从那里你可以提取一个 UTC 值,一个 Instant.

Instant Instant = odt.toInstant();

<块引用>

instant.toString(): 2007-12-03T09:15:30Z

或者您可以调整到所需的时区以获得与 ZonedDateTime 对象.

ZoneId z = ZoneId.of( "Asia/Kolkata" );ZonedDateTime zdt = odt.atZoneSameInstant(z);

<块引用>

zdt.toString(): 2007-12-03T14:45:30+05:30[亚洲/加尔各答]

术语:本地"

我建议您在提及调整为特定地区的日期时间时避免使用本地"一词 挂钟时间.java.time 类和其他上下文中的本地"一词表示任何 位置,而不是特定位置.本地日期时间不是时间线上的特定时刻,只是关于一系列可能时刻的粗略概念.

例如,今年圣诞节开始的当地日期时间是2017-12-25T00:00:00,但奥克兰的午夜时刻比加尔各答要早得多,并且几个小时后在巴黎,而在蒙特利尔更晚了几个小时.

我建议您改为使用术语 zonedwall-clock time 来表示通过特定时区的镜头看到的特定时刻.

提示:偏移文字

当提到偏移量时,问题碰巧使用了字母 -7.我总是建议:

  • 按照 ISO 8601 的要求使用两位数和填充零
  • 按照某些库和格式的预期,同时使用小时和分钟.

所以使用 -07:00 而不是 -7.

I understand that it's pretty easy to display local time to a user given an offset from GMT for the timezone (e.g. -7 hours for Pacific Daylight Time).

But, what if I want to continue to display the correct local time for a long period of time (say 1 year). Given just an offset from GMT, you do not know what timezone the user is in. E.g. given -7, the user may live in the US or in Canada (or in some other country). These countries my have different local times at different points of the year (e.g. if the US changes to daylight time in March and CA in April).

My question is, is the above paragraph correct? Is there a standard way to take a GMT offset and make a good guess as to which timezone the user is in?

解决方案

Your conclusion is correct: There is no reliable way to identify a time zone from an offset-from-UTC.

For your example of an offset of -07:00, I count about three dozen possible time zones in the current list including: America/Boise, America/Chihuahua, and America/Edmonton.

A time zone is actually a collection of offsets, recording changes made over time with a certain offset used in that region for a certain period of time but then changed over another certain period of time.

For example, in America/Los_Angeles part of each year has an offset of -08:00 while another part of the year has -07:00. So that time zone is accumulating a history of at least two offsets per annum. In contrast, the neighboring region using the time zone America/Phoenix is not accumulating changes in its offset, having retained the same -07:00 offset for decades.

So we have a many-to-many relationship between offsets and time zones. An offset may appear in one or more time zones. And each time zone can have one or more offsets (having changed over history).

Include time zone name

This is why the designers of the java.time class ZonedDateTime have taken the liberty of having its toString method extend the standard ISO 8601 format using only offsets to also append the name of the time zone in square brackets.

For example, instead of simply generating the standard format: 2007-12-03T10:15:30+01:00, the class generates 2007-12-03T10:15:30+01:00[Europe/Paris] with the name of the zone Europe/Paris appended.

ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
             .toString()

2007-12-03T10:15:30+01:00[Europe/Paris]

I hope this practice of appending the time zone name catches on. The lack of time zone name is a surprising omission by the standards committees that otherwise did an outstanding job in designing ISO 8601.

You can guess about the time zone using clues from the context of your business scenario. But I advise against that. Guessing is risky, especially because politicians around the world have a penchant for frequently re-defining time zones.

UTC

The best practice in storing, serializing, and exchanging date-time values is generally to adjust into UTC. Assuming a date-time library’s tzdata is up-to-date, adjusting into UTC provides a reliable value that is always correct and unambiguous.

In Java, for example, that means using or extracting an Instant object. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = Instant.now();

…or…

ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
Instant instant = zdt.toInstant();

The standard ISO 8601 formatted string representing such a value uses a Z as short for Zulu and meaning UTC.

2007-12-03T09:15:30Z

OffsetDateTime

If you are given a string representing a date-time with only an offset, parse it as a OffsetDateTime object.

OffsetDateTime odt = OffsetDateTime.parse( "2007-12-03T10:15:30+01:00" );

odt.toString(): 2007-12-03T10:15:30+01:00

From there you can extract a value in UTC, an Instant.

Instant instant = odt.toInstant();

instant.toString(): 2007-12-03T09:15:30Z

Or you can adjust into a desired time zone to get the same moment as a ZonedDateTime object.

ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );

zdt.toString(): 2007-12-03T14:45:30+05:30[Asia/Kolkata]

Terminology: "local"

I suggest you avoid the term "local" when referring to a date-time adjusted into a region’s particular wall-clock time. The word "local" in the java.time classes and in other contexts means any locality, rather than a particular locality. A local date-time is not a specific moment on the timeline, only a rough idea about a range of possible moments.

For example the local date-time of the beginning of Christmas this year is 2017-12-25T00:00:00, but that moment of midnight is much earlier in Auckland than in Kolkata, and still hours later in Paris, while even more hours later in Montréal.

I suggest instead you use the terms zoned or wall-clock time when you mean a specific moment seen through the lens of a particular time zone.

Tip: Offset literals

The Question happened to use the letters -7 when referring to an offset. I suggest always:

  • Using double-digits with padding zero, as required by ISO 8601
  • Using both hour and minutes, as expected by some libraries and formats.

So use -07:00 rather than -7.

这篇关于当您只有一个偏移量时(从 GMT)向用户显示当地时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆