Java中夏令时问题

17 篇文章 0 订阅
2 篇文章 0 订阅
1. 夏令时
时区 Asia/Shanghai  存在夏令时   进入夏令时 时钟快一个小时,离开夏令时 时钟慢一个小时
GMT 标准时,不存在夏令时
Java中 默认,和系统有关
TimeZone.getDefault()
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]

mysql中  查询时区,设置时区
show variables like '%time_zone%'
set global time_zone = '+8:00';
2. 找出中国的夏令时时间段

网上说的夏令时,和代码实现查找的不太一样

1935年至1951年,每年5月1日至9月30日
1952年3月1日至10月31日
1953年至1954年,每年4月1日至10月31日
1955年至1956年,每年5月1日至9月30日
1957年至1959年,每年4月1日至9月30日
1960年至1961年,每年6月1日至9月30日
1974年至1975年,每年4月1日至10月31日
1979年7月1日至9月30日

1986年至1991年,每年4月中旬的第一个星期日2时起至9月中旬的第一个星期日2时止。具体如下:
1986年5月4日至9月14日,
1987年4月12日至9月13日,
1988年4月10日至9月11日,
1989年4月16日至9月17日,
1990年4月15日至9月16日,
1991年4月14日至9月15日。

代码实现
关键 timeZone.inDaylightTime(date) // 判断 date对象是否为夏令时

 /**
     * 计算中国夏令时时间段,从夏令时到不是夏令时的结束夏令时
     * @param year
     * @param monthCDT
     * @param dayCDT
     * @param hourCDT
     * @return
     * @throws ParseException
     */
    public static String cdtRange(int year, int monthCDT, int dayCDT, int hourCDT) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TimeZone timeZone = TimeZone.getDefault();
        // 获取到的日期+时间
        String dataStr = "";

        for(int month = monthCDT; month <= 12; month++){
            // 日计算过的 从当天算起
            int day = 1;
            if(month == monthCDT){
                day = dayCDT;
            }

            for(; day <= 31; day++){
                if(month % 2 == 0){
                    //偶数月
                    if(day <= 30){
                        // 2月
                        if(month == 2){
                            if(isLeapYear(year)) {
                                if(day <= 29){
                                    dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                                }
                            }else {
                                if(day <= 28){
                                    dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                                }
                            }
                        }else {
                            dataStr = year + "-" + getMonth(month) + "-" + getDay(day);
                        }
                    }
                }else{
                    dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                }

                // 时计算过的 从当天当时算起
                int hour = 0;
                if(month == monthCDT && day == dayCDT){
                    hour = hourCDT;
                }

                for(; hour <= 23; hour++){
                    String dateTime = dataStr + " " + getHour(hour) + ":00:00";
                    Date date = simpleDateFormat.parse(dateTime);
                    if(!timeZone.inDaylightTime(date)){
                        //夏令时结束的时间
                        return simpleDateFormat.format(new Date(date.getTime() ));

//                        return dateTime;
                    }
                }
            }
        }
        return "";
    }
 /**
     * 测试夏令时
     * @throws Exception
     */
    @Test
    public void test5() throws Exception {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TimeZone timeZone = TimeZone.getDefault();
        // sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]
        System.out.println(timeZone);

        List<String> list = new ArrayList<>();

        label:
        for(int year = 1900; year <= 2023; year++){
            // 获取到的日期+时间
            String dataStr = "";
            for(int month = 1; month <= 12; month++){
                for(int day = 1; day <= 31; day++){
                    if(month % 2 == 0){
                        if(day <= 30){
                            if(month == 2){
                                if(isLeapYear(year)) {
                                    if(day <= 29){
                                        dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                                    }
                                }else {
                                    if(day <= 28){
                                        dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                                    }
                                }
                            }else {
                                dataStr = year + "-" + getMonth(month) + "-" + getDay(day);
                            }
                        }
                    }else{
                        dataStr = year + "-" + getMonth(month) + "-"+ getDay(day);
                    }

                    for(int hour = 0; hour <= 23; hour++){
                        String dateTimeStart = dataStr + " " + getHour(hour) + ":00:00";
                        Date date = simpleDateFormat.parse(dateTimeStart);
                        // 是夏令时
                        if(timeZone.inDaylightTime(date)){
                            String dateTimeEnd = cdtRange(year, month, day, hour);
                            list.add(dateTimeStart + "\t\t" + dateTimeEnd);

                            continue label;
                        }
                    }
                }
            }
        }

        list.forEach(System.out::println);
    }    

运行结果

开始夏令时 - 结束夏令时(1940-10-12 23:00:00 不是夏令时, 1940-10-12 22:59:59 是夏令时)
1940-06-01 00:00:00		1940-10-12 23:00:00
1941-03-15 00:00:00		1941-11-01 23:00:00
1942-01-31 00:00:00		
1943-01-01 00:00:00		
1944-01-01 00:00:00		
1945-01-01 00:00:00		1945-09-01 23:00:00
1946-05-15 00:00:00		1946-09-30 23:00:00
1947-04-15 00:00:00		1947-11-01 00:00:00
1948-05-01 00:00:00		1948-09-30 23:00:00
1949-05-01 00:00:00		1949-05-27 23:00:00
1986-05-04 02:00:00		1986-09-14 01:00:00
1987-04-12 02:00:00		1987-09-13 01:00:00
1988-04-17 02:00:00		1988-09-11 01:00:00
1989-04-16 02:00:00		1989-09-17 01:00:00
1990-04-15 02:00:00		1990-09-16 01:00:00
1991-04-14 02:00:00		1991-09-15 01:00:00
3. 测试
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// Sun Apr 14 03:00:00 CDT 1991 快一个小时 没有 真正的 2时
System.out.println(simpleDateFormat.parse("1991-04-14 02:00:00").toString());

 // 1991-09-15 01:00:00 结束夏令时 慢 一个小时    1991-09-15 01:00:00
System.out.println(simpleDateFormat.format(simpleDateFormat.parse("1991-09-15 00:00:00").getTime() + 2 * 60 * 60 * 1000L));
// 1991-09-15 02:00:00
System.out.println(simpleDateFormat.format(simpleDateFormat.parse("1991-09-15 00:00:00").getTime() + 3 * 60 * 60 * 1000L));
4. springboot 中夏令时存在问题
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.TransientDataAccessResourceException: 
Error attempting to get column 'create_time' from result set.  Cause: java.sql.SQLException: HOUR_OF_DAY: 2 -> 3; HOUR_OF_DAY: 2 -> 3; nested exception is java.sql.SQLException: HOUR_OF_DAY: 2 -> 3] with root cause

解决
Date类型时

@Data
public class Box {
    private String id;
    private String title;
    private String content;
    private String price;
    private Date createTime;  
    private Date updateTime;
}
yml中 jdbc配置
 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8

LocalDateTime时

@Data
public class Box {
    private String id;
    private String title;
    private String content;
    private String price;
    private LocalDateTime createTime;  
    private LocalDateTime updateTime;
}
yml中 jdbc配置
 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=Asia/Shanghai

添加配置类

/**
 * localDateTime 序列化/反序列化配置,并且兼容 Date类型的序列化/反序列化
 *
 * @author liuxb
 */
@Configuration
public class LocalDateTimeConfig {
    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String localDateTimeFormat;
    private String localDateFormat = "yyyy-MM-dd";
    private String localTimeFormat = "HH:mm:ss";

    @Value("${spring.jackson.time-zone:GMT+8}")
    private TimeZone timeZone;

    @Bean
    public ObjectMapper objectMapper() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        //序列化
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(localDateTimeFormat)));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(localDateFormat)));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(localTimeFormat)));
        //反序列化
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(localDateTimeFormat)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(localDateFormat)));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(localTimeFormat)));

        // 不能直接使用 new ObjectMapper(),会导致 Date 类型序列化失效变为毫秒数
        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
                .json()
                .modules(javaTimeModule)
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .build();

        //不格式化未知的属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //不返回时间戳格式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.setDateFormat(new SimpleDateFormat(localDateTimeFormat));
        objectMapper.setTimeZone(timeZone);

        return objectMapper;
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值