Joda-Time简介(二)

引用文章:

Joda-Time简介

快速入门指南(英文)

官方API(2.9.7)


以 Joda 的方式处理时间

现在,您已经了解了如何创建一些非常有用的 Joda 类,我将向您展示如何使用它们执行日期计算。接着您将了解到 Joda 如何轻松地与 JDK 进行互操作。

日期计算

如果您只是需要对日期/时间信息使用占位符,那么 JDK 完全可以胜任,但是它在日期/时间计算方面的表现十分糟糕,而这正是 Joda 的长处。我将向您展示一些简单的例子。
假设在当前的系统日期下,我希望计算上一个月的最后一天。对于这个例子,我并不关心一天中的时间,因为我只需要获得年/月/日。

//获取当前日期
    LocalDate now = new LocalDate();
    System.out.println(now.toString());
    //1.减去一个月。2.得到月的天数属性。3.得到最后一天
    LocalDate lastDayOfPreviousMonth = now.minusMonths(1).dayOfMonth().withMaximumValue();
    System.out.println(lastDayOfPreviousMonth.toString());

您可能对dayOfMonth() 调用感兴趣。这在 Joda 中被称为属性(property)。它相当于 Java 对象的属性。属性是根据所表示的常见结构命名的,并且它被用于访问这个结构,用于完成计算目的。属性是实现 Joda 计算威力的关键。您目前所见到的所有 4 个 Joda 类都具有这样的属性。一些例子包括:

yearOfCentury

dayOfYear

monthOfYear

dayOfMonth

dayOfWeek

首先,我从当前月份减去一个月,得到 “上一个月”。接着,我要求获得 dayOfMonth 的最大值,它使我得到这个月的最后一天。注意,这些调用被连接到一起(注意 Joda ReadableInstant 子类是不可变的),这样您只需要捕捉调用链中最后一个方法的结果,从而获得整个计算的结果。
当计算的中间结果对我不重要时,我经常会使用这种计算模式。(我以相同的方式使用 JDK 的 BigDecimal(高精度数值计算))

假设您希望获得任何一年中的第 11 月的第一个星期二的日期,而这天必须是在这个月的第一个星期一之后。

 LocalDate now = new LocalDate();
    System.out.println("Now:" + now.toString());
    LocalDate electionDate = now.monthOfYear()
     .setCopy(11)        // 11月
     .dayOfMonth()       // 获取dayOfMonth属性
     .withMinimumValue() // 获取它的第一天
     .plusDays(6)        // 接着增加六天
     .dayOfWeek()        // 获取Day Of Week属性
     .setCopy("1")  // 设置11月1日至7日中星期一的那天为日期
     .plusDays(1);       // 增加一天就是星期二了
    System.out.println("Then:" + electionDate.toString());

在上面例子中,setCopy()需要根据系统时间所在的时区来设置不同的值。在国外 周一 可能需要用“Monday”,在中国,“1”表示周一,以此类推。如果在中国使用“Monday”将会抛出 org.joda.time.IllegalFieldValueException。
.setCopy("1") 是整个计算的关键。不管中间 LocalDate 值是多少,将其 dayOfWeek属性设置为 1总是能够从7天中获取到,这样的话,在每月的开始再加上 6 天就能够让您得到第一个星期一。再加上一天就得到第一个星期二。

以下代码计算从现在开始经过两个星期之后的日期:
DateTime now = new LocalDate();
    System.out.println("example3_4-Now:" + now.toString());
    DateTime then = now.plusWeeks(2);
    System.out.println("example3_4-Then:" + then.toString());
您可以以这种方式计算从明天起 90 天以后的日期:
DateTime now = new DateTime();
    System.out.println("example3_3-Now:" + now.toString());
    DateTime tomorrow = now.plusDays(1);
    DateTime then = tomorrow.plusDays(90);
    System.out.println("example3_3-Then:" + then.toString());
下面是计算从现在起 156 秒之后的时间:
DateTime now = new DateTime();
    DateTime then = now.plusSeconds(156);

JDK 互操作性

我的许多代码都使用了 JDK Date 和 Calendar 类。但是幸亏有 Joda,我可以执行任何必要的日期算法,然后再转换回 JDK 类。这将两者的优点集中到一起。您在本文中看到的所有 Joda 类都可以从 JDK Calendar 或 Date 创建,正如您在 创建 Joda-Time 对象 中看到的那样。出于同样的原因,可以从您所见过的任何 Joda 类创建 JDK Calendar 或 Date。
从 Joda ReadableInstant 子类转换为 JDK 类有多么简单:

DateTime dateTime = new DateTime();
    System.out.println("DateTime:" + dateTime.toString());
    Calendar calendar = dateTime.toCalendar(Locale.getDefault());
    SimpleDateFormat sdf = new SimpleDateFormat();
    System.out.println("作为 Calendar:" + sdf.format(calendar.getTime()));
    Date date = dateTime.toDate();
    System.out.println("作为 Date:" + sdf.format(date));
    DateMidnight dateMidnight = SystemFactory.getClock()
      .getDateMidnight();
    date = dateMidnight.toDate();
    System.out.println("作为 Date (from DateMidnight):" + sdf.format(date));
对于 ReadablePartial 子类,您还需要经过额外一步
LocalDate localDate = new LocalDate();
    Date date = localDate.toDateMidnight().toDate();
要创建 Date 对象,它表示从清单 9 所示的 SystemClock 中获得的 LocalDate,您必须首先将它转换为一个 DateMidnight 对象,然后只需要将 DateMidnight 对象作为 Date。(当然,产生的 Date 对象将把它自己的时间部分设置为午夜时刻)。
JDK 互操作性被内置到 Joda API 中,因此您无需全部替换自己的接口,如果它们被绑定到 JDK 的话。比如,您可以使用 Joda 完成复杂的部分,然后使用 JDK 处理接口。

以 Joda 方式格式化时间

使用 JDK 格式化日期以实现打印是完全可以的,但是我始终认为它应该更简单一些。这是 Joda 设计者进行了改进的另一个特性。要格式化一个 Joda 对象,调用它的 toString() 方法,并且如果您愿意的话,传递一个标准的 ISO-8601(标准日期表示法) 或一个 JDK 兼容的控制字符串,以告诉 JDK 如何执行格式化。不需要创建单独的 SimpleDateFormat 对象(但是 Joda 的确为那些喜欢自找麻烦的人提供了一个 DateTimeFormatter类)。调用 Joda 对象的 toString() 方法,仅此而已。我将展示一些例子。

使用 ISO-8601

DateTime dateTime = new DateTime();
    //基本日期时间
    System.out.println("Using ISODateTimeFormat.basicDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicDateTime())
    );
    //不包含毫秒的日期时间
    System.out.println("Using ISODateTimeFormat.basicDateTimeNoMillis: " + 
        dateTime.toString(ISODateTimeFormat.basicDateTimeNoMillis())
    );
    //基本的原始日期时间
    System.out.println("Using ISODateTimeFormat.basicOrdinalDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicOrdinalDateTime())
    );
    //基本的年和周组合时间
    System.out.println("Using ISODateTimeFormat.basicWeekDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicWeekDateTime())
    );
打印结果:
Using ISODateTimeFormat.basicDateTime: 20170117T222546.170+0800
Using ISODateTimeFormat.basicDateTimeNoMillis: 20170117T222546+0800
Using ISODateTimeFormat.basicOrdinalDateTime: 2017017T222546.170+0800
Using ISODateTimeFormat.basicWeekDateTime: 2017W032T222546.170+0800

使用与 JDK 兼容的格式字符串

DateTime dateTime = new DateTime();
    System.out.println("Using yyyy/MM/d hh:mm:ss.SSSa: " + 
        dateTime.toString("yyyy/MM/dd hh:mm:ss.SSSa")
    );
    System.out.println("Using yyyy.MM.dd HH:mm:ss: " + 
        dateTime.toString("yyyy.MM.dd HH:mm:ss")
    );
    System.out.println("Using yyyy-MM-dd, yyyy HH:mm:ss: " + 
        dateTime.toString("yyyy-MM-dd, yyyy HH:mm:ss")
    );
    System.out.println("Using yyyy-MM-dd HH:mm ZZZZ: " + 
        dateTime.toString("yyyy-MM-dd HH:mm ZZZZ")
    );
    System.out.println("Using yyyy-MM-dd HH:mm Z: " + 
        dateTime.toString("yyyy-MM-dd HH:mm Z")
    );
    System.out.println("Using yyyy-MM-dd HH:mm Z: " + 
        dateTime.toString("yyyy-MM-dd HH:mm Z")
    );
打印:
Using yyyy/MM/d hh:mm:ss.SSSa: 2017/01/17 10:49:21.384下午
Using yyyy.MM.dd HH:mm:ss: 2017.01.17 22:49:21
Using yyyy-MM-dd, yyyy HH:mm:ss: 2017-01-17, 2017 22:49:21
Using yyyy-MM-dd HH:mm ZZZZ: 2017-01-17 22:49 +08:00
Using yyyy-MM-dd HH:mm Z: 2017-01-17 22:49 +0800
Using yyyy-MM-dd HH:mm Z: 2017-01-17 22:49 +0800

结束语

谈到日期处理,Joda 是一种令人惊奇的高效工具。无论您是计算日期、打印日期,或是解析日期,Joda 都将是工具箱中的便捷工具。在本文中,我首先介绍了 Joda,它可以作为 JDK 日期/时间库的替代选择。然后介绍了一些 Joda 概念,以及如何使用 Joda 执行日期计算和格式化。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值