Java Time学习(2)

本篇文章,承接上文,主要介绍的是java 8中的时间API

参考JAVA 8:健壮、易用的时间/日期API这篇GitChat


JAVA 8

自从 Java 8 发布以后,古老的 java.util.Date 不再是我们 Java 里操作日期时间的唯一选择。Java 8 借鉴第三方开源库 Joda-Time 的优秀设计,重新设计了一套新的日期时间 API,这套新的日期 API 是 JSR-310 规范的实现。

需要强调的一点Java 8中的类基本上都是不可变得类,类似于String,不存在线程安全问题
JAVA 8 API中常用的类

  • LocalDate:表示不带时间的日期
  • LocalTime:表示不带日期的时间
  • LocalDateTime:日期和时间类
  • ZoneId:时区
  • ZonedDateTime:一个带时区的完整时间
  • Instant:Unix 时间,它代表的是时间戳,比如 2018-01-14T02:20:13.592Z
  • Clock:获取某个时区下当前的瞬时时间,日期或者时间
  • Duration:表示一个绝对的精确跨度,使用毫秒为单位
  • Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周
  • DateTimeFormatter:格式化输出
  • TemporalAdjusters:获得指定日期时间等,如当月的第一天、今年的最后一天等,比较复杂的时间操作

LocalDate、LocalTime、LocalDateTime

Java 8 中将日期和时间进行分离,LocalDate 是用来表示无时间的日期的,也不附带任何与时区相关的信息。
LocalTime 类关注时分秒,而 LocalDateTime是两者的结合体。
它们的实例都是一个不可变的对象,因此任何修改操作都会返回一个新的实例

@Test
	public void test4() {
		LocalDate date = LocalDate.of(2014, Month.JUNE, 10);
		int year = date.getYear(); // 2014
		Month month = date.getMonth(); // 6月
		int dom = date.getDayOfMonth(); // 10
		DayOfWeek dow = date.getDayOfWeek(); // 星期二
		int len = date.lengthOfMonth(); // 30 (6月份的天数)
		boolean leap = date.isLeapYear(); // false (不是闰年)
	}

	@Test
	public void test5() {
		LocalDate date = LocalDate.of(2019, Month.JANUARY, 10);
		date = date.withYear(2020);
		System.out.println(date);
		
		date = date.plusMonths(2);
		System.out.println(date);
		
		date = date.minusDays(1);
		System.out.println(date);
		//ChronoUnit 则用来表示这个时间单位
		date = date.plus(3, ChronoUnit.DAYS);
		System.out.println(date);
	}
	结果:
	2020-01-10
    2020-03-10
    2020-03-09
    2020-03-12
    
    /**
	 * LocalDate、LocalTime、LocalDateTime三个类组合方法
	 */
	@Test
	public void test8() {
		LocalDate date = LocalDate.of(2018,11,16);
		LocalTime time = LocalTime.of(12,23,20);
		LocalDateTime dateTime = LocalDateTime.of(date,time);
		System.out.println(dateTime);

		//LocalDate结合LocalTime成一个LocalDateTime
		LocalDateTime dateTime2 = date.atTime(time);
		System.out.println(dateTime2); //2018-11-16T12:23:20
	}
	结果:
	2018-11-16T12:23:20
    2018-11-16T12:23:20

LocalDateTime的其他方法跟LocalDate和LocalTime相似。这种相似的方法模式非常有利于API的学习。
下面总结了用到的方法前缀:

  • of: 静态工厂方法,从组成部分中创建实例
  • from: 静态工厂方法,尝试从相似对象中提取实例。from()方法没有of()方法类型安全
  • now: 静态工厂方法,用当前时间创建实例
  • parse: 静态工厂方法,总字符串解析得到对象实例
  • get: 获取时间日期对象的部分状态
  • is: 检查关于时间日期对象的描述是否正确
  • with: 返回一个部分状态改变了的时间日期对象拷贝
  • plus: 返回一个时间增加了的、时间日期对象拷贝
  • minus: 返回一个时间减少了的、时间日期对象拷贝
  • to: 把当前时间日期对象转换成另外一个,可能会损失部分状态
  • at: 用当前时间日期对象组合另外一个,创建一个更大或更复杂的时间日期对象
  • format: 提供格式化时间日期对象的能力

TemporalAdjuster

该类主要用于复杂的时间计算操作功能

	@Test
	public void test9() {
		LocalDate date = LocalDate.now();
		date = date.with(lastDayOfMonth());
		System.out.println(date);
		date = date.with(nextOrSame(WEDNESDAY));
		System.out.println(date);
		
	}
	
	2019-01-31
    2019-02-06

    import static java.time.DayOfWeek.WEDNESDAY;
    import static java.time.temporal.ChronoField.DAY_OF_MONTH;    
    
    @Test
	public void test12() {
		LocalDate localDate = LocalDate.now();
		TemporalAdjuster firstDayOfMonth = (temporal) -> temporal.with(DAY_OF_MONTH, 10);
		System.out.println(localDate.plusMonths(1).with(firstDayOfMonth));
		// 等价于下面语句
		System.out.println(localDate.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()));

		// 计算下一个工作日的日期
		TemporalAdjuster nextWorkDay = TemporalAdjusters.ofDateAdjuster(
		        tdate->{
		            DayOfWeek work = tdate.getDayOfWeek();
		            int addDays=0;
		            if (work.equals(DayOfWeek.FRIDAY)) {
		                addDays=3;
		            }else if(work.equals(DayOfWeek.SATURDAY)){
		                addDays=2;
		            }else {
		                addDays=1;
		            }
		            return tdate.plusDays(addDays);
		        }
		);

		LocalDate localDate1 = LocalDate.now().with(nextWorkDay);
		System.out.println(localDate1);
	}
	
	2019-02-10
    2019-02-01
    2019-01-11

Duration 与 Period

Duration 和 Period代表时间上的间隔,Duration代表间隔是以秒数位单位,而Period 的间隔是以年月日来衡量一个时间段

@Test
	public void test10() {
		LocalDateTime from = LocalDateTime.of(2018, Month.JANUARY, 5, 10, 7, 0);    // 2018-01-05 10:07:00
		LocalDateTime to = LocalDateTime.of(2018, Month.FEBRUARY, 5, 10, 7, 0);     // 2018-02-05 10:07:00
		Duration duration = Duration.between(from, to);     // 表示从 2018-01-05 10:07:00 到 2018-02-05 10:07:00 这段时间

		Duration d = Duration.ofSeconds(6000);  
		System.out.println("6000秒相当于" + d.toMinutes() + "分");  
		System.out.println("6000秒相当于" + d.toHours() + "小时");  
		System.out.println("6000秒相当于" + d.toDays() + "天");
		
		
		LocalDate start = LocalDate.of(2018, Month.JANUARY, 1);
		LocalDate end = LocalDate.of(2020, Month.NOVEMBER, 11);
		System.out.println("相隔月数:"+Period.between(start, end).getMonths());
		System.out.println("相隔天数:"+Period.between(start, end).getDays());
		
		/**
		 * Period 得到的是差值的绝对值(对应年月日直接计算数学上的差值),而并不表示真正的区间距离。
		 */
		long distanceMonth = start.until(end, ChronoUnit.MONTHS);
		long  distanceDay= start.until(end, ChronoUnit.DAYS);
		System.out.println(distanceMonth);
		System.out.println(distanceDay);
	}
	
	运行结果:
    6000秒相当于1006000秒相当于1小时
    6000秒相当于0天
    相隔月数:10
    相隔天数:10
    34
    1045
	

Instant

Instant 表示时间线上的一点(与 Date 类似),而不需要任何上下文信息,例如时区。概念上讲,它只是简单地表示自 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)开始的秒数。不提供处理人类意义上的时间单位

需要注意的是:这里存储的是与UTC1970的秒数间隔,其实我现在是2019-01-09早上10点,在UTC下的凌晨2点

@Test
	public void test11() {
		Instant instant1 = Instant.now();
		System.out.println(instant1); //1970-01-01T00:00:00Z

		Instant instant2 = Instant.parse("2018-11-11T10:12:35.342Z");
		System.out.println(instant2); //2018-11-11T10:12:35.342Z
		// 在instant3的基础上添加5小时4分钟
		Instant instant3 = instant2.plus(Duration.ofHours(5).plusMinutes(4));
		System.out.println(instant3); //2018-11-11T15:16:35.342Z

		//java.util.Date与Instant可相互转换
		Instant timestamp = new Date().toInstant();
		Date.from(Instant.now());
	}

2019-01-10T02:46:10.532Z
2018-11-11T10:12:35.342Z
2018-11-11T15:16:35.342Z

ZoneId 和 ZonedDateTime

Java 8 不仅将日期和时间进行了分离,同时还有时区。Java 使用 ZoneId 来标识不同的时区。
ZonedDateTime 是存储了与时区关联的 LocalDateTime

// 所有可用的zoneid
Set<String> zoneIds = ZoneId.getAvailableZoneIds(); 
//所有合法的“区域/城市”字符串
zoneIds.forEach(System.out::println);

ZoneId china = ZoneId.of("Asia/Shanghai");
ZonedDateTime dateAndTimeInChina = ZonedDateTime.of(LocalDateTime.now(), china);
System.out.println("特定时区下的日期和时间 : " + dateAndTimeInChina);

ZoneId america = ZoneId.of("America/New_York");
System.out.println(ZonedDateTime.now(america));

解析和格式化

java.time.format包是专门用来格式化输出时间/日期的。这个包围绕DateTimeFormatter类和它的辅助创建类DateTimeFormatterBuilder展开

静态方法加上DateTimeFormatter中的常量,是最通用的创建格式化器的方式。包括:

  • 常用ISO格式常量,如ISO_LOCAL_DATE
  • 字母模式,如ofPattern(“dd/MM/uuuu”)
  • 本地化样式,如ofLocalizedDate(FormatStyle.MEDIUM)
DateTimeFormatter f = DateTimeFormatter.ofPattern("dd/MM/uuuu");
LocalDate date = LocalDate.parse("24/06/2014", f);
String str = date.format(f);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值