3. 不稳定的 Calendar
  我们知道 Calendar 是能够被 serialize 的,可是我们要注意以下的问题
import java.io.*;
import java.util.*;
public class UnstableCalendar implements Serializable
{
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0 , 0);
cal1.set(Calendar.MILLISECOND, 0);
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("newCalendar.out"t);
out.writeObject(cal1);
out.close();
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("newCalendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
cal2.set(Calendar.MILLISECOND, 0);
System.out.println(cal2.getTime());
}
}
  执行的结果居然是: Thu Jan 01 00:00:00 PST 1970
  它被复原到 EPOC 的起始点,我们称该 Calendar 是处于不稳定状态。这个问题的根本原因是 Java 在 serialize GregorianCalendar 时没有保存全部的信息,所以当它被恢复到内存中,又缺少足够的信息时,Calendar 会被恢复到 EPOCH 的起始值。Calendar 对象由两部分构成:字段和相对于 EPOC 的微秒时间差。字段信息是由微秒时间差计算出的,而 set() 方法不会强制 Calendar 又一次计算字段。这样字段值不正确了。
  以下的代码能够解决问题:
import java.io.*;
import java.util.*;
public class StableCalendar implements Serializable
{
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0 , 0);
cal1.set(Calendar.MILLISECOND, 0);
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("newCalendar.out"t);
out.writeObject(cal1);
out.close();
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("newCalendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
cal2.get(Calendar.MILLISECOND); //先调用 get(),强制 Calendar 刷新
cal2.set(Calendar.MILLISECOND, 0);//再设值
System.out.println(cal2.getTime());
}
}
  执行的结果是: Tue Aug 01 00:00:00 PDT 2000
  这个问题主要会影响到在 EJB 编程中,?数对象中包括 Calendar 时。经过 Serialize/Deserialize 后,直接操作 Calendar 会产生不稳定的情况。
  4. add() 与 roll() 的差别
  add() 的功能很强大,add 能够对 Calendar 的字段进行计算。假设须要减去值,那么使用负数值能够了,如 add(field, -value)。
  add() 有两条规则:
  当被改动的字段超出它能够的范围时,那么比它大的字段会自己主动修正。如:
  Calendar cal1 = Calendar.getInstance();
  cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
  cal1.add(Calendar.MONTH, 1); //2000-9-31 => 2000-10-1,对吗?
  System.out.println(cal1.getTime()); //结果是 2000-9-30
  还有一个规则是,假设比它小的字段是不可变的(由 Calendar 的实现类决定),那么该小字段会修正到变化小的值。
  以上面的样例,9-31 会变成 9-30,由于变化小。
  Roll() 的规则仅仅有一条:
  当被改动的字段超出它能够的范围时,那么比它大的字段不会被修正。如:
  Calendar cal1 = Calendar.getInstance();
  cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
  cal1.roll(Calendar.WEEK_OF_MONTH, -1); //1999-6-1, 周二
  cal1.set(1999, 5, 6, 0, 0, 0); //1999-6-6, 周日
  cal1.add(Calendar.WEEK_OF_MONTH, -1); //1999-5-30, 周日
  WEEK_OF_MONTH 比 MONTH 字段小,所以 roll 不能修正 MONTH 字段。
  Date类介绍
  Data和Calendar类:
  一、创建一个日期对象r
  让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单样例. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间.
  import java.util.Date;
  public class DateExample1 {
  public static void main(String[] args) {
  // Get the system date/time
  Date date = new Date();
  System.out.println(date.getTime());
  }
  }
  在星期六, 2001年9月29日, 下午大约是6:50的样子, 上面的样例在系统输出设备上显示的结果是 1001803809710. 在这个样例中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受不论什么?数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期.假设用System.out.println(new Date());则输出形式为:Tue Nov 08 14:28:07 CST 2005
  那么, 如今我们已经知道了怎样获取从1970年1月1日?始经历的毫秒数了. 我们如何才干以一种用户明确的格式来显示这个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基类 java.text.DateFormat 派得上用场了.
  二、日期数据的定制格式
  假如我们希望定制日期数据的格式, 例如星期六-9月-29日-2001年. 以下的样例展
  示了怎样完毕这个工作:
  import java.text.SimpleDateFormat;
  import java.util.Date;
  public class DateExample2 {
  public static void main(String[] args) {
  SimpleDateFormat bartDateFormat =
  new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
  Date date = new Date();
  System.out.println(bartDateFormat.format(date));
  }
  }
  仅仅要通过向SimpleDateFormat 的构造函数传递格式字符串"EEE-MMMM-dd-yyyy",我们行指明自己想要的格式. 你应该可以看见, 格式字符串中的ASCII 字符告诉格式化函数以下显示日期数据的哪一个部分. EEEE是星期, MMMM是月, dd是日, yyyy是年. 字符的个数决定了日期是怎样格式化的.传递"EE-MM-dd-yy"会显示Sat-09-29-01. 请察看Sun 公司的Web 网站获取日期格式化选项的完整的指示.