请考虑以下代码:
if(strTimeZoneCd.equals("A"))
locTz = TimeZone.getTimeZone("AST");
else if(strTimeZoneCd.equals("M"))
locTz = TimeZone.getTimeZone("MST");
else if(strTimeZoneCd.equals("P"))
locTz = TimeZone.getTimeZone("PST");
else if(strTimeZoneCd.equals("H"))
locTz = TimeZone.getTimeZone("HST");
else if(strTimeZoneCd.equals("C"))
locTz = TimeZone.getTimeZone("CST");
else if(strTimeZoneCd.equals("E"))
locTz = TimeZone.getTimeZone("EST");
else if(strTimeZoneCd.equals("G"))
locTz = TimeZone.getTimeZone("GMT");
else if(strTimeZoneCd.equals("Y"))
locTz = TimeZone.getTimeZone("AKST");
在这里,如果我通过A
,它会给我AST
。但取而代之的是,我需要确定我应该返回AST
还是ADT
.
我需要确定AST
现在是否处于夏令时状态。如果是夏令时,我可以返回ADT
,如果不是,我可以返回AST
.但是我不知道如何确定该时区是否在夏令时。
有人可以帮我吗?
首先,避免使用时区名称的简短缩写(如CST
,PST
或CEST
),因为它们是模棱两可的,不是标准的。
例如,CST
被多个时区使用:它可以是"中部标准时间"、"中国标准时间"或"古巴标准时间"。而且每个人都有不同的关于Dayligh节省时间的规则,因此使用缩写不一定能得到你期望的结果。
TimeZone
类假定这些短名称的一些默认值(所有任意选择,就像任何默认值一样),并且还具有在名称未知时返回 GMT 的奇怪行为。
为避免这些歧义,最好使用 IANA 时区名称(始终采用Region/City
格式,如Asia/Kolkata
或America/New_York
)。
您可以通过调用TimeZone.getAvailableIDs()
来获取可用时区的列表(并选择最适合您系统的时区)。
然后,您可以使用inDaylightTime()
方法,如其他答案中所述。
另一种方法是使用格式化程序,因为它会自动检查它是否在夏令时并打印区域短名称。我还使用java.util.Locale
来指示名称应为英文(我不确定不同的语言是否会影响短区名称,这是一种"以防万一"的方法):
// formatter with `z` (zone short name)
SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.ENGLISH);
// set timezone in the formatter
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// prints the zone name for the current date
System.out.println(sdf.format(new Date()));
上面的代码打印EDT
(因为今天,2017 年 9 月 13日,纽约处于夏令时,使用的缩写是 EDT)。
在这种情况下,您可以创建格式化程序,并使用if
逻辑在其中设置正确的时区。然后,格式化程序负责检查日期是否在夏令时,返回正确的缩写。
Java new Date/Time API
旧的类(Date
、Calendar
和SimpleDateFormat
)有很多问题和设计问题,它们正在被新的API所取代。
如果您使用的是Java 8,请考虑使用新的 java.time API。它比旧的 API 更容易、更少错误且更不容易出错。
如果你使用的是Java<= 7,你可以使用ThreeTen Backport,这是Java 8新的日期/时间类的一个很好的反向移植。对于Android,您还需要ThreeTenABP(更多有关如何使用它的信息)。
下面的代码适用于这两种情况。 唯一的区别是包名(在Java 8中是java.time
,在ThreeTen Backport(或Android的ThreeTenABP)中是org.threeten.bp
),但类和方法名称是相同的。
首先,我创建一个具有z
模式(对应于区域短名称)和英语区域设置的DateTimeFormatter
。
然后我使用ZonedDateTime
,它表示特定时区中的日期和时间,以及获取当前日期/时间的now()
方法。我还使用ZoneId
来指定我想要的时区:
// create formatter for short zone name and English locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z", Locale.ENGLISH);
// format current date in New York timezone
System.out.println(fmt.format(ZonedDateTime.now(ZoneId.of("America/New_York"))));
这也打印EDT
。您可以应用上述相同的if
逻辑来定义将在ZoneId.of()
中使用哪个时区。只是提醒不要使用短名称(CST
等),因为新 API 不像旧 API 那么宽松。
TimeZone
假设有很多任意默认值,并在区域不存在时返回"GMT",但如果尝试获取无效区域,ZoneId
会引发异常(某些缩写应该适用于逆向兼容性原因,但默认值也是任意的,您应该避免它们)。
区域名称的自定义映射
您可以选择创建时区名称的自定义映射,因此无需创建大量if
子句来确定相应的区域。像这样:
// create custom map of zone names
Map<String, String> customZones = new HashMap<>();
// map "E" to New York
customZones.put("E", "America/New_York");
// map "G" to GMT
customZones.put("G", "GMT");
...
// create timezone using the custom map ("E" will create "America/New_York" zone)
ZoneId zone = ZoneId.of("E", customZones);
// format current date in specified timezone
System.out.println(fmt.format(ZonedDateTime.now(zone)));
解决此问题:
对于任何特定时区
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
您可以使用此程序来确定该时区是否处于夏令时之下。
另请参阅此链接。
TimeZone.getTimeZone("CST") 返回 GMT
import java.util.Date;
import java.util.TimeZone;
public class test {
public static void main(String[] args) {
System.out.println(TimeZone.getTimeZone("EST").inDaylightTime( new Date() ));
System.out.println(TimeZone.getTimeZone( "GMT-9:00").inDaylightTime( new Date() ));
}
}