Java编程系列Java判断世界各时区的夏令时冬令时

Posted 善良勤劳勇敢而又聪明的老杨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java编程系列Java判断世界各时区的夏令时冬令时相关的知识,希望对你有一定的参考价值。

热门系列:


目录

1.前言

2.正文

    2.1 设置时区

    2.2 判断夏令时、冬令时

3.结尾


1.前言

前段时间在做一个需求的时候,其中有一个环节是需要判断当前时段,是否属于夏令时或是冬令时!对于做过国际业务或是外贸业务的童靴,应该都可能有接触到这一块。

在我们国内,是以北京时间为准,但在美国、或是欧洲等其他地区,不仅都有各自的时区,并且一年中,还分为夏令时和冬令时两个阶段!所以,在解决这个问题时,我们需要注意到两个问题点:

1、怎么获取到对应的时区?

2、怎么判断是否属于夏令时或是冬令时?


2.正文

弄清楚问题点后,咱们直接开整!

2.1 设置时区

在这里,会有一个选择题出现!一般我们平时使用日期类的时候,都是基于

java.util.Date

这个工具类来使用的;其次,现在Java8也新出了一个时间类库:

java.time.LocalDate;
java.time.LocalDateTime;
java.time.LocalTime;
java.time.ZoneId;
java.time.ZonedDateTime;
java.time.zone.ZoneRules;

那这个时候,就得二选一啦。功能实现上,其实二者都是可选的,但是应该选哪一种,优劣对比之下呢。我本人,选择了后者!

为什么?Date时间类其实使用的时候,可读性比较差;这个时候,我们通常会使用SimpleDateFormat去进行格式化;此时,我们需要注意他的线程安全问题,例如使用format方法,但其实现源码如下:

private StringBuffer format(Date date, StringBuffer toAppendTo,
                              FieldDelegate delegate) 
        // Convert input date to time field list
        calendar.setTime(date);

        boolean useDateFormatSymbols = useDateFormatSymbols();

        for (int i = 0; i < compiledPattern.length; ) 
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) 
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            

            switch (tag) 
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;

            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;

            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            
        
        return toAppendTo;
    

calendar是共享变量,并且这个共享变量没有做线程安全控制。当多个线程同时使用相同的SimpleDateFormat对象【如用static修饰的SimpleDateFormat】调用format方法时,多个线程会同时调用calendar.setTime方法,可能一个线程刚设置好time值另外的一个线程马上把设置的time值给修改了导致返回的格式化时间可能是错误的。

在多并发情况下使用SimpleDateFormat需格外注意SimpleDateFormat除了format是线程不安全以外,parse方法也是线程不安全的。parse方法实际调用alb.establish(calendar).getTime()方法来解析,alb.establish(calendar)方法里主要完成了:

  • 重置日期对象cal的属性值
  • 使用calb中中属性设置cal
  • 返回设置好的cal对象

但是这三步不是原子操作!!!而后者,java8新推出的时间类LocalDate、LocalTime、LocalDateTime等都是不可变类且线程安全的!所以可以放心使用!至于具体使用方式,此处不做赘述,各位可自行了解!

时区有很多,但是通过java.time类库中java.time.ZoneId的源码,可以发现可供选择的有如下这些:

public abstract class ZoneId implements Serializable 

    /**
     * A map of zone overrides to enable the short time-zone names to be used.
     * <p>
     * Use of short zone IDs has been deprecated in @code java.util.TimeZone.
     * This map allows the IDs to continue to be used via the
     * @link #of(String, Map) factory method.
     * <p>
     * This map contains a mapping of the IDs that is in line with TZDB 2005r and
     * later, where 'EST', 'MST' and 'HST' map to IDs which do not include daylight
     * savings.
     * <p>
     * This maps as follows:
     * <ul>
     * <li>EST - -05:00</li>
     * <li>HST - -10:00</li>
     * <li>MST - -07:00</li>
     * <li>ACT - Australia/Darwin</li>
     * <li>AET - Australia/Sydney</li>
     * <li>AGT - America/Argentina/Buenos_Aires</li>
     * <li>ART - Africa/Cairo</li>
     * <li>AST - America/Anchorage</li>
     * <li>BET - America/Sao_Paulo</li>
     * <li>BST - Asia/Dhaka</li>
     * <li>CAT - Africa/Harare</li>
     * <li>CNT - America/St_Johns</li>
     * <li>CST - America/Chicago</li>
     * <li>CTT - Asia/Shanghai</li>
     * <li>EAT - Africa/Addis_Ababa</li>
     * <li>ECT - Europe/Paris</li>
     * <li>IET - America/Indiana/Indianapolis</li>
     * <li>IST - Asia/Kolkata</li>
     * <li>JST - Asia/Tokyo</li>
     * <li>MIT - Pacific/Apia</li>
     * <li>NET - Asia/Yerevan</li>
     * <li>NST - Pacific/Auckland</li>
     * <li>PLT - Asia/Karachi</li>
     * <li>PNT - America/Phoenix</li>
     * <li>PRT - America/Puerto_Rico</li>
     * <li>PST - America/Los_Angeles</li>
     * <li>SST - Pacific/Guadalcanal</li>
     * <li>VST - Asia/Ho_Chi_Minh</li>
     * </ul>
     * The map is unmodifiable.
     */
    public static final Map<String, String> SHORT_IDS;
    static 
        Map<String, String> map = new HashMap<>(64);
        map.put("ACT", "Australia/Darwin");
        map.put("AET", "Australia/Sydney");
        map.put("AGT", "America/Argentina/Buenos_Aires");
        map.put("ART", "Africa/Cairo");
        map.put("AST", "America/Anchorage");
        map.put("BET", "America/Sao_Paulo");
        map.put("BST", "Asia/Dhaka");
        map.put("CAT", "Africa/Harare");
        map.put("CNT", "America/St_Johns");
        map.put("CST", "America/Chicago");
        map.put("CTT", "Asia/Shanghai");
        map.put("EAT", "Africa/Addis_Ababa");
        map.put("ECT", "Europe/Paris");
        map.put("IET", "America/Indiana/Indianapolis");
        map.put("IST", "Asia/Kolkata");
        map.put("JST", "Asia/Tokyo");
        map.put("MIT", "Pacific/Apia");
        map.put("NET", "Asia/Yerevan");
        map.put("NST", "Pacific/Auckland");
        map.put("PLT", "Asia/Karachi");
        map.put("PNT", "America/Phoenix");
        map.put("PRT", "America/Puerto_Rico");
        map.put("PST", "America/Los_Angeles");
        map.put("SST", "Pacific/Guadalcanal");
        map.put("VST", "Asia/Ho_Chi_Minh");
        map.put("EST", "-05:00");
        map.put("MST", "-07:00");
        map.put("HST", "-10:00");
        SHORT_IDS = Collections.unmodifiableMap(map);
    

上述时区简写,可以自行了解。我贴一下,我本次使用到的一些常见时区简称中文版:

<timezone id="Asia/Shanghai">中国标准时间 (北京)</timezone>  
<timezone id="Asia/Hong_Kong">香港时间 (香港)</timezone>  
<timezone id="Asia/Taipei">台北时间 (台北)</timezone>  
<timezone id="Asia/Seoul">首尔</timezone>  
<timezone id="Asia/Tokyo">日本时间 (东京)</timezone>  
<timezone id="America/New_York">美国东部时间 (纽约)</timezone>  
<timezone id="America/Denver">美国山区时间 (丹佛)</timezone>  
<timezone id="America/Costa_Rica">美国中部时间 (哥斯达黎加)</timezone>  
<timezone id="America/Chicago">美国中部时间 (芝加哥)</timezone>  
<timezone id="America/Mexico_City">美国中部时间 (墨西哥城)</timezone>  
<timezone id="America/Regina">美国中部时间 (里贾纳)</timezone>  
<timezone id="America/Los_Angeles">美国太平洋时间 (洛杉矶)</timezone>  
<timezone id="America/Tijuana">美国太平洋时间 (提华纳)</timezone>  
<timezone id="America/Phoenix">美国山区时间 (凤凰城)</timezone>  

现在,贴下时区设置的代码:

//例如设置美国纽约时区,并获取纽约当前时间
ZoneId zoneId = ZoneId.of("America/New_York");
LocalDateTime localDateTime = LocalDateTime.now(zoneId);

 

2.2 判断夏令时、冬令时

在判断都夏冬令时之前,我们得知道各个时区的冬夏令时计时规则!这里有一个时区大全的传送门各位按需查看!我本次需要判断美国、欧洲两个地区的夏冬令时,所以其计时规则如下:

美国

夏令时:每年3月第一个星期六到11月第二个星期日;

冬令时:每年3月第二个星期日到11月第一个星期六;

 

欧洲

夏令时:每年3月的最后一个星期天的凌晨1点开始,十月最后一个星期天凌晨1点结束;

冬令时:每年十月的最后一个星期天的凌晨1点开始,到第二年的三月份的最后一个星期天的凌晨1点结束;

但是,其实我们通过以下代码,就可以直接判断,当前时区,是处在夏令时还是冬令时了:

//还是以美国纽约时区为例
ZoneId zoneId = ZoneId.of("America/New_York");
//获取当前时区当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//设置ZonedDateTime对象
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
//获取时区计时规则
ZoneRules rules = zoneId.getRules();
//true表示处于夏令时,否则冬令时
boolean result = rules.isDaylightSavings(zonedDateTime.toInstant());

3.结尾

以上内容,作为开发记录,也是一种分享,希望能帮助到有需要的朋友!若有错误,也欢迎大家积极留言指正、讨论!

二维码内,有我个人平时收集而来的2T资料,有网盘存储,长期有效!有兴趣的同学,可以扫码关注我的个人公众号:时代名猿,回复关键字:wyzl,领取一线资料!

以上是关于Java编程系列Java判断世界各时区的夏令时冬令时的主要内容,如果未能解决你的问题,请参考以下文章

各种时间格式(UTC、GMT等)及夏令时和冬令时

中国与美国的时差怎么算?

中国有夏令时和冬令时吗?

utc时间21是北京时间多少

在 Java 中获取时区的夏令时转换日期

在 Java 中获取时区的夏令时转换日期