Java8-日期和时间

  • 使用 LocalDateLocalTime
    LocalDate该类的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息。另外,它也不附带任何与时区相关的信息。可以通过静态工厂方法of创建一个LocalDate实例。
LocalDate date = LocalDate.of(2014, 3, 18);//2014-03-18
int year = date.getYear();//2014
Month month = date.getMonth();//MARCH
int day = date.getDayOfMonth();//18
DayOfWeek dow = date.getDayOfWeek();//TUESDAY
int len = date.lengthOfMonth();//31(这个月有多少天)
boolean leap = date.isLeapYear();//false(是不是闰年)

还可以使用工厂方法从系统时钟中获取当前的日期:

LocalDate today = LocalDate.now();   

这些日期-时间类,都提供了这些静态工厂方法,还可以通过传递一个TemporalField参数给get方法拿到同样的信息。TemporalField是一个接口,它定义了如何访问temporal对象某个字段的值。ChronoField枚举实现了这一接口,所以可以很方便地使用get方法得到枚举元素的值。(这些类都实现了Temporal接口,Temporal接口定义了如何读取和操纵为时间建模的对象的值。)


int year = date.get(ChronoField.YEAR);
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);

使用静态方法parse,LocalDateLocalTime都可以通过解析代表它们的字符串创建,一旦传递的字符串参数无法被解析为合法的LocalDateLocalTime对象,这两个parse方法都会抛出一个继承自RuntimeExceptionDateTimeParseException异常。

LocalDate date = LocalDate.parse("2014-03-18");
LocalTime time = LocalTime.parse("13:45:20"); 
  • 合并日期和时间
    这个复合类名叫LocalDateTime,是LocalDateLocalTime的合体。它同时表示了日期和时间,但不带有时区信息,可以直接创建,也可以通过合并日期和时间对象构造
// 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);

通过atTime或者atDate方法,向LocalDate传递一个时间对象,或者向LocalTime传递一个日期对象的方式,可以创建一个LocalDateTime对象。

也可以使用toLocalDate或者toLocalTime方法,从LocalDateTime中提取LocalDate或者LocalTime组件

LocalDate date1 = dt1.toLocalDate();
LocalTime time1 = dt1.toLocalTime(); 
  • 机器的日期和时间格式
    从计算机的角度来看,建模时间最自然的格式是表示一个持续时间段上某个点的单一大整型数。这也是新的java.time.Instant类对时间建模的方式,基本上它是以Unix元年时间(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的秒数进行计算。

    可以通过向静态工厂方法ofEpochSecond传递一个代表秒数的值创建一个该类的实例。静态工厂方法ofEpochSecond还有一个增强的重载版本,它接收第二个以纳秒为单位的参数值,对传入作为秒数的参数进行调整。重载的版本会调整纳秒参数,确保保存的纳秒分片在0到999 999999之间。

Instant.ofEpochSecond(3);
Instant.ofEpochSecond(3, 0);
Instant.ofEpochSecond(2, 1_000_000_000);//2秒之后加上100万纳秒(1秒)
Instant.ofEpochSecond(4, -1_000_000_000); 4秒之前100弯纳秒(1秒)

由于Instant类也支持静态工厂方法now,它能够帮你获取当前时刻的时间戳,但是,Instant的设计初衷是为了便于机器使用。它包含的是由秒及纳秒所构成的数字。所以,它无法处理那些我们非常容易理解的时间单位。

int day = Instant.now().get(ChronoField.DAY_OF_MONTH); 

会抛出如下异常:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field:
     DayOfMonth 
  • 定义DurationPeriod
    可以创建两个LocalTimes对象、两个LocalDateTimes对象,或者两个Instant对象之间的duration
    注意:LocalDateTimeInstant不能混用,否则会触发一个DateTimeException异常
Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
Duration d2 = Duration.between(instant1, instant2); 

以年、月或者日的方式对多个时间单位建模,可以使用Period类。使用该类的工厂方法between,可以得到两个LocalDate之间的时长,

Period tenDays = Period.between(LocalDate.of(2014, 3, 8),
                                LocalDate.of(2014, 3, 18)); 
image.png
image.png

以上这些日期-时间对象都是不可修改的,为了更好地支持函数式编程,确保线程安全。

  • 操纵、解析和格式化日期
  • 以相对直观的方式修改localDate属性
    若需要修改个LocalDate对象,withAttribute方法会创建对象的一个副本,并按照需要修改它的属性。(with方法也可以达到同样目的,它接受的第一个参数是一个TemporalField对象)
//所有的方法都返回一个修改了属性的对象。它们都不会修改原来的对象!
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.withYear(2011);
LocalDate date3 = date2.withDayOfMonth(25);
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);
  • 以相对方式修改localDate属性
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.plusWeeks(1);
LocalDate date3 = date2.minusYears(3);
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS); //2011-09-25

plus方法也是通用方法,它和minus方法都声明于Temporal接口中,通过这些方法,对TemporalUnit对象加上或者减去一个数字,能非常方便地将Temporal对象前溯或者回滚至某个时间段,通过ChronoUnit枚举可以非常方便地实现TemporalUnit接口。

image.png
  • 使用TemporalAdjuster
import static java.time.temporal.TemporalAdjusters.*;
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));//2014-03-18
LocalDate date3 = date2.with(lastDayOfMonth()); //2014-03-31
image.png

也可以自定义一个TemporalAdjuster接口

@FunctionalInterface
public interface TemporalAdjuster {
     Temporal adjustInto(Temporal temporal);
} 
TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(
     temporal -> {
         DayOfWeek dow =
               DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
         int dayToAdd = 1;
         if (dow == DayOfWeek.FRIDAY) dayToAdd = 3;
         if (dow == DayOfWeek.SATURDAY) dayToAdd = 2;
         return temporal.plus(dayToAdd, ChronoUnit.DAYS);
     });

    date = date.with(nextWorkingDay); 

ofDateAdjuster接受一个UnaryOperator的参数。

  • 解析日期-时间对象
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);//20140318 
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); //2014-03-18

使用工厂方法parse达到重创该日期对象的目的:

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

和老的java.util.DateFormat相比较,所有的DateTimeFormatter实例都是线程安全的。所以,你能够以单例模式创建格式器实例,就像DateTimeFormatter所定义的那些常量,并能在多个线程间共享这些实例。

也可以按照某个特定的模式创建格式器:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); 
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);//按照指定模式生成字符串
LocalDate date2 = LocalDate.parse(formattedDate, formatter); //利用同样的格式器解析生成的字符串

DateTimeFormatterBuilder类还提供了更复杂的格式器,你可以选择恰当的方法,一步一步地构造自己的格式器。同时,提供了强大的解析功能。

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

//处理不同的时区和使用不同的日历 12.3

你可能感兴趣的:(Java8-日期和时间)