我需要一个时区,我有时区偏移。
例如,我有偏移= 14400000
。我想有一个时区(任何地方,任何城市)。我可以在SimpleDateFormat
中使用此时区,以便为此区域打印正确的时间。
This is what I found(我重构了一下):
private TimeZone getTimeZone(int offset) {
final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
String[] ids = TimeZone.getAvailableIDs(offset);
if (ids == null || ids.length == 0) {
return UTC_TIME_ZONE;
}
String matchingZoneId = ids[0];
return TimeZone.getTimeZone(matchingZoneId);
}
我明白了:
sun.util.calendar.ZoneInfo[id="Asia/Baku",offset=14400000,dstSavings=0,useDaylight=false,transitions=68,lastRule=null]
我不喜欢这种方法,因为TimeZone
会调用此处的ZoneInfoFile
getZoneIds(int var1)
。这是反编译的代码。
public static String[] getZoneIds(int var0) {
ArrayList var1 = new ArrayList();
String[] var2 = getZoneIds();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String var5 = var2[var4];
ZoneInfo var6 = getZoneInfo(var5);
if (var6.getRawOffset() == var0) {
var1.add(var5);
}
}
var2 = (String[])var1.toArray(new String[var1.size()]);
Arrays.sort(var2);
return var2;
}
你可以看到它在现有对象上循环以构建一个区域ID数组,而我只需要一个!
我的问题是,这是一种更有效的方式吗?我只需要任意时区ID或给定偏移量的单个时区。
答案 0 :(得分:2)
您可以使用SimpleTimeZone:
为任何偏移量构建TimeZone实例new SimpleTimeZone(offset, "My TimeZone");
答案 1 :(得分:2)
不要做你正在尝试的事情。
没有意义,因为在某个时刻共享偏移的区域可能不会在过去或将来的其他时刻共享该偏移。
Answer by Ole V.V.是正确的。这是一个更多的讨论。
我需要一个时区,我有时区偏移。
不太可能。
offset-from-UTC只是UTC之前或之后的几小时,几分钟和几秒钟。
时区更多。区域是特定区域的人员使用的偏移的过去变化的历史。区域还具有针对该区域的偏移的当前和未来更改的规则。因此,时区总是优于仅仅偏移,但只有在确定已知时。在你的情况下,你不知道区域,不应该猜测;只需坚持使用偏移。
给定的偏移量无法引导您进入特定时区而不会产生歧义且没有错误。
Europe/Gibralter
&amp; Europe/Oslo
&amp;今天,Africa/Lagos
共享相同的偏移量,比UTC早一个小时。因此,只有+01:00
的UTC偏移量,你怎么知道哪个合适?请注意ZoneRules
类只有在您提供(日期时间值)作为参数传递时才能为特定区域提供偏移量。
ZoneOffset offset = ZoneId.of( "Africa/Tunis" ) // Instantiate a `ZoneId`.
.getRules() // Obtain a `ZoneRules` object from that `ZoneId` object.
.getOffset( Instant.now() ) ; // Interrogate that `ZoneRules` for an offset-from-UTC in use at a specific moment in history.
我只需要任何时区id或给定偏移量的单个时区。
这是不可取的。如上所述,在一个日期上共享特定偏移的时区可能不会在另一个日期共享该偏移。每个区域根据偏移变化的历史而变化。所以任意挑选一个区域是不明智的。
如其他答案中所述,TimeZone
&amp; ZoneInfo
类现已成为遗产。它们是由 java.time 类取代的麻烦的旧日期时间类的一部分。
而是使用ZoneOffset
(从UTC偏移)和ZoneId
(时区)。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" );
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和&amp; SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:1)
TimeZone
类与您通常使用的类一起已经过时了; Calendar
,GregorianCalendar
,DateFormat
和SimpleDateFormat
。
我建议您开始使用java.time
,而不是现代Java日期和时间API。通常这么好用。然后,您需要一个ZoneId
对象作为您的时区。对于具有常量偏移量的ZoneId
,我们创建ZoneOffset
的实例,ZoneId
的两个子类之一。
int offsetMilliseconds = 14_400_000;
int offsetSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(offsetMilliseconds);
// to check that we haven’t lost any precision, convert back to milliseconds and compare
if (TimeUnit.SECONDS.toMillis(offsetSeconds) != offsetMilliseconds) {
throw new IllegalArgumentException("Millisecond precision not supported: " + offsetMilliseconds);
}
ZoneId tzid = ZoneOffset.ofTotalSeconds(offsetMilliseconds / 1000);
System.out.println(tzid);
// test the time zone we got
System.out.println(ZonedDateTime.now(tzid));
在我的电脑上刚打印出来:
+04:00
2018-01-16T19:44:22.863760+04:00
ZoneOffset
只有秒的精度,而不是毫秒,这对于14 400 000毫秒的情况很好。如果你有几毫秒没有化妆一整秒,你可能想要整数秒而不是抛出异常,你的决定。
只有当您需要将旧式TimeZone
对象传递给某些您无法更改或不想立即更改的旧版API时,请转换我们上面提到的ZoneId
:
TimeZone oldfashionedTimeZone = TimeZone.getTimeZone(tzid);
这将为您显示TimeZone
,其显示名称为GMT+04:00
,当然还有4小时的偏移量。但是,请注意,如果TimeZone
无法识别您尝试转换的时区(如果您的偏移是奇数秒,则可能会出现这种情况),它会默认为您提供GMT(只有其中一个)旧班的问题)。所以你应该检查你得到的TimeZone
对象,例如:
if (oldfashionedTimeZone.getRawOffset() != offsetMilliseconds) {
throw new IllegalStateException("Conversion to legacy TimeZone object failed");
}