JDK1.8之DateTimeFormatter

本文探讨了JDK1.8之前的日期格式化问题,特别是SimpleDateFormat在并发环境下可能出现的安全问题。介绍了使用同步锁和ThreadLocal作为解决方案。接着详细介绍了JDK1.8引入的DateTimeFormatter,它是线程安全的,提供了多种实例化和常用方法,推荐在高并发场景下使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们常用的日期格式方式就是使用SimpleDateFormat,SimpleDateFormat在我们系统的里面,经常会用到,比如转换时间戳导出、打印啊等等。
伪代码:
在这里插入图片描述
正常我们都会这样使用转换时间
注意:有些是需要的时候创建新实例
如:工具类,创建新的实例
SimpleDateFormat在并发下会出现出现时间不对,线程挂死等等。
见源码:
在这里插入图片描述
作者写的注释:
翻译为:

  • 日期格式不同步。
  • 建议为每个线程创建单独的格式实例。
  • 如果多个线程同时访问一种格式,则必须从外部对其进行同步。

我们常用的format方法,我们去看看。
在这里插入图片描述
其次底层操作用的是calendar,然后声明的时候如果用static修饰变量,那么calendar变量也是就是一个共享变量,如果simpledateformat被用在n多方法,就你比如导出,需要各种转换的时候,那并发的时候,就会出现线程1执行完calendar.setTime(date),设置了值,这时候挂起的时候,线程2拿到了执行权,线程2也执行了calendar.setTime(date),线程2挂起了,然后线程1取值的时候,被其它竞争线程修改了值,那就会出现时间不对,线程挂死等。
如果需要用到simpledateformat,那如何解决这个问题

这里先要提2个东西
JDK1.8之前,JDK1.8之后
先讲JDK1.8之前
按上述作者的注释

一:JDK1.8之前

1:加一个同步锁

publict Class SimpleDateFormatTest{

public static String formatDate(Date date) {
		synchronized (formater) {			
			return formater.format(date);
		}
	}
}

在这里插入图片描述
一个同步锁搞定,但是我们知道同步锁会影响效率,高并发下会影响性能的

2:ThreadLocal

本地线程 - 解决线程竞争,安全不影响效率
在这里插入图片描述

private static ThreadLocal<DateFormat> threadLocalFormater = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};
public static String threadLoaclFormatDate(Date date) {
    return threadLocalFormater.get().format(date);
}

二:JDK1.8之后

java.time.format包下的DateTimeFormatter,是JDK1.8加入的日期格式化工具类,引入这个工具类就是解决了SimpleDateFormat的线程安全问题
见源码:
在这里插入图片描述
简述:
DateTimeFormatter不单单是不变对象,并也是线程安全的。
见源码:258行,作者的注释
在这里插入图片描述
SimpleDateFormat不是线程安全的,使用的时候,只能在方法内部创建新的局部变量。而DateTimeFormatter可以只创建一个实例,到处引用。

1 常用方法:

1.1 实例化方式:

预定义的标准格式;如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
本地化相关的格式;如:ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式;如:ofPattern(“yyyy-MM-dd hh:mm:ss”)

1.2 常用方法

		// 自定义格式如:ofPattern("yyyy-MM-dd hh:mm:ss")
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");// 12小时
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 24小时

        /* 日期类型转换字符串 -- start */
        // LocalTime  --> String
        LocalTime localTime = LocalTime.now();
        String format1 = localTime.format(DateTimeFormatter.ISO_TIME); // 15:01:22.42

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss");
        String format2 = localTime.format(formatter);

        System.out.println("LocalTime  --> String:" + format1);
        System.out.println("LocalTime  --> String:" + format2);
        // LocalTime  --> String

        // localDate --> String
        LocalDate localDate1 = LocalDate.now();
        String format3 = localDate1.format(DateTimeFormatter.BASIC_ISO_DATE);    // yyyyMMdd
        String format4 = localDate1.format(DateTimeFormatter.ISO_DATE);          // yyyy-MM-dd
        System.out.println("LocalDate --> String:" + format3);
        System.out.println("LocalDate --> String:" + format4);

        // LocalDateTime  --> String
        LocalDateTime localDateTime = LocalDateTime.now();
        String timeStr1 = localDateTime.format(dateTimeFormatter1);
        System.out.println("LocalDateTime  --> String:" + timeStr1);

        String timeStr2 = dateTimeFormatter1.format(LocalDateTime.now());
        System.out.println("LocalDateTime  --> String:" + timeStr2);
        // LocalDateTime  --> String

        /* 日期类型转换字符串 -- end */

        /* 字符串转日期类型 -- start */

        // String --> LocalDate
        LocalDate localDate2 = LocalDate.parse("2021-05-11 11:32:05",dateTimeFormatter2);
        System.out.println("String --> LocalDate:" + localDate2);

        LocalDate localDate3 = LocalDate.parse("2021-05-11");
        System.out.println("String --> LocalDate:" + localDate3);

        DateTimeFormatter pattern1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        System.out.println("String --> LocalDate:" + LocalDate.parse("2021-05-11").format(pattern1));
        // String --> LocalDate

        // String --> LocalTime
        LocalTime localTime2 = LocalTime.parse("07:43:53");
        System.out.println("String --> LocalTime:" + localTime2);
        // String --> LocalTime


        // String -->LocalDateTime
        LocalDate localDate4 = LocalDate.parse("2021-05-11 15:30:53",dateTimeFormatter2);
        System.out.println("String -->LocalDateTime:" + localDate4);
        // String -->LocalDateTime

        /* 字符串转日期类型 -- end */

        // 解析
        // 注意:我的日期格式12小时制,但是我的文本时间是24小时制,启动看会报什么错
		// TemporalAccessor temporalAccessor1 = dateTimeFormatter1.parse("2021-05-11 15:32:05");
		// System.out.println(temporalAccessor1);
        // java.time.format.DateTimeParseException: Text '2021-05-11 15:32:05' could not be parsed:
        // Invalid value for ClockHourOfAmPm (valid values 1 - 12): 15
        TemporalAccessor temporalAccessor2 = dateTimeFormatter1.parse("2021-05-11 11:32:05");
        // {SecondOfMinute=5, MilliOfSecond=0, NanoOfSecond=0, HourOfAmPm=11, MinuteOfHour=32, MicroOfSecond=0},ISO resolved to 2021-05-11
        System.out.println(temporalAccessor2);

如果你的JDK是1.8,并且你的simpledateformat没有做线程安全处理,除了上述的解决方案,强烈建议你使用JDK1.8推出的DateTimeFormatter ,如果没有用,别人搞这个干吗,需要注意的是,要使用instant代替Date,LocalDateTime替代Calendar

这边给出一些常用的转换方法

// date与instant的相互转化 -- start
Instant now = Instant.now();
System.out.println("时间戳与北京时间相差8个时区:"+now);
// 我们去查看源码: 272行
// 发现是采用的UTC,如果你需要使用北京时间,则需要增加8个小时
Instant nowUTC = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println("nowUTC :"+nowUTC );

Date date = Date.from(now);
System.out.println(date);

Instant instant = date.toInstant();

// LocalDate、LocalDateTime 的now()方法使用的是系统默认时区 不存在Instant.now()的时间问题。
// date与instant的相互转化 -- end

// LocalDateTime代替Calendar -- start
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
int year = localDateTime.getYear();// 年
int month = localDateTime.getMonthValue();// 月
int dayOfMonth = localDateTime.getDayOfMonth();// 日
int hour = localDateTime.getHour();// 小时
int minute = localDateTime.getMinute();// 分钟
int second = localDateTime.getSecond();// 秒
System.out.println(year);
System.out.println(month);
System.out.println(dayOfMonth);
System.out.println(hour);
System.out.println(minute);
System.out.println(second);
// LocalDateTime代替Calendar -- end


// DateTimeFormatter代替SimpleDateFormat
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 24小时制

// Date格式化成String -- start
String format = dateTimeFormatter.format(localDateTime);
System.out.println("Date格式化成String:" + format);
// Date格式化成String -- end

// String获得Date -- start
LocalDateTime parse = LocalDateTime.parse(format, dateTimeFormatter);
ZoneOffset offset = OffsetDateTime.now().getOffset();
Instant instant2 = parse.toInstant(offset);
Date date1 = Date.from(instant2);
System.out.println("String获得Date:" + date1);
// String获得Date -- end

在这里插入图片描述
见阿里巴巴手册:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值