相关文章推荐
坏坏的山羊  ·  Unparseable date: ...·  2 月前    · 
刚毅的馒头  ·  java中SimpleDateFormat解 ...·  2 月前    · 
逆袭的红酒  ·  解决pip is configured ...·  1 年前    · 
温暖的凉面  ·  Pnpm 错误 - 掘金·  1 年前    · 

在实际的项目中,时间是非常常见的一种应用,因此一般为时间格式化创建一个工具类,用于将项目中的时间进行格式化,目前使用的是 SimpleDateFormat ,但是在阿里编码规范检查中有一项检查,此项检查中不推荐使用 SimpleDateFormat ,因此本文对此项检查进行分析,用于设计出一个比较好用的时间格式化工具类。
检查条目描述如下:

SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。 说明:如果是JDK8的应用,可以使用instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

格式化当前时间

  • 使用SimpleDateFormat 进行格式当前时间代码如下
 public static String formatCurrent(String format){
 		// 注意 如果仅是格式化年月日时分秒都是使用数字来表示, Locale不影响
 		// 如果 如果需要进行国际化,则Locale 会受影响
        SimpleDateFormat  df = new SimpleDateFormat(format, Locale.US);
        return df.format(new Date());
  • 使用DateTimeFormatter进行格式化代码如下
	public static String formatCurrent(String format){
        LocalDateTime dt = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return formatter.format(dt);

小结
从格式化当前的功能来看,代码量差不多,易用性也差不多,同时 DateTimeFormatter 是线程安全的,确实带来了好处。
国际化问题
以月份为例子,其他例如星期,上午下午,等在国际化的时候都会受到影响

// 调用 DateUtils.formatCurrent("yyyy-MMMM-dd HH:mm:ss:SSS"); 输出:2020-六月-30 19:02:00:794
// 调用 DateUtils.formatCurrent("yyyy-MMM-dd HH:mm:ss:SSS"); 输出:2020-6月-30 19:02:00:794
public static String formatCurrent(String format){
		// 注意第二个参数
        SimpleDateFormat  df = new SimpleDateFormat(format, Locale.CHINA);
        return df.format(new Date());
// 调用 DateUtils.formatCurrent("yyyy-MMMM-dd HH:mm:ss:SSS"); 输出:2020-June-30 19:02:00:794
public static String formatCurrent(String format){
		// 注意第二个参数
        SimpleDateFormat  df = new SimpleDateFormat(format, Locale.US);
        return df.format(new Date());

格式化时间转换

  • 使用SimpleDateFormat 进行格式化时间进行转换,代码如下
public static String transformTime(String time, String oldFormat, String newFormat) {
        try {
            return new SimpleDateFormat(newFormat).format(new SimpleDateFormat(oldFormat).parse(time));
        } catch (Exception e) {
            e.printStackTrace();
        return time;
  • 使用DateTimeFormatter进行格式化时间进行转换,代码如下
	public static String transformTime(String timeStr,String oldFormat,String newFormat) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(oldFormat);
        LocalDateTime dt = LocalDateTime.parse(timeStr, formatter);
        return DateTimeFormatter.ofPattern(newFormat).format(dt);

使用DateTimeFormatter需要注意的问题是有:

  1. 如果带有毫秒,且格式为yyyyMMddHHmmssSSS,会抛出异常,调用代码如下。bug 描述。在java9 应该已经解决这个问题,但是目前android 还不支持java9,在android 上面还存在这个问题。
 String newRet1 = NewDateUtils.transformTime("20200630163030123","yyyyMMddHHmmssSSS","yyyy-MM-dd HH:mm:ss:SSS");
 * 抛出异常  java.time.format.DateTimeParseException: Text '20200630163030123' could not be parsed at index 0
 // 解决1
 public static String transformTimeMil(String timeStr,String oldFormat,String newFormat) {
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                // 解析date+time
                .appendPattern("yyyyMMddHHmmss")
                // 解析毫秒数
                .appendValue(ChronoField.MILLI_OF_SECOND, 3)
                .toFormatter();
        LocalDateTime dt = LocalDateTime.parse(timeStr, formatter);
        return DateTimeFormatter.ofPattern(newFormat).format(dt);
 // 解决方式2 ,可以在秒和毫秒直接添加空格等符号,
  1. 格式化年月日时分秒使用LocalDateTime,格式化年月日,使用LocalDate,格式化时间(时分秒)使用LocalTime。不能统一使用LocalDateTime进行格式化
    代码如下
// 格式化代码 
	public static String transformTime(String timeStr,String oldFormat,String newFormat) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(oldFormat);
        LocalDateTime dt = LocalDateTime.parse(timeStr, formatter);
        return DateTimeFormatter.ofPattern(newFormat).format(dt);
 // 调用代码
 String newRet1 = NewDateUtils.transformTime("20200630", "yyyyMMdd","yyyy-MM-dd");
 // 抛出异常
 // java.time.format.DateTimeParseException:
 // 解决 需要将LocalDateTime 替换为LocalDate,如果是只有时间也要替换为 LocalTime
  1. LocalDate 无法只格式化月和日,代码如下
// 格式化代码 
    public static String transformDate(String timeStr,String oldFormat,String newFormat) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(oldFormat);
        LocalDate dt = LocalDate.parse(timeStr, formatter);
        return DateTimeFormatter.ofPattern(newFormat).format(dt);
 // 调用
 String newRet1 = NewDateUtils.transformDate("0630", "MMdd","MM-dd");
 String newRet1 = NewDateUtils.transformDate("202006", "yyyyMM","yyyy-MM");              
 // 抛出异常 java.time.format.DateTimeParseException: 

小结
从格式化时间转换这个功能来说,DateTimeFormatter 的设计并不完美,或者因为本人知识有限,使用方式不对,造成的问题。从格式化时间转换这个功能点来说,DateTimeFormatter 在android 上面尚不具备在项目中编写成工具类的条件。

判断时间是否有效

  • 使用SimpleDateFormat 判断时间是否有效
	public static boolean isValidDate(String str, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            format.setLenient(false);
            format.parse(str);
        }catch (ParseException e) {
             e.printStackTrace();
             return false;
        return true;
  • 使用 DateTimeFormatter 来判断时间的有效性。
// 调用,注意这种模式下面,使用u代表年
ret = NewDateUtils.isValidDate("20200630","uuuuMMdd");
public static boolean isValidDate(String str, String pattern){
        try {
            DateTimeFormatter.ofPattern(pattern)
                            .withResolverStyle(ResolverStyle.STRICT)
                            .parse(str);
        } catch (RuntimeException e) {
            e.printStackTrace();
            return false;
        return true;

当然,时间格式的使用还有判断时间的大小,计算出距离某个时间前或者后的时间等等。从第二点(格式化时间转换)来看,目前DateTimeFormatter 还不具备足够大的优势,替换SimpleDateFormat。SimpleDateFormat 面临的问题就是线程安全的问题,定义为工具类,且SimpleDateFormat 为局部变量,可以解决线程安全的问题,但是导致的问就是SimpleDateFormat为局部变量,创建了大量的实例,消耗了空间。同时了解到有一个开源库Joda-Time对时间的操作比较友好,但是目前暂时没有进行体验,后面有时候可以深度体验一下。

阿里编码规范检查在阿里编码规范检查中有一项检查是java8推荐使用检查条目描述如下:SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类。 说明:如果是JDK8的应用,可以使用instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方给出的解释:simple beautiful strong immutable
Android 中,可以使用 java.text.DateFormat 类来格式化时间。 例如,要将当前时间格式化为中国的默认格式(类似于 "2022年12月29日 星期四 下午3点45分56秒"),可以使用以下代码: DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale....
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); dateTimeFormatter.format(LocalDateTime.now()); SimpleDateFormat sim
在项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用static修饰SimpleDateFormat吗 通过阅读本篇文章你将了解到: 为什么需要LocalDate、LocalTime、LocalDateTime【java8新提供的类】 java8新的时间API的使用方式,包括创建、格式化、解析、计算、修改 为什么需要LocalDate、LocalTime、LocalDateTime Date如果不格式化,打印出的日期可读性差 Tue Sep 10 09:34:04 CST 201
获得当前时间的本周一的凌晨零点零分零秒的时间,时间戳。 获得当前时间的本月的第一天的凌晨零点零分零秒的时间,时间戳。 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。 使用Java 8 新提供的API可以很好的操作时间。 时间和日期,可以实现简单的加plus 减 minus。可以操作的跨度:... import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.Loca 1、把格式化好的字符串解析成时间对象 Joda-Time为这两个核心需求的解决方案就是DateTimeFormatter。 额外提一点,DateTimeFormatter在格式化和解析时是支持时区的。 二、核心对象: 2.1 DateTimeFormatter 日期格式化与解析 2.2 LocalD... import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; * @author xiaobu * @version JDK1.8.0_171 * @date on 2019/...