你还在用SimpleDateFormat格式化时间么?老板叫你明天不要来了,,,,,,,,,,

 你在项目中写如下一行代码来格式化时间会有啥危险?

你来打我呀
/**
 * 定义一个全局的SimpleDateFormat
 */
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

1.在阿里巴巴Java开发手册中,有如下明确规定: 

2.SimpleDateFormat的线程安全性: 

3.SimpleDateFormat为神马会有线程安全性问题?

找到SimpleDateFormat类的format方法一看便知,他使用了一个全局的Calendar 变量导致:

protected Calendar calendar;

       由于我们在声明SimpleDateFormat的时候,使用的是static定义的。那么这个SimpleDateFormat就是一个共享变量,随之,SimpleDateFormat中的calendar也就可以被多个线程访问到

4.如何解决

 4.1使用局部变量(略)

 4.2加同步锁

synchronized (simpleDateFormat) {
   ,,,,,,,,,,,,,,,,,,
}
可以只对simpleDateFormat.format这一行加锁,这样效率更高一些

4.3使用ThreadLocal 

/**
 * 使用ThreadLocal定义一个全局的SimpleDateFormat
 */
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};

//用法
String dateString = simpleDateFormatThreadLocal.get().format(calendar.getTime());

4.4使用DateTimeFormatter

        可以使用DateTimeFormatter代替SimpleDateFormat,这是一个线程安全的格式化工具类。就像官方文档中说的,这个类 simple beautiful strong immutable thread-safe

5.工具类

package xxxxx(自己的项目路径);

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zlf
 * @description:
 * @time: 2021/10/10 16:27
 */
@Component
@Slf4j
public class DateUtils {

    private static final DateTimeFormatter df1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter df2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter df3 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
    private static final DateTimeFormatter df4 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

   /**
     * 传入一个开始日期和结束日期(开始日期小于结束日期),返回这之间的日期天数,可以结合xxl-job等定时任务跑批处理开始时间至结束时间段的每一天额数据
     * @param startTime
     * @param endTime
     * @return
     */
    public List<String> calculationDays(String startTime, String endTime) {
        List<String> allDays = new ArrayList<>();
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDt = LocalDate.parse(startTime, dateTimeFormatter1);
        int start_Y = startDt.getYear();
        int start_M = startDt.getMonth().getValue();
        int start_D = startDt.getDayOfMonth();
        log.info("Y=" + start_Y + ",M=" + start_M + ",D=" + start_D);

        LocalDate endDt = LocalDate.parse(endTime, dateTimeFormatter1);
        int start_Y1 = endDt.getYear();
        int start_M1 = endDt.getMonth().getValue();
        int start_D1 = endDt.getDayOfMonth();
        log.info("Y1=" + start_Y1 + ",M1=" + start_M1 + ",D1=" + start_D1);

        if (startDt.compareTo(endDt) > 1) {
            //开始时间大于结束时间返回空!
            return null;
        }
        String endTimeStr = dateTimeFormatter1.format(endDt);

        Period period = Period.between(LocalDate.parse(startTime), endDt);

        StringBuffer sb = new StringBuffer();
        sb.append(period.getYears()).append(",")
                .append(period.getMonths()).append(",")
                .append(period.getDays());
        log.info("=======时间分量:=======" + sb.toString());

        int py = start_Y1 - start_Y;
        int Y = 12;
        detailYear(allDays, start_Y, py, Y);
        log.info("=======allDays--size()=======" + allDays.size());
        if (CollectionUtil.isNotEmpty(allDays)) {
            for (int i = 0; i < allDays.size(); i++) {
                log.info(allDays.get(i) + "--------allDays------>第" + (i + 1) + "天");
            }
            List<String> okResult = getOkResult(allDays, startTime, endTimeStr);
            System.out.println("=======okResult--size()=======" + okResult.size());
            for (int i = 0; i < okResult.size(); i++) {
                log.info(okResult.get(i) + "--------okResult-------->第" + (i + 1));
            }
            return okResult;
        }
        return null;
    }

    /**
     * 获取正确的List
     *
     * @param startTime
     * @param allDays
     * @return
     */
    private static List<String> getOkResult(List<String> allDays, String startTime, String endTime) {
        List<String> result = new ArrayList<>();
        int indexStart = 0;
        int indexEnd = 0;
        for (int i = 0; i < allDays.size(); i++) {
            if (allDays.get(i).equals(startTime)) {
                indexStart = i;
            }
        }
        for (int i = 0; i < allDays.size(); i++) {
            if (allDays.get(i).equals(endTime)) {
                indexEnd = i;
            }
        }
        result = allDays.subList(indexStart, indexEnd + 1);
        return result;
    }

    /**
     * 处理整年
     *
     * @param allDays
     * @param start_Y
     * @param py
     * @param y
     */
    private void detailYear(List<String> allDays, int start_Y, int py, int y) {
        //处理年的天
        for (int i = start_Y; i < start_Y + py + 1; i++) {
            for (int j = 1; j <= y; j++) {
                String fst = "";
                if (j <= 9) {
                    fst = i + "-0" + j + "-01";
                } else {
                    fst = i + "-" + j + "-01";
                }
                int diff_day = getDiff_day(fst);
                for (int k = 1; k <= diff_day + 1; k++) {
                    String d = "";
                    if (j <= 9) {
                        d = i + "-0" + j;
                        if (k <= 9) {
                            d += "-0" + k;
                        } else if (k > 9) {
                            d += "-" + k;
                        }
                    } else if (j > 9) {
                        d = i + "-" + j;
                        if (k <= 9) {
                            d += "-0" + k;
                        } else if (k > 9) {
                            d += "-" + k;
                        }
                    }
                    allDays.add(d);
                }
            }
        }
    }

    /**
     * 根据当月第一天计算本月的开始天和结束天
     *
     * @param fst
     * @return
     */
    private int getDiff_day(String fst) {
        LocalDate fstLd = LocalDate.parse(fst);
        //获取月的第一天
        LocalDate fstLd_fd = fstLd.with(TemporalAdjusters.firstDayOfMonth());
        //获取月的最后一天
        LocalDate fstLd_ld = fstLd.with(TemporalAdjusters.lastDayOfMonth());
        Period period2 = Period.between(fstLd_fd, fstLd_ld);
        int diff_day = period2.getDays();
        return diff_day;
    }

    /**
     * LocalDateTime转String,格式是:yyyy-MM-dd HH:mm:ss
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToString(LocalDateTime localDateTime) {
        String format = df1.format(localDateTime);
        return format;
    }

    /**
     * LocalDateTime转String,格式是:yyyy-MM-dd
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToStringToYMD(LocalDateTime localDateTime) {
        String format = df2.format(localDateTime);
        return format;
    }
     /**
     * String转LocalDateTime,格式是:yyyy-MM-dd HH:mm:ss
     * @param dateTimeStr
     * @return
     */
    public static LocalDateTime stringToLocalDateTime(String dateTimeStr) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, df1);
        return localDateTime;
    }
    /**
     * String转LocalDateTime,格式是:yyyy-MM-dd
     * @param dateTimeStr
     * @return
     */
    public static LocalDateTime stringIncludeTStrToLocalDateTime(String dateTimeStr) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, df3);
        return localDateTime;
    }
    /**
     * LocalDateTime转String,格式是:yyyy-MM-dd'T'HH:mm:ss.SSS
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToStringT(LocalDateTime localDateTime) {
        String format = df3.format(localDateTime);
        return format;
    }
     /**
     * LocalDateTime转String,格式是:yyyy-MM-dd'T'HH:mm:ss
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToStringT2(LocalDateTime localDateTime) {
        String format = df4.format(localDateTime).replace("T", " ");
        return format;
    }
    
    /**
     * data转String
     * @param date
     * @return
     */
    public static String DateToString(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = instant.atZone(zoneId);
        LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
        // 或者直接使用LocalDateTime.ofInstant
        LocalDateTime localDateTime1 = LocalDateTime.ofInstant(instant, zoneId);
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dateTimeFormatter1.format(localDateTime);
    }

}

       这个DateUtils工具类是我在项目中每次都会遇到JDK8新日期的API转换操作的接口代码整理,日积月累还是挺方便的。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值