0%

JDK8-JODA实战

Java 8日期/时间( Date/Time)API是开发人员最受追捧的变化之一,Java从一开始就没有对日期时间处理的一致性方法,因此日期/时间API也是除Java核心API以外另一项倍受欢迎的内容。

为什么我们需要新的Java日期/时间API?

在开始研究Java 8日期/时间API之前,让我们先来看一下为什么我们需要这样一个新的API。在Java中,现有的与日期和时间相关的类存在诸多问题,其中有:

  1. Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。
  2. java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  3. 对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求。
  4. 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一。
  5. 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。

在现有的日期和日历类中定义的方法还存在一些其他的问题,但以上问题已经很清晰地表明:Java需要一个健壮的日期/时间类。这也是为什么Joda Time在Java日期/时间需求中扮演了高质量替换的重要角色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 获取当前时间
LocalDate localDate = LocalDate.now();

System.out.println(localDate);

System.out.println(localDate.getYear() + ", " + localDate.getMonthValue() + ", " + localDate.getDayOfMonth());

System.out.println("------------");

// 生成日期
LocalDate localDate2 = LocalDate.of(2017, 4, 8);
System.out.println(localDate2);

System.out.println("------------");


// 只关注月份和日期
LocalDate localDate3 = LocalDate.of(2010, 3, 25);
MonthDay monthDay = MonthDay.of(localDate3.getMonth(), localDate3.getDayOfMonth());
MonthDay monthDay2 = MonthDay.from(LocalDate.of(2011, 3, 25));

System.out.println(monthDay.equals(monthDay2));

System.out.println("------------");

// 时分秒
LocalTime time = LocalTime.now();
System.out.println(time);

LocalTime time2 = time.plusHours(3).plusMinutes(20);
System.out.println(time2);

System.out.println("------------");

LocalDate localDate1 = localDate.plus(2, ChronoUnit.WEEKS);

System.out.println(localDate1);

System.out.println("------------");

LocalDate localDate4 = localDate.minus(2, ChronoUnit.MONTHS);
System.out.println(localDate4);

System.out.println("------------");
Clock clock = Clock.systemDefaultZone();
System.out.println(clock.millis());

System.out.println("------------");

LocalDate localDate5 = LocalDate.now();
LocalDate localDate6 = LocalDate.of(2017, 4, 25);

System.out.println(localDate5.isAfter(localDate6));
System.out.println(localDate5.isBefore(localDate6));
System.out.println(localDate5.equals(localDate6));

System.out.println("------------");

Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
System.out.println(availableZoneIds);


System.out.println("------------");

ZoneId zoneId = ZoneId.of("Asia/Shanghai");

LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);

ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

System.out.println(zonedDateTime);

System.out.println("------------");

YearMonth yearMonth = YearMonth.now();
System.out.println(yearMonth);
System.out.println(yearMonth.lengthOfMonth());
System.out.println(yearMonth.isLeapYear());

System.out.println("------------");

YearMonth yearMonth1 = YearMonth.of(2016, 2);
System.out.println(yearMonth1);
System.out.println(yearMonth1.lengthOfMonth());
System.out.println(yearMonth1.lengthOfYear());
System.out.println(yearMonth1.isLeapYear());

System.out.println("------------");

LocalDate localDate7 = LocalDate.now();
LocalDate localDate8 = LocalDate.of(2017, 3, 25);
Period period = Period.between(localDate7, localDate8);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());

System.out.println("------------");

System.out.println(Instant.now());

时间差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 2014-03-18
LocalDate date = LocalDate.of(2014, 3, 18);
int year = date.getYear();
Month month = date.getMonth();
int day = date.getDayOfMonth();
DayOfWeek dow = date.getDayOfWeek();
int len = date.lengthOfMonth();
// 闰年
boolean leap = date.isLeapYear();
System.out.println(leap);

LocalDate today = LocalDate.now();

// TemporalField方式获取
year = date.get(ChronoField.YEAR);

// 时间
// 13:45:20
LocalTime time = LocalTime.of(13, 45, 20);
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();


// 从字符串转换
date = LocalDate.parse("2014-03-18");
time = LocalTime.parse("13:45:20");

// LocalDateTime
// 2014-03-18T13:45:20
LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(date, time);
LocalDateTime dt3 = date.atTime(13, 45, 20);
LocalDateTime dt4 = date.atTime(time);
LocalDateTime dt5 = time.atDate(date);

// 机器嗦理解的时间类Instant
Instant.ofEpochSecond(0);
// 2秒后加上一千秒
Instant.ofEpochSecond(2, 1_000);
Instant.now().toEpochMilli();

// 所有类都实现了Temporal接口, Temporal接口定义了如何读取和操纵为时间建模的对象的值

// Duration类主要用于以秒和纳秒恒衡量的时间的长短
Duration d1 = Duration.between(time, time.plusHours(1));
System.out.println(d1.getSeconds());
// Period则以年、月或日的方式对多个时间单位建模
Period tenDays = Period.between(LocalDate.of(2014, 3, 8), LocalDate.of(2014, 3, 18));
System.out.println(tenDays.getDays());
// Duration和Period还有一些工厂类
Duration threeMinutes = Duration.ofMinutes(3);
threeMinutes = Duration.of(3, ChronoUnit.MINUTES);

Period nineDays = Period.ofDays(9);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
System.out.println(dt1.plus(twoYearsSixMonthsOneDay));


// 取今天的0点
LocalDateTime localDateTime = LocalDate.now().atTime(0, 0, 0);
long beginOfDay = localDateTime.toEpochSecond(ZoneOffset.of("+08:00"));

System.out.println(localDateTime);
System.out.println(beginOfDay);

计算&格式化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// with是直接修改对应的属性
LocalDate date1 = LocalDate.of(2014, 3, 18);
// 2011-03-18
LocalDate date2 = date1.withYear(2011);
// 2011-03-25
LocalDate date3 = date2.withDayOfMonth(25);
// 2011-09-25
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);

// plus和minus是相对方式修改属性
// 2014-03-18
date1 = LocalDate.of(2014, 3, 18);
// 2014-03-25
date2 = date1.plusWeeks(1);
// 2011-03-25
date3 = date2.minusYears(3);
// 2011-09-25
date4 = date3.plus(6, ChronoUnit.MONTHS);

// 利用TemporalAdjuster进行复杂处理
date1 = LocalDate.of(2014, 3, 18);
// 下一个星期天 2014-03-23
date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
// 这个月最后一天 2014-03-31
date3 = date2.with(lastDayOfMonth());
// 只取工作日
date3 = date2.with(temporal -> {
DayOfWeek dow = DayOfWeek.of(temporal.get(DAY_OF_WEEK));
int dayToAdd = 1;
if (dow == DayOfWeek.FRIDAY) {
dayToAdd = 3;
} else if (dow == DayOfWeek.SATURDAY) {
dayToAdd = 2;
}
return temporal.plus(dayToAdd, DAYS);
});

TemporalAdjuster nextWorkingDay = ofDateAdjuster(temporal -> {
DayOfWeek dow = DayOfWeek.of(temporal.get(DAY_OF_WEEK));
int dayToAdd = 1;
if (dow == DayOfWeek.FRIDAY) {
dayToAdd = 3;
} else if (dow == DayOfWeek.SATURDAY) {
dayToAdd = 2;
}
return temporal.plus(dayToAdd, DAYS);
});

date2.with(nextWorkingDay);

// 格式化操作

LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);

date1 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
date2 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);

DateTimeFormatter italianFormatter =
DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.ITALIAN);

date1 = LocalDate.of(2014, 3, 18);
// 18. marzo 2014
String formattedDate = date.format(italianFormatter);
date2 = LocalDate.parse(formattedDate, italianFormatter);

italianFormatter = new DateTimeFormatterBuilder().appendText(ChronoField.DAY_OF_MONTH)
.appendLiteral(". ")
.appendText(ChronoField.MONTH_OF_YEAR)
.appendLiteral(" ")
.appendText(ChronoField.YEAR)
.parseCaseInsensitive()
.toFormatter(Locale.ITALIAN);

时区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ZoneId romeZone = ZoneId.of("Europe/Rome");
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);

LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);

Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);

// Instant instantFromDateTime = dateTime.toInstant(romeZone);
LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);

// 时区偏差
ZoneOffset newYourkOffset = ZoneOffset.of("-05:00");
OffsetDateTime dateTimeInNewYork = OffsetDateTime.of(dateTime, newYourkOffset);

MinguoDate minguoDate = MinguoDate.now();
System.out.println(minguoDate);