java8时间处理及获取时间戳性能优化

996 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

java8新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。 最后附上时间处理工具类代码DateUtil.java和获取时间戳性能优化代码SystemClock.java

  • Local(本地) − 简化了日期时间的处理,没有时区的问题。
  • Zoned(时区) − 通过制定的时区处理日期时间。

LocalDate、 LocalTime、 LocalDateTime

提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息

//获取当前时间
LocalTime time = LocalTime.now();
//获取当前日期
LocalDate date = LocalDate.now();
//获取当前日期和时间
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime dateTime = LocalDateTime.of(2018, 12, 12, 12, 12, 12);
LocalDateTime dateTime = date.plusYears(2);// +两年
System.out.println(dateTime);// 2020-12-12T12:12:12
LocalDateTime dateTime1 = date.minusMonths(10);// -10月
//比较
boolean flag = localDate.isAfter(localDate2);
//闰年
boolean flag = localDate.isLeapYear();

Instant

用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算

//java7之前获取时间戳方式
long time = System.currentTimeMillis();
System.out.println(time);//1561599260726
//java8时间戳获取
Instant instant = Instant.now();//默认是UTC时区
System.out.println(instant);//2019-06-27T01:42:19.578Z
//带偏移量运算
OffsetDateTime odTime=instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(odTime);//2019-06-27T09:42:19.578+08:00
//获取毫秒显示的格式
long time1= instant.toEpochMilli();
System.out.println(time1);//1561599873015

Duration、Period

Duration:用于计算两个“时间”间隔 Period:用于计算两个“日期”间隔

// Duration
LocalTime localTime1 = LocalTime.of(12, 4, 33);
LocalTime localTime2 = LocalTime.of(12, 5, 45);
Duration duration1 = Duration.between(localTime1, localTime2);
System.out.println(duration1.getSeconds());// 72
System.out.println(duration1.toMinutes());// 1
// Period
LocalDate localDate = LocalDate.now();
LocalDate localDate2 = LocalDate.of(2018, 1, 12);
Period period=Period.between(localDate, localDate2);
System.out.println(period.getDays());

DateTimeFormatter

日期时间格式化类

//1.使用DateTimeFormatter默认提供好的格式对时间格式化,如DateTimeFormatter.ISO_DATE;
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.format(formatter));
//2.自定义时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd");
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.format(formatter));

ZonedDate、ZonedTime、ZonedDateTime

时区处理

//查看java8中支持的时区有哪些
Set<String> strings = ZoneId.getAvailableZoneIds();
strings.forEach(System.out::println);
//获取一个指定的时区
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
//获取指定时区的当前时间
LocalDateTime localDateTime = LocalDateTime.now(zoneId);
System.out.println(localDateTime);
ZonedDateTime localDateTime2 = localDateTime.atZone(zoneId);
System.err.println(localDateTime2);//2019-06-27T10:44:53.672+08:00[Asia/Shanghai]

DateUtil.java


public class DateUtil {
    public static final String YYMMDD = "yyMMdd";
    public static final String YYYYMMDD = "yyyy-MM-dd";
    public static final String YYYYMMDDHHMMSS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYMMDDHHMMSS_SHORT = "yyMMddHHmmss";
    public static final String YYYYMMDDTHHMM = "yyyy-MM-dd'T'HH:mm";

    public static String date2str(Date date, String format) {
        if (date == null) {
            return null;
        }
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return localDateTime.format(DateTimeFormatter.ofPattern(format));
    }

    public static String date2str(LocalDateTime localDateTime, DateTimeFormatter format) {
        if (localDateTime == null) {
            return null;
        }
        return localDateTime.format(format);
    }
    
    
    public static Date str2date(String dateStr, String format) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        if (YYYYMMDD.equals(format)) {
            LocalDate localDate = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
            return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        } else {
            LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(format));
            return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        }
    }

    public static long dateDifferMinute(Date startDate, Date endDate) {
        if (startDate == null) {
            startDate = new Date();
        }
        if (endDate == null) {
            endDate = new Date();
        }
        return (endDate.getTime() - startDate.getTime()) / (1000 * 60);
    }

    public static long dateDifferDay(Date startDate, Date endDate) {
        if (startDate == null) {
            startDate = new Date();
        }
        if (endDate == null) {
            endDate = new Date();
        }
        return (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24);
    }
    
    public static LocalDateTime getLocalDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }
    
    public static LocalDateTime addDateTime(LocalDateTime baseDateTime, long amountToAdd, ChronoUnit unit) {
        return baseDateTime.plus(amountToAdd, unit);
    }

SystemClock.java

System.currentTimeMillis()是比较重的调用,调用时候要进行内核态/用户态切换,应该让真正在忙着的那些线程尽量少切换。

SystemClock的时间精度不那么高,所以不能用在要求时间非常精准的场景。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

// System.currentTimeMillis()是比较重的调用,调用时候要进行内核态/用户态切换,应该让真正在忙着的那些线程尽量少切换
// SystemClock的时间精度不那么高,所以不能用在要求时间非常精准的场景
public class SystemClock {
    private static final String THREAD_NAME = "system-clock-daemon-thread";
    private static final SystemClock SYSTEM_CLOCK = new SystemClock(1);

    private final long precision;
    private final AtomicLong now;

    public SystemClock(long precision) {
        this.precision = precision;

        now = new AtomicLong(System.currentTimeMillis());
        scheduleClockUpdating();
    }

    private void scheduleClockUpdating() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable runnable) {
                Thread thread = new Thread(runnable, THREAD_NAME);
                thread.setDaemon(true);

                return thread;
            }
        });
        scheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                now.set(System.currentTimeMillis());
            }
        }, precision, precision, TimeUnit.MILLISECONDS);
    }

    public long now() {
        return now.get();
    }

    public long precision() {
        return precision;
    }

    public static SystemClock instance() {
        return SYSTEM_CLOCK;
    }
}