Joda-Time 简介

本文将介绍并展示如何使用它。我将介绍以下主题:

日期/时间替代库简介
Joda 的关键概念
创建 Joda-Time 对象
以 Joda 的方式操作时间 style
以 Joda 的方式格式化时间
您可以 下载 演示这些概念的样例应用程序的源代码。

Joda 简介

为什么要使用 Joda?考虑创建一个用时间表示的某个随意的时刻 — 比如,2000 年 1 月 1 日 0 时 0 分。我如何创建一个用时间表示这个瞬间的 JDK 对象?使用 java.util.Date?事实上这是行不通的,因为自 JDK 1.1 之后的每个 Java 版本的 Javadoc 都声明应当使用 java.util.Calendar。Date 中不赞成使用的构造函数的数量严重限制了您创建此类对象的途径。

然而,Date 确实有一个构造函数,您可以用来创建用时间表示某个瞬间的对象(除 “现在” 以外)。该方法使用距离 1970 年 1 月 1 日子时格林威治标准时间(也称为 epoch)以来的毫秒数作为一个参数,对时区进行校正。考虑到 Y2K 对软件开发企业的重要性,您可能会认为我已经记住了这个值 — 但是我没有。Date 也不过如此。

那么 Calendar 又如何呢?我将使用下面的方式创建必需的实例:

Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);

使用 Joda,代码应该类似如下所示:

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);

这一行简单代码没有太大的区别。但是现在我将使问题稍微复杂化。假设我希望在这个日期上加上 90 天并输出结果。使用 JDK,我需要使用清单 1 中的代码:

清单 1. 以 JDK 的方式向某一个瞬间加上 90 天并输出结果

Calendar calendar = Calendar.getInstance();
calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
SimpleDateFormat sdf =
  new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.add(Calendar.DAY_OF_MONTH, 90);
System.out.println(sdf.format(calendar.getTime()));

使用 Joda,代码如清单 2 所示:

清单 2. 以 Joda 的方式向某一个瞬间加上 90 天并输出结果

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS");

两者之间的差距拉大了(Joda 用了两行代码,JDK 则是 5 行代码)。

现在假设我希望输出这样一个日期:距离 Y2K 45 天之后的某天在下一个月的当前周的最后一天的日期。坦白地说,我甚至不想使用 Calendar 处理这个问题。使用 JDK 实在太痛苦了,即使是简单的日期计算,比如上面这个计算。正是多年前的这样一个时刻,我第一次领略到 Joda-Time 的强大。使用 Joda,用于计算的代码如清单 3 所示:

清单 3. 改用 Joda

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");

清单 3 的输出为:

Sun 03/19/2000 00:00:00.000

如果您正在寻找一种易于使用的方式替代 JDK 日期处理,那么您真的应该考虑 Joda。如果不是这样的话,那么继续痛苦地使用 Calendar 完成所有日期计算吧。当您做到这一点后,您完全可以做到使用几把剪刀修建草坪并使用一把旧牙刷清洗您的汽车。

Joda 和 JDK 互操作性
JDK Calendar 类缺乏可用性,这一点很快就能体会到,而 Joda 弥补了这一不足。Joda 的设计者还做出了一个决定,我认为这是它取得成功的构建:JDK 互操作性。Joda 的类能够生成(但是,正如您将看到的一样,有时会采用一种比较迂回的方式)java.util.Date 的实例(和 Calendar)。这使您能够保留现有的依赖 JDK 的代码,但是又能够使用 Joda 处理复杂的日期/时间计算。

例如,完成 清单 3 中的计算后。我只需要做出如清单 4 所示的更改就可以返回到 JDK 中:

清单 4. 将 Joda 计算结果插入到 JDK 对象中

Calendar calendar = Calendar.getInstance();
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
  .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");
calendar.setTime(dateTime.toDate());

就是这么简单。我完成了计算,但是可以继续在 JDK 对象中处理结果。这是 Joda 的一个非常棒的特性。

Joda 的关键日期/时间概念

Joda 使用以下概念,它们可以应用到任何日期/时间库:

  • 不可变性(Immutability)
  • 瞬间性(Instant)
  • 局部性(Partial)
  • 年表(Chronology)
  • 时区(Time zone)
    我将针对 Joda 依次讨论每一个概念。

不可变性

我在本文讨论的 Joda 类具有不可变性,因此它们的实例无法被修改。(不可变类的一个优点就是它们是线程安全的)。我将向您展示的用于处理日期计算的 API 方法全部返回一个对应 Joda 类的新实例,同时保持原始实例不变。当您通过一个 API 方法操作 Joda 类时,您必须捕捉该方法的返回值,因为您正在处理的实例不能被修改。您可能对这种模式很熟悉;比如,这正是 java.lang.String 的各种操作方法的工作方式。

瞬间性

Instant 表示时间上的某个精确的时刻,使用从 epoch 开始计算的毫秒表示。这一定义与 JDK 相同,这就是为什么任何 Joda Instant 子类都可以与 JDK Date 和 Calendar 类兼容的原因。

更通用一点的定义是:一个瞬间 就是指时间线上只出现一次且唯一的一个时间点,并且这种日期结构只能以一种有意义的方式出现一次。

局部性

一个局部时间,正如我将在本文中将其称为局部时间片段一样,它指的是时间的一部分片段。瞬间性指定了与 epoch 相对的时间上的一个精确时刻,与此相反,局部时间片段指的是在时间上可以来回 “移动” 的一个时刻,这样它便可以应用于多个实例。比如,6 月 2 日 可以应用于任意一年的 6 月份(使用 Gregorian 日历)的第二天的任意瞬间。同样,11:06 p.m. 可以应用于任意一年的任意一天,并且每天只能使用一次。即使它们没有指定一个时间上的精确时刻,局部时间片段仍然是有用的。

我喜欢将局部时间片段看作一个重复周期中的一点,这样的话,如果我正在考虑的日期构建可以以一种有意义的方式出现多次(即重复的),那么它就是一个局部时间。

年表

Joda 本质 — 以及其设计核心 — 的关键就是年表(它的含义由一个同名抽象类捕捉)。从根本上讲,年表是一种日历系统 — 一种计算时间的特殊方式 — 并且是一种在其中执行日历算法的框架。受 Joda 支持的年表的例子包括:

ISO(默认)
Coptic
Julian
Islamic
Joda-Time 1.6 支持 8 种年表,每一种都可以作为特定日历系统的计算引擎。

时区

时区是值一个相对于英国格林威治的地理位置,用于计算时间。要了解事件发生的精确时间,还必须知道发生此事件的位置。任何严格的时间计算都必须涉及时区(或相对于 GMT),除非在同一个时区内发生了相对时间计算(即时这样时区也很重要,如果事件对于位于另一个时区的各方存在利益关系的话)。

DateTimeZone 是 Joda 库用于封装位置概念的类。许多日期和时间计算都可以在不涉及时区的情况下完成,但是仍然需要了解 DateTimeZone 如何影响 Joda 的操作。默认时间,即从运行代码的机器的系统时钟检索到的时间,在大部分情况下被使用。

创建 Joda-Time 对象

现在,我将展示在采用该库时会经常遇到的一些 Joda 类,并展示如何创建这些类的实例。
可变的 Joda 类

本节中介绍的所有实现都具有若干构造函数,允许您初始化封装的日期/时间。它们可以分为 4 个类别:

使用系统时间

使用多个字段指定一个瞬间时刻(或局部时间片段),达到这个特定实现所能支持的最细粒度的精确度。
指定一个瞬间时刻(或局部时间片段),以毫秒为单位。
使用另一个对象(例如,java.util.Date,或者是另一个 Joda 对象)。
我将在第一个类中介绍这些构造函数: DateTime。当您使用其他 Joda 类的相应构造函数时,也可以使用这里介绍的内容。

ReadableInstant

Joda 通过 ReadableInstant 类实现了瞬间性这一概念。表示时间上的不可变瞬间的 Joda 类都属于这个类的子类。(将这个类命名为 ReadOnlyInstant 可能更好,我认为这才是设计者需要传达的意思)。换句话说,ReadableInstant 表示时间上的某一个不可修改的瞬间)。其中的两个子类分别为 DateTime 和 DateMidnight:

DateTime:这是最常用的一个类。它以毫秒级的精度封装时间上的某个瞬间时刻。DateTime 始终与 DateTimeZone 相关,如果您不指定它的话,它将被默认设置为运行代码的机器所在的时区。
可以使用多种方式构建 DateTime 对象。这个构造函数使用系统时间:

DateTime dateTime = new DateTime();

一般来讲,我会尽量避免使用系统时钟来初始化应用程序的实际,而是倾向于外部化设置应用程序代码使用的系统时间。样例应用程序执行以下代码:
DateTime dateTime = SystemFactory.getClock().getDateTime();

这使得使用不同日期/时间测试我的代码变得更加简单:我不需要修改代码来在应用程序中运行不同的日期场景,因为时间是在 SystemClock 实现的内部设置的,而不是在应用程序的内部。(我可以修改系统时间,但是那实在太痛苦了!)
下面的代码使用一些字段值构建了一个 DateTime 对象:

DateTime dateTime = new DateTime(
  2000, //year
  1,    // month
  1,    // day
  0,    // hour (midnight is zero)
  0,    // minute
  0,    // second
  0     // milliseconds
);

正如您所见,Joda 可以使您精确地控制创建 DateTime 对象的方式,该对象表示时间上的某个特定的瞬间。每一个 Joda 类都有一个与此类似的构造函数,您在此构造函数中指定 Joda 类可以包含的所有字段。您可以用它快速了解特定类在哪一种粒度级别上操作。

下一个构造函数将指定从 epoch 到某个时刻所经过的毫秒数。它根据 JDK Date 对象的毫秒值创建一个 DateTime 对象,其时间精度用毫秒表示,因为 epoch 与 Joda 是相同的:

java.util.Date jdkDate = obtainDateSomehow();
long timeInMillis = jdkDate.getTime();
DateTime dateTime = new DateTime(timeInMillis);
并且这个例子与前例类似,唯一不同之处是我在这里将 Date 对象直接传递给构造函数:

java.util.Date jdkDate = obtainDateSomehow();
dateTime = new DateTime(jdkDate);
Joda 支持使用许多其他对象作为构造函数的参数,用于创建 DateTime,如清单 5 所示:

清单 5. 直接将不同对象传递给 DateTime 的构造函数

// Use a Calendar
java.util.Calendar calendar = obtainCalendarSomehow();
dateTime = new DateTime(calendar);
// Use another Joda DateTime
DateTime anotherDateTime = obtainDateTimeSomehow();
dateTime = new DateTime(anotherDateTime);
// Use a String (must be formatted properly)
String timeString = "2006-01-26T13:30:00-06:00";
dateTime = new DateTime(timeString);
timeString = "2006-01-26";
dateTime = new DateTime(timeString);

注意,如果您准备使用 String(必须经过解析),您必须对其进行精确地格式化。参考 Javadoc,获得有关 Joda 的 ISODateTimeFormat 类的更多信息(参见 参考资料)。

DateMidnight:这个类封装某个时区(通常为默认时区)在特定年/月/日的午夜时分的时刻。它基本上类似于 DateTime,不同之处在于时间部分总是为与该对象关联的特定 DateTimeZone 时区的午夜时分。
您将在本文看到的其他类都遵循与 ReadableInstant 类相同的模式(Joda Javadoc 将显示这些内容),因此为了节省篇幅,我将不会在以下小节介绍这些内容。

ReadablePartial

应用程序所需处理的日期问题并不全部都与时间上的某个完整时刻有关,因此您可以处理一个局部时刻。例如,有时您比较关心年/月/日,或者一天中的时间,甚至是一周中的某天。Joda 设计者使用 ReadablePartial 接口捕捉这种表示局部时间的概念,这是一个不可变的局部时间片段。用于处理这种时间片段的两个有用类分别为 LocalDate 和 LocalTime:

LocalDate:该类封装了一个年/月/日的组合。当地理位置(即时区)变得不重要时,使用它存储日期将非常方便。例如,某个特定对象的出生日期 可能为 1999 年 4 月 16 日,但是从技术角度来看,在保存所有业务值的同时不会了解有关此日期的任何其他信息(比如这是一周中的星期几,或者这个人出生地所在的时区)。在这种情况下,应当使用 LocalDate。
样例应用程序使用 SystemClock 来获取被初始化为系统时间的 LocalDate 的实例:

LocalDate localDate = SystemFactory.getClock().getLocalDate();

也可以通过显式地提供所含的每个字段的值来创建 LocalDate:

LocalDate localDate = new LocalDate(2009, 9, 6);// September 6, 2009

LocalDate 替代了在早期 Joda 版本中使用的 YearMonthDay。

LocalTime:这个类封装一天中的某个时间,当地理位置不重要的情况下,可以使用这个类来只存储一天当中的某个时间。例如,晚上 11:52 可能是一天当中的一个重要时刻(比如,一个 cron 任务将启动,它将备份文件系统的某个部分),但是这个时间并没有特定于某一天,因此我不需要了解有关这一时刻的其他信息。
样例应用程序使用 SystemClock 获取被初始化为系统时间的 LocalTime 的一个实例:

LocalTime localTime = SystemFactory.getClock().getLocalTime();

也可以通过显式地提供所含的每个字段的值来创建 LocalTime:

LocalTime localTime = new LocalTime(13, 30, 26, 0);// 1:30:26PM

时间跨度

了解特定的时刻或是某个局部时间片段将非常有用,但是如果能够表达一段时间跨度的话,通常也很有用。Joda 提供了三个类来简化这个过程。您可以选择用于表示不同跨度的类:

Duration:这个类表示一个绝对的精确跨度,使用毫秒为单位。这个类提供的方法可以用于通过标准的数学转换(比如 1 分钟 = 60 秒,1 天 = 24 小时),将时间跨度转换为标准单位(比如秒、分和小时)。
您只在以下情况使用 Duration 的实例:您希望转换一个时间跨度,但是您并不关心这个时间跨度在何时发生,或者使用毫秒处理时间跨度比较方便。

Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周。
您可以在以下情况使用 Period:您并不关心这段时期必须在何时发生,或者您更关心检索单个字段的能力,这些字段描述由 Period 封装的时间跨度。

Interval:这个类表示一个特定的时间跨度,将使用一个明确的时刻界定这段时间跨度的范围。Interval 为半开 区间,这表示由 Interval 封装的时间跨度包括这段时间的起始时刻,但是不包含结束时刻。
可以在以下情况使用 Interval:需要表示在时间连续区间中以特定的点开始和结束的一段时间跨度。

更多见:https://www.ibm.com/developerworks/cn/java/j-jodatime.html

代码

引入 joda-time.jar/log4j.jar:

package com.makotogroup.util.time;
interface SystemClock :

package com.makotogroup.util.time;

import java.util.Calendar;
import java.util.Date;

import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;

/**
 * Serves as a wrapper for the system clock to be used by applications
 * to retrieve the system time, rather than System.currentTimeMillis().
 * This allows us to set arbitrary times to exercise application logic
 * without having to alter the system time to do so.
 * 
 * @author steve
 *
 */
public interface SystemClock {
  /**
   * Retrieve the system time in milliseconds
   * 
   * @return - long - the number of milliseconds since the epoc that
   * represents the system time. This is consistent with the JDK
   * definition of time.
   */
  public long getTimeInMillis();
  /**
   * Retrieve the system time as a Joda DateTime object.
   *  
   * @return - DateTime - a Joda DateTime object that contains the
   * system time.
   */
  public DateTime getDateTime();
  /**
   * Retrieve the system time as a Joda DateMidnight object.
   * 
   * @return - DateMidnight - a Joda DateMidnight object that contains
   * the system time.
   */
  public DateMidnight getDateMidnight();
  /**
   * Retrieve the system time as a Joda LocalDate object.
   * 
   * @return - LocalDate - a Joda LocalDate object that contains
   * the system time.
   */
  public LocalDate getLocalDate();
  /**
   * Retrieve the system time as a Joda LocalTime object.
   * 
   * @return - LocalTime - a Joda LocalTime object that contains
   * the system time.
   */
  public LocalTime getLocalTime();
  /**
   * Retrieve the system time as a JDK Date object.
   * 
   * @return - Date - the system time as JDK Date
   */
  public Date getDate();
  /**
   * Retrieve the system time as a JDK Calendar object.
   * 
   * @return - Calendar - the system time as JDK Calendar
   */
  public Calendar getCalendar();
}

package com.makotogroup.util.time;
class HardcodedSystemClock implements SystemClock:


public class HardcodedSystemClock implements SystemClock {

  /**
   * Hardcode the date time here. It will be used as the "Sytem Time"
   * for all code that use the SystemClock interface, where this implementation
   * is the one returned by SystemFactory.getClock().
   */
  // This instance set to 7/30/2018 8:00am
  private static final DateTime theDateTime = new DateTime(2018, 7, 30, 14, 30, 0, 0);

  public DateTime getDateTime() {
    return theDateTime;
  }

  public long getTimeInMillis() {
    return theDateTime.getMillis();
  }

  public DateMidnight getDateMidnight() {
    return theDateTime.toDateMidnight();
  }

  public LocalDate getLocalDate() {
    return theDateTime.toLocalDate();
  }

  public LocalTime getLocalTime() {
    return theDateTime.toLocalTime();
  }

  public Calendar getCalendar() {
    return theDateTime.toCalendar(Locale.getDefault());
  }

  public Date getDate() {
    return theDateTime.toDate();
  }

}

package com.makotogroup.joda.factory;
class SystemFactory:

package com.makotogroup.joda.factory;

import com.makotogroup.util.time.HardcodedSystemClock;
import com.makotogroup.util.time.SystemClock;

/**
 * A simple factory for retrieving system objects.
 * 
 * @author steve
 *
 */
public final class SystemFactory {
  /**
   * Return an implementation of SystemClock to represent the system
   * clock for application code.
   * 
   * @return SystemClock - an implementation of SystemClock.
   */
  public static SystemClock getClock() {
    // Currently set to HardcodedSystemClock...
    return new HardcodedSystemClock();
  }
}

CreatingJodaTimeObjects :

package com.makotogroup.joda;

import java.util.Calendar;
import java.util.Date;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;

import com.makotogroup.joda.factory.SystemFactory;

public class CreatingJodaTimeObjects {
  private static Logger log = Logger.getLogger(CreatingJodaTimeObjects.class);
  public static void main(String[] args) {

    example2_1();
    example2_2(); 
    example2_3();
    example2_4();
    example2_5();

  }

  private static void example2_1() {
    DateTime dateTime = new DateTime();
    log.info("Using system clock: " + dateTime.toString());
    dateTime = SystemFactory.getClock().getDateTime();
    log.info("Using (better) system clock: " + dateTime.toString());
  }

  private static void example2_2() {
    DateTime dateTime = new DateTime(
        2000, //year
        1,    // month
        1,    // day
        0,    // hour (midnight is zero)
        0,    // minute
        0,    // second
        0     // milliseconds
      );
    log.info("Using explicit field values: " + dateTime.toString());
  }

  private static void example2_3() {
    java.util.Date jdkDate = obtainDateSomehow();
    long timeInMillis = jdkDate.getTime();
    DateTime dateTime = new DateTime(timeInMillis);
    log.info("Using a Date object's millisecond value: " + dateTime.toString());
  }

  private static Date obtainDateSomehow() {
    return SystemFactory.getClock().getDate();
  }
  private static Calendar obtainCalendarSomehow() {
    return SystemFactory.getClock().getCalendar();
  }
  private static DateTime obtainDateTimeSomehow() {
    return SystemFactory.getClock().getDateTime();
  }

  private static void example2_4() {
    java.util.Date jdkDate = obtainDateSomehow();
    DateTime dateTime = new DateTime(jdkDate.getTime());    
    log.info("Using a Date object directly: " + dateTime.toString());
  }
  private static void example2_5() {
    // Use a Calendar
    java.util.Calendar calendar = obtainCalendarSomehow();
    DateTime dateTime = new DateTime(calendar);
    log.info("Using a Calendar object directly: " + dateTime.toString());
    // Use another Joda DateTime
    DateTime anotherDateTime = obtainDateTimeSomehow();
    dateTime = new DateTime(anotherDateTime);
    log.info("Using another DateTime object: " + dateTime.toString());
    // Use a String (must be formatted properly)
    String timeString = "2006-01-26T13:30:00-06:00";
    dateTime = new DateTime(timeString);
    log.info("Using a String: " + dateTime.toString());

    timeString = "2006-01-26";
    dateTime = new DateTime(timeString);
    log.info("Using a String: " + dateTime.toString());    
  }
}

FormattingTime :

package com.makotogroup.joda;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;

import com.makotogroup.joda.factory.SystemFactory;

public class FormattingTime {
  private static Logger log = Logger.getLogger(FormattingTime.class);
  public static void main(String[] args) {

    example4_1();
    example4_2();

  }

  private static void example4_1() {
    DateTime dateTime = SystemFactory.getClock().getDateTime();
    log.info("Using ISODateTimeFormat.basicDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicDateTime())
    );
    log.info("Using ISODateTimeFormat.basicDateTimeNoMillis: " + 
        dateTime.toString(ISODateTimeFormat.basicDateTimeNoMillis())
    );
    log.info("Using ISODateTimeFormat.basicOrdinalDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicOrdinalDateTime())
    );
    log.info("Using ISODateTimeFormat.basicWeekDateTime: " + 
        dateTime.toString(ISODateTimeFormat.basicWeekDateTime())
    );
  }

  private static void example4_2() {
    DateTime dateTime = SystemFactory.getClock().getDateTime();
    log.info("Using MM/dd/yyyy hh:mm:ss.SSSa: " + 
        dateTime.toString("MM/dd/yyyy hh:mm:ss.SSSa")
    );
    log.info("Using dd-MM-yyyy HH:mm:ss: " + 
        dateTime.toString("dd-MM-yyyy HH:mm:ss")
    );
    log.info("Using EEEE dd MMMM, yyyy HH:mm:ss: " + 
        dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ss")
    );
    log.info("Using MM/dd/yyyy HH:mm ZZZZ: " + 
        dateTime.toString("MM/dd/yyyy HH:mm ZZZZ")
    );
    log.info("Using MM/dd/yyyy HH:mm Z: " + 
        dateTime.toString("MM/dd/yyyy HH:mm Z")
    );
  }
}

KeyConcepts:

package com.makotogroup.joda;

import java.text.SimpleDateFormat;
import java.util.Calendar;

import org.joda.time.DateTime;

public class KeyConcepts {
  public static void main(String[] args) {
    example1_1();
    example1_2();
    example1_3();
    example1_4();
  }

  private static void example1_1() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
    SimpleDateFormat sdf = new SimpleDateFormat("E MM/dd/yyyy HH:mm:ss.SSS");
    calendar.add(Calendar.DAY_OF_MONTH, 90);
    System.out.println(sdf.format(calendar.getTime()));
  }

  private static void example1_2() {
    DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
    System.out.println(dateTime.plusDays(90).toString("E MM/dd/yyyy HH:mm:ss.SSS"));
  }

  private static void example1_3() {
    DateTime dt = new DateTime(2000, 1, 1, 0, 0, 0, 0);
    System.out.println(
        dt.plusDays(45)
          .plusMonths(1)
          .dayOfWeek()
          .withMaximumValue()
          .toString("E MM/dd/yyyy HH:mm:ss.SSS"));    
  }

  private static void example1_4() {
    Calendar calendar = Calendar.getInstance();
    DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
    System.out.println(dateTime.plusDays(45).plusMonths(1).dayOfWeek()
      .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS"));
    calendar.setTime(dateTime.toDate());    
  }
}

ManipulatingTime :

package com.makotogroup.joda;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import org.apache.log4j.Logger;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;

import com.makotogroup.joda.factory.SystemFactory;

public class ManipulatingTime {
  private static Logger log = Logger.getLogger(ManipulatingTime.class);
  public static void main(String[] args) {

    example3_1();
    example3_2();
    example3_3();
    example3_4();
    example3_5();
    example3_6();
    example3_7();

  }

  private static void example3_1() {
    LocalDate now = SystemFactory.getClock().getLocalDate();
    log.info("Now:" + now.toString());
    LocalDate lastDayOfPreviousMonth = now.minusMonths(1).dayOfMonth().withMaximumValue();
    log.info("Then: " + lastDayOfPreviousMonth.toString());
  }

  private static void example3_2() {
    LocalDate now = SystemFactory.getClock().getLocalDate();
    log.info("Now:" + now.toString());
    LocalDate electionDate = now.monthOfYear()
     .setCopy(11)        // November
     .dayOfMonth()       // Access Day Of Month Property
     .withMinimumValue() // Get its minimum value
     .plusDays(6)        // Add 6 days
     .dayOfWeek()        // Access Day Of Week Property
     .setCopy("Monday")  // Set to Monday (it will round down)
     .plusDays(1);       // Gives us Tuesday
    log.info("Then:" + electionDate.toString());
  }

  private static void example3_3() {
    DateTime now = SystemFactory.getClock().getDateTime();
    log.info("Now:" + now.toString());
    DateTime tomorrow = now.plusDays(1);
    DateTime then = tomorrow.plusDays(90);
    log.info("Then:" + then.toString());
  }

  private static void example3_4() {
    DateTime now = SystemFactory.getClock().getDateTime();
    log.info("Now:" + now.toString());
    DateTime then = now.plusWeeks(2);
    log.info("Then:" + then.toString());
  }

  private static void example3_5() {
    DateTime now = SystemFactory.getClock().getDateTime();
    log.info("Now:" + now.toString());
    DateTime then = now.plusSeconds(156);
    log.info("Then:" + then.toString());
  }

  private static void example3_6() {
    DateTime now = SystemFactory.getClock().getDateTime();
    log.info("Now:" + now.toString());
    DateTime then = now.minusYears(5)
                   .monthOfYear()
                   .setCopy(2)
                   .dayOfMonth()
                   .withMaximumValue();    
    log.info("Then:" + then.toString());    
  }

  private static void example3_7() {
    DateTime dateTime = SystemFactory.getClock().getDateTime();
    log.info("DateTime:" + dateTime.toString());
    Calendar calendar = dateTime.toCalendar(Locale.getDefault());
    SimpleDateFormat sdf = new SimpleDateFormat();
    log.info("As Calendar:" + sdf.format(calendar.getTime()));
    Date date = dateTime.toDate();
    log.info("As Date:" + sdf.format(date));
    DateMidnight dateMidnight = SystemFactory.getClock()
      .getDateMidnight();
    date = dateMidnight.toDate();
    log.info("As Date (from DateMidnight):" + sdf.format(date));
  }

}

https://www.ibm.com/developerworks/cn/java/j-jodatime.html#artdownload

原文地址:https://www.cnblogs.com/DiZhang/p/12544961.html