一直都知道SimpleDateFormat是线程不安全的,现在还是出现了问题。阿里Java规范中(六.5)有这么一条强制
Instant
java.time 包中的 Instant 类代表的是某个时间(有点像 java.util.Date),准确的说是:”是不带时区的即时时间点“,它是精确到纳秒的(而不是象旧版本的Date精确到毫秒)。如果使用纳秒去表示一个时间则原来使用一位Long类型是不够的,需要占用更多一点的存储空间,实际上其内部是由两个Long字段组成,第一个部分保存的是自标准Java计算时代(就是1970年1月1日开始)到现在的秒数,第二部分保存的是纳秒数(永远不会超过999,999,999)。
实例代码如下:
1 // DateTimeFormatter - SimpleDateFormat 2 // Intant - Date 3 // LocalDateTime - Calendar 4 5 // date与instant的相互转化 6 Instant now = Instant.now(); 7 Date date = Date.from(now); 8 Instant instant = date.toInstant(); 9 // LocalDateTime代替Calendar 10 ZoneId zoneId = ZoneId.systemDefault(); 11 LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId); 12 int year = localDateTime.getYear(); 13 int month = localDateTime.getMonthValue(); 14 int dayOfMonth = localDateTime.getDayOfMonth(); 15 int hour = localDateTime.getHour(); 16 int minute = localDateTime.getMinute(); 17 int second = localDateTime.getSecond(); 18 // DateTimeFormatter代替SimpleDateFormat 19 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 20 // Date格式化成String 21 String format = dateTimeFormatter.format(localDateTime); 22 LocalDateTime parse = LocalDateTime.parse(format, dateTimeFormatter); 23 ZoneOffset offset = OffsetDateTime.now().getOffset(); 24 Instant instant2 = parse.toInstant(offset); 25 // 从String获得Date 26 Date from = Date.from(instant2);
说明:Java.time 这个包是线程安全的,所以可以替换之前的date类的使用。
Instant now = Instant.now();
System.out.println("now:"+now);
控制台输出:now:2018-07-09T08:59:08.853Z
通过这种方式获取的时间戳与北京时间相差8个时区,需要修正为北京时间,通过查看源代码发现Instant.now()使用等是UTC时间Clock.systemUTC().instant()。LocalDate、LocalDateTime 的now()方法使用的是系统默认时区 不存在Instant.now()的时间问题。
解决方法
如果要对应北京时间,需要增加8个小时
Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println("now:"+now);
控制台输出:now:2018-07-09T16:58:48.188Z
LocalDateTime
它表示的是不带时区的 日期及时间,替换之前的Calendar。看上去,LocalDateTime和Instant很象,但记得的是“Instant中是不带时区的即时时间点。可能有人说,即时的时间点 不就是日期+时间么?看上去是这样的,但还是有所区别,比如LocalDateTime对于用户来说,可能就只是一个简单的日期和时间的概念,考虑如下的 例子:两个人都在2013年7月2日11点出生,第一个人是在英国出生,而第二个是在加尼福利亚,如果我们问他们是在什么时候出生的话,则他们看上去都是 在同样的时间出生(就是LocalDateTime所表达的),但如果我们根据时间线(如格林威治时间线)去仔细考察,则会发现在出生的人会比在英国出生的人稍微晚几个小时(这就是Instant所表达的概念,并且要将其转换为UTC格式的时间)。
实例代码如下:
1 public static void main(String[] args) { 2 //LocalDateTime 相当于calendar 3 LocalDateTime localDateTime = LocalDateTime.now(); 4 System.out.println(localDateTime+" localDateTime1"); 5 //当前时间加上5小时,分钟等一样的用法,支持链式编程 6 LocalDateTime localDateTime1 = localDateTime.plusHours(5); 7 System.out.println(localDateTime1+" localDateTime1"); 8 //当前时间加上5小时,分钟等一样的用法,支持链式编程 但是这里localtime只是时间,不展示年月日,只展示如:15:26:50.398 时分秒毫秒 9 LocalTime localDateTime2 = localDateTime.toLocalTime().plusHours(5); 10 //当前时间加上5天,只展示年月日,不展示时分秒毫秒,下面是两种写法,都可以 11 LocalDate localDate = localDateTime.toLocalDate().plusDays(5); 12 System.out.println(localDateTime2+" localDateTime2 "+localDate+ " localDate"); 13 LocalDate plus = localDateTime.toLocalDate().plus(Period.ofDays(5)); 14 System.out.println(plus+" plus"); 15 16 17 }
格式化日期
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.now() ,ZoneId.systemDefault()); String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss")); System.out.println(format);
另一种方式使用会报错:
Instant now = Instant.now(); String format = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(now); system.out.println(format);
格式化日期并获取这一周内的数据
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.now() ,ZoneId.systemDefault()); String createStartTp =localDateTime.plusDays(-6).format(DateTimeFormatter.ofPattern("yyyy/MM/dd 00:00:00")); system.out.println(createStartTp);