java8日期_java8处理日期和时间

自省:java8用了好久了,虽然一直知道有新的时间API,但是一直用java.util.Date用习惯了,也没有特意的去了解java8的时间类java.time,虽然效果同样达到了,但不是当前最适当的方式,以后要吸取教训。

在java8中,java.time包下主要包含下面几个主要的类:

Instant:时间戳,相当于java.util的Date

LocalDate:只包含日期,比如:2016-10-20

LocalTime:只包含时间,比如:23:12:10

LocalDateTime:包含日期和时间,比如:2016-10-20 23:14:21

Duration:计算两个“时间”的间隔

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

ZoneOffset:时区偏移量,比如:+8:00

ZonedDateTime:可以得到特定时区的日期/时间

Clock:时钟,比如获取目前美国纽约的时间

时间格式化以DateTimeFormatter代替SimpleDateFormat

DateTimeFormatter:时间格式化

方法前缀的含义,统一了api:

of:静态工厂方法(用类名去调用)。

parse:静态工厂方法,关注于解析(用类名去调用)。

now: 静态工厂方法,用当前时间创建实例(用类名去调用)

get:获取某些东西的值。

is:检查某些东西的是否是true。

with:返回一个部分状态改变了的时间日期对象拷贝(单独一个with方法,参数为TemporalAdjusters类型)。

plus:返回一个时间增加了的、时间日期对象拷贝(如果参数是负数也能够有minus方法的效果)。

minus:返回一个时间减少了的、时间日期对象拷贝。

to:把当前时间日期对象转换成另外一个,可能会损失部分状态。

at:把这个对象与另一个对象组合起来,例如: date.atTime(time)。

format :根据某一个DateTimeFormatter格式化为字符串。

通过以上一系列方法,java.time完成了加、减、格式化、解析、从日期/时间中提取单独部分等任务。

java.time包里面的类实例如果用了上面的方法而被修改了,那么会返回一个新的实例过来,而不像Calendar那样可以在同一个实例进行不同的修改,体现了不可变。

下面讲解具体的类

Instant :时间戳,相当于java.util的Date

Instant用于表示一个时间戳,它与我们常使用的System.currentTimeMillis()有些类似,不过Instant可以精确到纳秒(Nano-Second),System.currentTimeMillis()方法只精确到毫秒(Milli-Second)。如果查看Instant源码,发现它的内部使用了两个常量,seconds表示从1970-01-01 00:00:00开始到现在的秒数,nanos表示纳秒部分(nanos的值不会超过999,999,999)。Instant除了使用now()方法创建外,还可以通过ofEpochSecond方法创建:

Instant instant = Instant.ofEpochSecond(120, 100000);

ofEpochSecond()方法的第一个参数为秒,第二个参数为纳秒,上面的代码表示从1970-01-01 00:00:00开始后两分钟的10万纳秒的时刻,控制台上的输出为:

1970-01-01T00:02:00.000100Z

Duration : 计算两个“时间”的间隔

这个很好理解,看下面的了栗子就懂了

LocalDateTime from = LocalDateTime.of(2019, Month.JANUARY, 21, 15, 56, 0); // 2019-01-21 15:56:00

LocalDateTime to = LocalDateTime.of(2019, Month.FEBRUARY, 21, 15, 56, 0); // 2019-02-21 15:56:00

Duration duration = Duration.between(from, to); // 表示从 2019-01-21 15:56:00 到 2019-02-21 15:56:00

long days = duration.toDays(); // 这段时间的总天数

long hours = duration.toHours(); // 这段时间的小时数

long minutes = duration.toMinutes(); // 这段时间的分钟数

long seconds = duration.getSeconds(); // 这段时间的秒数

long milliSeconds = duration.toMillis(); // 这段时间的毫秒数

long nanoSeconds = duration.toNanos(); // 这段时间的纳秒数

Duration对象还可以通过of()方法创建,该方法接受一个时间段长度,和一个时间单位作为参数

Duration duration1 = Duration.of(5, ChronoUnit.DAYS); // 5天

Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS); // 1000毫秒

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

Period在概念上和Duration类似,区别在于Period是以年月日来衡量一个时间段,比如2年3个月6天

Period period = Period.of(2, 3, 6);

由于Period是以年月日衡量时间段,所以between()方法只能接收LocalDate类型的参数:

// 2019-01-21 到 2019-02-21 这段时间

Period period = Period.between(

LocalDate.of(2019, 1, 21),

LocalDate.of(2019, 2, 21));

ZoneId : 时区

获取所有合法的“区域/城市”字符串 :

Set zoneIds = ZoneId.getAvailableZoneIds();

获取系统默认时区 :

ZoneId systemZoneId = ZoneId.systemDefault();

创建时区 :

ZoneId shanghaiZoneId = ZoneId.of("Africa/Bangui");

LocalDateTime:包含日期和时间,比如:2016-10-20 23:14:21

获取当前时间 :

LocalDateTime localDateTime = LocalDateTime.now();//2019-01-21T16:15:52.863

创建特定日期 (多种自定义):

LocalDateTime localDateTime = LocalDateTime.of(2019,01,21,16,22,34);

获取获取年、月、日信息 :

LocalDateTime.now().getYear();//2019

LocalDateTime.now().getMonth();//JANUARY

LocalDateTime.now().getDayOfYear();//21

LocalDateTime.now().getDayOfMonth();//21

LocalDateTime.now().getDayOfWeek();//MONDAY

LocalDateTime.now().getHour();//16

能够自定义时间 :

LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);

System.out.println(time); //2017-01-01T01:01:01

//使用plus方法增加年份

//改变时间后会返回一个新的实例nextYearTime

LocalDateTime nextYearTime = time.plusYears(1);

System.out.println(nextYearTime); //2018-01-01T01:01:01

//使用minus方法减年份

LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);

LocalDateTime lastYearTime = time.minusYears(1);

System.out.println(lastYearTime); //2016-01-01T01:01:01

//使用with方法设置月份

LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);

LocalDateTime changeTime = time.withMonth(12);

System.out.println(changeTime); //2017-12-01T01:01:01

//判断当前年份是否闰年

System.out.println("isLeapYear :" + time.isLeapYear());

//判断当前日期属于星期几

LocalDateTime time = LocalDateTime.now();

DayOfWeek dayOfWeek = time.getDayOfWeek();

System.out.println(dayOfWeek); //WEDNESDAY

LocalDate和LocalTime与LocalDateTime类似,不多说

其他使用场景:

判断两个日期是否相等

LocalDate date1 = LocalDate.of(2019, 01, 21);

if(date1.equals(LocalDate.now())){

System.out.printf("Today %s and date1 %s are same date %n", LocalDate.now(), date1);

}

//输出:Today 2019-01-21 and date1 2019-01-21 are same date

检查像生日这种周期性事件

类似每月账单、结婚纪念日、保险缴费日这些周期性事件。使用MonthDay类。这个类组合了月份和日,去掉 了年,这意味着你可以用它判断每年都会发生事件。

LocalDate dateOfBirth = LocalDate.of(1993, 01, 21);

MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());

MonthDay currentMonthDay = MonthDay.from(LocalDate.now());

if(currentMonthDay.equals(birthday)){

System.out.println("Many Many happy returns of the day !!");

}else{

System.out.println("Sorry, today is not your birthday");

}

//输出: Many Many happy returns of the day !!

判断日期是早于还是晚于另一个日期

LocalDate tomorrow = LocalDate.of(2019, 1, 22);

if(tomorrow.isAfter(LocalDate.now())){

System.out.println("Tomorrow comes after today");//Tomorrow comes after today

}

LocalDate yesterday = LocalDate.now().minus(1, ChronoUnit.DAYS);

if(yesterday.isBefore(LocalDate.now())){

System.out.println("Yesterday is day before today");//Yesterday is day before today

}

java8 时间类与Date类的相互转化

//Date与Instant的相互转化

Instant instant = Instant.now();

Date date = Date.from(instant);

Instant instant2 = date.toInstant();

//Date转为LocalDateTime

Date date2 = new Date();

LocalDateTime localDateTime2 = LocalDateTime.ofInstant(date2.toInstant(), ZoneId.systemDefault());

//LocalDateTime转Date

LocalDateTime localDateTime3 = LocalDateTime.now();

Instant instant3 = localDateTime3.atZone(ZoneId.systemDefault()).toInstant();

Date date3 = Date.from(instant);

//LocalDate转Date

//因为LocalDate不包含时间,所以转Date时,会默认转为当天的起始时间,00:00:00

LocalDate localDate4 = LocalDate.now();

Instant instant4 = localDate4.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();

Date date4 = Date.from(instant);

日期的格式化和解析DateTimeFormatter

Java8的DateTimeFormatter也是线程安全的,而SimpleDateFormat并不是线程安全。

*DateTimeFormatter和SimpleDateFormat对比 *

Date转String

//使用Date和SimpleDateFormat

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("G yyyy年MM月dd号 E a hh时mm分ss秒");

String format = simpleDateFormat.format(new Date());

System.out.println(format);

//打印: 公元 2017年03月21号 星期二 下午 06时38分20秒

//使用jdk1.8 LocalDateTime和DateTimeFormatter

LocalDateTime now = LocalDateTime.now();

DateTimeFormatter pattern = DateTimeFormatter.ofPattern("G yyyy年MM月dd号 E a hh时mm分ss秒");

String format = now.format(pattern);

System.out.println(format);

//打印: 公元 2017年03月21号 星期二 下午 06时38分20秒

String转Date

//使用Date和SimpleDateFormat

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

Date date = simpleDateFormat.parse("2017-12-03 10:15:30");

System.out.println(simpleDateFormat.format(date));

//打印 2017-12-03 10:15:30

//使用jdk1.8 LocalDateTime和DateTimeFormatter

DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

//严格按照ISO yyyy-MM-dd验证,03写成3都不行

LocalDateTime dt = LocalDateTime.parse("2017-12-03 10:15:30",pattern);

System.out.println(dt.format(pattern));

使用SimpleDateFormat的正确姿势

方法一

在需要执行格式化的地方都新建SimpleDateFormat实例,使用局部变量来存放SimpleDateFormat实例

public static String formatDate(Date date)throws ParseException{

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

return sdf.format(date);

}

这种方法可能会导致短期内创建大量的SimpleDateFormat实例,如解析一个excel表格里的字符串日期。

方法二

为了避免创建大量的SimpleDateFormat实例,往往会考虑把SimpleDateFormat实例设为静态成员变量,共享SimpleDateFormat对象。这种情况下就得对SimpleDateFormat添加同步。

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public static String formatDate(Date date)throws ParseException{

synchronized(sdf){

return sdf.format(date);

}

}

这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。

方法三(推荐)

要在高并发环境下能有比较好的体验,可以使用ThreadLocal来限制SimpleDateFormat只能在线程内共享,这样就避免了多线程导致的线程安全问题。

private static ThreadLocal threadLocal = new ThreadLocal() {

@Override

protected DateFormat initialValue() {

return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

}

};

public static String format(Date date) {

return threadLocal.get().format(date);

}

//打印

public static void main(String[] args) {

System.out.println(format(new Date()));//2019-01-21

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值