Java之Date类和Calendar类的区别
Java日期处理的十个坑
SimpleDateFormat线程不安全及解决办法
《java核心技术1》 中,类库的设计者希望能够将时间点和日期分开:一个是用来表示时间点的Date类,一个是用来表示大家熟悉的日历表示法的GregorianCalendar类,事实上,GregorianCalendar类拓展了一个更加通用的Calendar类,这个类描述了日历的一般属性。
在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和
日期处理 。
主要区别:java.util.Date是个日期数据;java.util.Calendar 用于日期相关的计算;
//1. 两个对象之间的不同 Date date=new Date(); // Sun Apr 17 22:05:46 CST 2022 Calendar ca=Calendar.getInstance(); //java.util.GregorianCalendar[time=1650204346836,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19, // lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=3,WEEK_OF_YEAR=17,WEEK_OF_MONTH=4,DAY_OF_MONTH=17,DAY_OF_YEAR=107,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=10,HOUR_OF_DAY=22,MINUTE=5,SECOND=46,MILLISECOND=836,ZONE_OFFSET=28800000,DST_OFFSET=0] System.out.println(date); System.out.println(ca); //2.两者之间的相互转换 Date caDate=ca.getTime(); Calendar cb=Calendar.getInstance(); cb.setTime(date); System.out.println(caDate); //Sun Apr 17 22:05:46 CST 2022 System.out.println(cb); // cb 与ca一致
Date类常用的构造器:到目前为止,还有两个构造器是推荐使用,其他的构造器已经过时就不在此说明:
Date中常用方法
时间概念:Java 8开始,明确了日期时间概念,例如:瞬时(instant)、 长短(duration)、日期、时间、时区和周期。
常用方法汇总: (Date中的方法全部包含此处不在累述): protected Calendar() 由于修饰符是protected,所以无法直接创建对象
常量 | 描述 |
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
注意事项:
a.Calendar获取的月份比实际数字少1即(0-11)
b.西方星期的开始为周日,中国为周一
c. 日期是有大小关系的,时间靠后,时间越大
a.yyyy与YYYY之间的区分:
2019年12月31号,就转了一下格式,就变成了2020年12月31号了?因为YYYY是基于周来计算年的,它指向当天所在周属于的年份,一周从周日开始算起,周六结束,只要本周跨年,那么 这一周就算下一年的了。正确姿势是使用yyyy格式。
b.hh与HH之间的区分:
hh是12制的日期格式,当时间为12点,会处理为0点。正确姿势是使用HH,它才是24小时制。
c.dd和DD之间的区分:
DD表示的是一年中的第几天,而dd表示的是一月中的第几天,所以应该用的是dd。
d.SimleDateFormat的format初始化问题:
SimpleDateFormat继承了 DateFormat,DateFormat类中维护了一个全局的Calendar变量,sdf.parse(dateStr)和sdf.format(date),都是由Calendar引用来储存的。如果SimpleDateFormat是static全局共享的,Calendar引用也会被共享。又因为Calendar内部并没有线程安全机制,所以全局共享的SimpleDateFormat不是线性安全的。
解决SimpleDateFormat线性不安全问题的方式:
1、将SimpleDateFormat定义成局部变量。
缺点:每调用一次方法就会创建一个SimpleDateFormat对象,方法结束又要作为垃圾回收。
2、方法加同步锁synchronized,在同一时刻,只有一个线程可以执行类中的某个方法。
缺点:性能较差,每次都要等待锁释放后其他线程才能进入。
3、使用第三方库joda-time,由第三方考虑线程不安全的问题。(可以使用)DateUtils (采用SimpleDateFormat定义成局部变量)
4、使用ThreadLocal:每个线程拥有自己的SimpleDateFormat对象。(推荐使用)
JDK8的应用,可以使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替Simpledateformatter,官方给出的解释:simple beautiful strong immutable thread-safe。
e.日期本地化问题
DateTimeFormatter 这个类默认进行本地化设置,如果默认是中文,解析英文字符串就会报异常。可以传入一个本地化参数(Locale.US)解决这个问题.
String dateStr = "Wed Mar 18 10:00:00 2020";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy",Locale.US);
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println(dateTime)
1.java Date日期去掉时分秒: 参考(java Date日期去掉时分秒)
@Test public void DateToDateForYYYYMMDD(){ //第一种方式: 格式转换SimpleDateFormat SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { Date dt= sdf.parse(sdf.format(new Date())); System.out.println(dt); } catch (ParseException e) { throw new RuntimeException("时间转换异常", e); } //第二种方式 直接清除的方式 Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date dt2=calendar.getTime(); //第三种方式 Long createTime = new Date().getTime(); Date dt3 =new Date(createTime - ((createTime + 28800000) % (86400000))); System.out.println(dt2); System.out.println(dt3); }
执行结果分析:
三种方式执行结果是一致的;其中第三种方式中(把毫秒转换为日期:1 天 = 24 × 60 × 60 = 86400 秒 = 86400 x 1000 = 86400000毫秒,28800000是补上 时区的8小时。
2.两个Date值比较年月的大小
3.两个Date相差几个月,几天,几年,几个小时,几分钟,几秒问题
4.根据字符串赋初值
5.时间格式的使用 DateTimeFormatter,SimpleDateFormat
6.Calendar 月份与年份相加