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>的参数。

  • 解析日期-时间对象
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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容