java8 Date/Time API
history
- jdk1.0 只有java.util.Date类,Date中的月份从1开始,日期却从0开始
- jdk1.1 java.util.Calender类
- jdk1.8 java.time.*
Issues
- 线程安全(Thread Safety)
- api设计和易理解性(APIs Design and Ease of Understanding)
- 用本地和ZonedDate/Time API处理时区。
Use
LocalDate
a date in ISO format (yyyy-MM-dd)
- 获取当前时间
LocalDate localDate = LocalDate.now();
//localdate current: 2019-12-18
- 用of 或者parse 表示特定日期
LocalDate localDate = LocalDate.of(2015, 02, 20);//2015-02-20
LocalDate localDate = LocalDate.parse("2015-02-20");//2015-02-20
- 当前日期加一天
LocalDate tomorrow = LocalDate.now().plusDays(1);
- 当前日期减去一个月,接受枚举ChronoUnit作为单位时间
LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);
- 获取当前日期的年月日
DayOfWeek sunday = LocalDate.parse("2019-12-18").getDayOfWeek();//WEDNESDAY
int twelve = LocalDate.parse("2019-12-18").getDayOfMonth();//18
- 判断当前日期是否为闰年
boolean leapYear = LocalDate.now().isLeapYear();
- 判断日期是否在另一个日期之前或之后
boolean notBefore = LocalDate.parse("2016-06-12")
.isBefore(LocalDate.parse("2016-06-11"));//false
boolean isAfter = LocalDate.parse("2016-06-12")
.isAfter(LocalDate.parse("2016-06-11"));//true
- 给定日期的边界,一天(2019-12-18T00:00)或一个月的开始
LocalDateTime beginningOfDay = LocalDate.now().atStartOfDay();//2019-12-18T00:00
LocalDate firstDayOfMonth = LocalDate.now()
.with(TemporalAdjusters.firstDayOfMonth());//2019-12-01
LocalTime
time without a date
// 当前时间
LocalTime now = LocalTime.now();//10:36:24.494126800
// of
LocalTime localTime = LocalTime.of(6,30);//06:30
// parse 加一个小时
LocalTime sevenThirty = LocalTime.parse("06:30").plus(1,ChronoUnit.HOURS);//07:30
// 获取特定时间单位 时 分秒
int six = LocalTime.parse("06:30").getHour();//6
// 比较一个时间是否在另一个时间前后
boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));
// 一天中最大,最小,中午时间,数据库查询给定时间范围
LocalTime maxTime = LocalTime.MAX;//23:59:59.999999999
LocalTime maxTime = LocalTime.NOON;//12:00
LocalDateTime
a combination of date and time. 不考虑时区
日期和时间的组合时,这是最常用的类
- 获取时间
LocalDateTime localDateTime = LocalDateTime.now();
//2019-12-18T10:48:06.661236500
- of parse
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
//2015-02-20T06:30
LocalDateTime localDateTime = LocalDateTime.parse("2015-02-20T06:30:00");
//2015-02-20T06:30
- plus minus 加 减
LocalDateTime add = LocalDateTime.now().plusDays(1);
LocalDateTime minu = LocalDateTime.now().minusMonths(1);
- 获取年月日
Month month = LocalDateTime.now().getMonth();
ZonedDateTime API
// 时区
ZoneId zoneId = ZoneId.of("Europe/Paris");
// 获取所有时区
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
// 转化为特定的区域中 2019-12-18T11:05:54.112860700+01:00[Europe/Paris]
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
// 转换时间 instance
LocalDateTime localDateTime1 = LocalDateTime.ofInstant(zonedDateTime.toInstant(),ZoneId.systemDefault());
// 2015-02-20T13:30
// parse方法获取时区特定日期
ZonedDateTime zonedDateTime1 = ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");
本地日期时间加2小时,变为2015-02-20T06:30+02:00
LocalDateTime localDateTime1 = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
//2015-02-20T06:30
ZoneOffset zoneOffset = ZoneOffset.of("+02:00");// +02:00
OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime1,zoneOffset);
//2015-02-20T06:30+02:00
DateTime与Calendar转换
Calendar calendar = Calendar.getInstance();
dateTime = new DateTime(calendar);
时区转换
ZonedDateTime zonedDateTime = ZonedDateTime.now(romeZone);
ZoneId romeZone = ZoneId.of("Asia/Tokyo");
Period and Duration
Period类表示以年、月和日表示的时间量,Duration类表示以秒和纳秒表示的时间量.
Period
- 修改给定日期的值
LocalDate initialDate = LocalDate.parse("2017-05-10");
LocalDate finalDate = initialDate.plus(Period.ofDays(5));//2017-05-15
- 获取日期差
period 获取天数差的时候,是跑出年月的。2019-01-01 与2019-02-02 差1天
建议使用枚举ChronoUtils。2019-01-01 与2019-02-02 差2天。
int five = Period.between(initialDate, finalDate).getDays();// 5
long five = ChronoUnit.DAYS.between(initialDate,finalDate);// 5
Duration
- 修改给定时间
LocalTime initialTime = LocalTime.of(6, 30, 0);
LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));// 06:30:30
- 获取时间差
long thirty = Duration.between(initialTime,finalTime).getSeconds();// 30
long thirty = ChronoUnit.SECONDS.between(initialTime,finalTime);
Instant
LocalDateTime date = LocalDateTime.now();
ZoneId zoneId = ZoneId.of("Asia/Tokyo");
// 2019-12-18T15:55:04.517113900+09:00[Asia/Tokyo]
ZonedDateTime zonedDateTime = ZonedDateTime.of(date, zoneId);
// 2019-12-18T14:55:04.517113900 zonedDateTime.toInstant()
LocalDateTime localDateTime1 = LocalDateTime.ofInstant(date.toInstant(ZoneOffset.of("+09:00")),ZoneId.systemDefault());
// 秒转换
// 2016-06-13T11:34:50
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);
Format
LocalDateTime localDateTime1 = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
//2015-02-20T06:30
String localDateString = localDateTime2.format(DateTimeFormatter.ISO_DATE);
// 2015-01-25
String formatDate = localDateTime2.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));
//2015年1月25日 上午6:30:00
// FormatStyle.SHORT 2015/1/25 上午6:30
String formatDate2 = localDateTime2.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
//2015/01/25
Joda-Time
why use
- 解决线程问题,Joda Time使用不可变类来处理日期和时间。
- API干净流畅
dependency
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</dependency>
获取本地时间和日期对象
LocalDateTime currentDateAndTime = LocalDateTime.now();
LocalDate localDate = currentDateAndTime.toLocalDate();//2019-12-18
LocalTime localTime = currentDateAndTime.toLocalTime();// 16:40:54.602925500
DateTime
不可变类,它以毫秒级的精度封装时间上的某个瞬间时刻,用来替换JDK的Calendar类
- 设置时间
DateTime dt = new DateTime(2000, 11, 27, 0, 0, 0);
// 2000-11-27T00:00:00.000+08:00
dt = dt.withYear(2017);
// 2017-11-27T00:00:00.000+08:00
// 获取时间
dt.getyear()
String day3 = dt.dayOfWeek().getAsShortText(Locale.CHINESE); // 以指定格式获取
Instant
不可变类,代表时间线上的一个瞬时的时间点.
传统的设定为UTC时区1970年1月1日午夜时分
//获取当前时刻
Instant instant = new Instant();
Instant.now();
// 时间戳 1970-01-01T00:02:00.000100Z
Instant instant = Instant.ofEpochSecond(120,100000);
// 传递一个秒数已创建该类的实例
Instant.ofEpochSecond(3);
// 传递一个秒数+纳秒 2 秒之后再加上100万纳秒(1秒)
Instant.ofEpochSecond(2, 1_000_000_000);
BigDecimal
来对超过16位有效位的数进行精确的运算
构造方法
- BigDecimal(int) 创建一个具有参数所指定整数值的对象。
- BigDecimal(double) 创建一个具有参数所指定双精度值的对象。(不建议采用)
Double num = 123456789.98;
BigDecimal bg1=new BigDecimal(num);
BigDecimal bg2=new BigDecimal(num + "");
System.err.println(num);
System.err.println(bg1);
System.err.println(bg2);
1.2345678998E8
123456789.98000000417232513427734375
123456789.98
- BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
- BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象
加减乘除
- public BigDecimal add(BigDecimal value); //加法
- public BigDecimal subtract(BigDecimal value); //减法
- public BigDecimal multiply(BigDecimal value); //乘法
- public BigDecimal divide(BigDecimal value); //除法
BigDecimal a = new BigDecimal("4.5");
BigDecimal b = new BigDecimal("1.5");
System.out.println("a + b =" + a.add(b));
System.out.println("a - b =" + a.subtract(b));
System.out.println("a * b =" + a.multiply(b));
System.out.println("a / b =" + a.divide(b));
a + b =6.0
a - b =3.0
a * b =6.75
a / b =3
对货币和百分比格式化
BigDecimal bigLoanAmount = new BigDecimal("1.5"); //创建BigDecimal对象
BigDecimal bigInterestRate = new BigDecimal("1.5");
BigDecimal bigInterest = bigLoanAmount.multiply(bigInterestRate);
NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化用
percent.setMaximumFractionDigits(3); //百分比小数点最多3位
//利用BigDecimal对象作为参数在format()中调用货币和百分比格式化
System.out.println("Loan amount:\t" + currency.format(bigLoanAmount));
System.out.println("Interest rate:\t" + percent.format(bigInterestRate));
System.out.println("Interest:\t" + currency.format(bigInterest));
Loan amount: ¥1.50
Interest rate: 150%
Interest: ¥2.25
RFC 3339
- 所有日期和时间都假定在“当前时代”,公元000年到9999年之间。
- 不建议使用两位数时间
- 世界标准时间UTC