(在文章的最后,将会介绍Date类,假设有兴趣,能够直接翻到最后去阅读)

到底什么是一个 Calendar 呢?中文的翻译就是日历,那我们立马能够想到我们生活中有阳(公)历、阴(农)历之分。它们的差别在哪呢?

比方有:
月份的定义 - 阳`(公)历 一年12 个月,每一个月的天数各不同;阴(农)历,每一个月固定28天
每周的第一天 - 阳(公)历星期日是第一天;阴(农)历,星期一是第一天

实际上,在历史上有着很多种纪元的方法。它们的差异实在太大了,比方说一个人的生日是"八月八日" 那么一种可能是阳(公)历的八月八日,但也可以是阴(农)历的日期。所以为了计时的统一,必需指定一个日历的选择。那如今最为普及和通用的日历就是 "Gregorian Calendar"。也就是我们在讲述年份时经常使用 "公元几几年"。Calendar 抽象类定义了足够的方法,让我们可以表述日历的规则。Java 本身提供了对 "Gregorian Calendar" 规则的实现。我们从 Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与您通过 new GregorianCalendar() 获得的结果一致)。

以下的代码能够证明这一点:

import java.io.*;
import java.util.*;

public class WhatIsCalendar
{
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
if (calendar instanceof GregorianCalendar)
System.out.println("It is an instance of GregorianCalendar"t;
}
}

Calendar 在 Java 中是一个抽象类(Abstract Class),GregorianCalendar 是它的一个详细实现。

我们也能够自己的 Calendar 实现类,然后将它作为 Calendar 对象返回(面向对象的特性)。在 IBM alphaWorks 上,IBM 的开发者实现了多种日历(http://www.alphaworks.ibm.com/tech/calendars)。相同在 Internet 上,也有对中国农历的实现。本文对怎样扩展 Calendar 不作讨论,大家能够通过察看上述 Calendar 的源代码来学习。

Calendar 与 Date 的转换很easy:

Calendar calendar = Calendar.getInstance();
// 从一个 Calendar 对象中获取 Date 对象
Date date = calendar.getTime();
// 将 Date 对象反应到一个 Calendar 对象中,
// Calendar/GregorianCalendar 没有构造函数能够接受 Date 对象
// 所以我们必需先获得一个实例,然后设置 Date 对象
calendar.setTime(date);

Calendar 对象在使用时,有一些值得注意的事项:

1. Calendar 的 set() 方法

set(int field, int value) - 是用来设置"年/月/日/小时/分钟/秒/微秒"等值

field 的定义在 Calendar 中

set(int year, int month, int day, int hour, int minute, int second) 但没有

set(int year, int month, int day, int hour, int minute, int second, int millisecond) 前面 set(int,int,int,int,int,int) 方法不会自己主动将 MilliSecond 清为 0。

另外,月份的起始值为0而不是1,所以要设置八月时,我们用7而不是8。

calendar.set(Calendar.MONTH, 7);

我们通常须要在程序逻辑中将它清为 0,否则可能会出现以下的情况:

import java.io.*;
import java.util.*;

public class WhatIsCalendarWrite
{
public static void main(String[] args) throws Exception{
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("calendar.out"t);
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0, 0);
out.writeObject(cal1);
Calendar cal2 = Calendar.getInstance();
cal2.set(2000, 7, 1, 0, 0, 0);
cal2.set(Calendar.MILLISECOND, 0);
out.writeObject(cal2);
out.close();
}
}

我们将 Calendar 保存到文件里

import java.io.*;
import java.util.*;

public class WhatIsCalendarRead
{
public static void main(String[] args) throws Exception{
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream("calendar.out"t);
Calendar cal2 = (Calendar)in.readObject();
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 1, 0, 0, 0);
if (cal1.equals(cal2))
System.out.println("Equals"t;
else
System.out.println("NotEqual"t;
System.out.println("Old calendar "+cal2.getTime().getTime());
System.out.println("New calendar "+cal1.getTime().getTime());
cal1.set(Calendar.MILLISECOND, 0);
cal2 = (Calendar)in.readObject();
if (cal1.equals(cal2))
System.out.println("Equals"t;
else
System.out.println("NotEqual"t;
System.out.println("Processed Old calendar "+cal2.getTime().getTime());
System.out.println("Processed New calendar "+cal1.getTime().getTime());
}
}

然后再另外一个程序中取回来(模拟对数据库的存储),可是运行的结果是:

NotEqual
Old calendar 965113200422 <------------ 最后三位的MilliSecond与当前时间有关
New calendar 965113200059 <-----------/
Equals
Processed Old calendar 965113200000
Processed New calendar 965113200000

另外我们要注意的一点是,Calendar 为了性能原因对 set() 方法採取延缓计算的方法。在 JavaDoc 中有以下的样例来说明这个问题:

Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //应该是 2000-9-31,也就是 2000-10-1
cal1.set(Calendar.DAY_OF_MONTH, 30); //假设 Calendar 转化到 2000-10-1,那么如今的结果就该是 2000-10-30
System.out.println(cal1.getTime()); //输出的是2000-9-30,说明 Calendar 不是立即就刷新其内部的记录

在 Calendar 的方法中,get() 和 add() 会让 Calendar 立马刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。我们后面会看到这个问题。

2. Calendar 对象的容错性,Lenient 设置
我们知道特定的月份有不同的日期,当一个用户给出错误的日期时,Calendar 怎样处理的呢?

import java.io.*;
import java.util.*;

public class WhatIsCalendar
{
public static void main(String[] args) throws Exception{
Calendar cal1 = Calendar.getInstance();
cal1.set(2000, 1, 32, 0, 0, 0);
System.out.println(cal1.getTime());
cal1.setLenient(false);
cal1.set(2000, 1, 32, 0, 0, 0);
System.out.println(cal1.getTime());
}
}

它的运行结果是:

Tue Feb 01 00:00:00 PST 2000
Exception in thread "main" java.lang.IllegalArgumentException
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:1368)
at java.util.Calendar.updateTime(Calendar.java:1508)
at java.util.Calendar.getTimeInMillis(Calendar.java:890)
at java.util.Calendar.getTime(Calendar.java:871)
at WhatIsCalendar.main(WhatIsCalendar.java:12)
当我们设置该 Calendar 为 Lenient false 时,它会根据特定的月份检查出错误的赋值。

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 网站获取日期格式化选项的完整的指示.

三、将文本数据解析成日期对象r

如果我们有一个文本字符串包括了一个格式化了的日期对象, 而我们希望解析这个
字符串并从文本日期数据创建一个日期对象. 我们将再次以格式化字符串
"MM-dd-yyyy" 调用SimpleDateFormat类, 可是这一次, 我们使用格式化解析而不
是生成一个文本日期数据. 我们的样例, 显示在以下, 将解析文本字符串
"9-29-2001"并创建一个值为001736000000 的日期对象.

样例程序:

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

public class DateExample3 {

public static void main(String[] args) {
// Create a date formatter that can parse dates of
// the form MM-dd-yyyy.
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("MM-dd-yyyy");

// Create a string containing a text date to be parsed.
String dateStringToParse = "9-29-2001";

try {
// Parse the text version of the date.
// We have to perform the parse method in a
// try-catch construct in case dateStringToParse
// does not contain a date in the format we are expecting.
Date date = bartDateFormat.parse(dateStringToParse);

// Now send the parsed date as a long value
// to the system output.
System.out.println(date.getTime());
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}

五、使用标准的日期格式化过程

既然我们已经能够生成和解析定制的日期格式了, 让我们来看一看怎样使用内建的
格式化过程. 方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的
方法获得标准的日期格式化过程. 在以下的样例中, 我们获取了四个内建的日期格
式化过程. 它们包含一个短的, 中等的, 长的, 和完整的日期格式.

import java.text.DateFormat;
import java.util.Date;

public class DateExample4 {

public static void main(String[] args) {
Date date = new Date();

DateFormat shortDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.SHORT,
DateFormat.SHORT);

DateFormat mediumDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.MEDIUM,
DateFormat.MEDIUM);

DateFormat longDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.LONG);

DateFormat fullDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL);

System.out.println(shortDateFormat.format(date));
System.out.println(mediumDateFormat.format(date));
System.out.println(longDateFormat.format(date));
System.out.println(fullDateFormat.format(date));
}
}

注意我们在对 getDateTimeInstance的每次调用中都传递了两个值. 第一个參数
是日期风格, 而第二个參数是时间风格. 它们都是基本数据类型int(整型). 考虑
到可读性, 我们使用了DateFormat 类提供的常量: SHORT, MEDIUM, LONG, 和
FULL. 要知道获取时间和日期格式化过程的很多其它的方法和选项, 请看Sun 公司Web
网站上的解释.

执行我们的样例程序的时候, 它将向标准输出设备输出以下的内容:
9/29/01 8:44 PM
Sep 29, 2001 8:44:45 PM
September 29, 2001 8:44:45 PM EDT
Saturday, September 29, 2001 8:44:45 PM EDT

转载于:https://www.cnblogs.com/bhlsheji/p/4051783.html

JAVA Calendar具体解释相关推荐

  1. Java Calendar类 练习题:为孙工找到当月休息日

    Java Calendar 练习题:为孙工找到当月休息日 题目 难点分析 怎么进行格式化输出,达到图中的展示效果? 制表符:\t System.out.printf("%-8s", ...

  2. Java Calendar 类的时间操作

    Java Calendar 类时间操作,这也许是创建和管理日历最简单的一个方案,示范代码很简单. 演示了获取时间,日期时间的累加和累减,以及比较. 原文地址:blog.csdn.NET/joyous/ ...

  3. java语言中解释方式是什么意思,Java语言快速入门·简答T

    1 面向对象与面向过程有什么区别? 面向对象编程:既然面向的是对象,那么强调的自然就是--对象,那么对象多了,就会抽象出相应的类(对象是类的实例化),所以 · 程序是由类组成 · 程序运行的时候去调用 ...

  4. java同步关键词解释、synchronized、线程锁(Lock)

    1.java同步关键词解释 21.1 synchronized synchronized是用来实现线程同步的!!! 加同步格式: synchronized( 需要一个任意的对象(锁) ){ 代码块中放 ...

  5. Java Calendar使用指南

    Java Calendar使用指南 @(JAVA)[java] 完整代码请见:https://github.com/lujinhong/lujinhong-commons/tree/master/lu ...

  6. java语言特点解释类_Java语言特点

    Java语言特点 引导语:Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.那么你知道Java语言的特点吗,以下是百分网小编分享给大家的Java语言特点,欢迎阅读! Java语言的特点 1 ...

  7. java基础--名词解释汇总

    "专业术语",程序员在对JVM 做任何的性能和垃圾回收调整之前理解和记住这些"专业术语"是非常重要的.那么学习java有哪些专业名词是程序员必须记的呢?下面为大 ...

  8. 解释java程序所使用的命令是,【单选题】Java 源程序的解释命令是

    [单选题]Java 源程序的解释命令是 更多相关问题 [多选] 两端有电源的线路故障跳闸,选择强送端的原则包括(). [多选] 高技能人才聘期年度考核包括(),全部合格方为聘期年度考核合格. [单选] ...

  9. 利用Java Calendar类打印日历

    利用Java Calendar类打印日历 说到日历,我们接触的就多了,每天都在和日历打交道,每年家里都会买日历.那么,大家知道如何用Java打印日历呢?在这里,我说一下如何用Calendar类打印日历 ...

最新文章

  1. 【物联网智能网关-14】Html5:Canvas+WebSocket实现远程实时通信(下)
  2. 1.6 Dropout 正则化-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. 语音识别-过零率和短时能量-端点检测
  4. Programe_Of_Beauty:2.14 求数组的子数组之和的最大值
  5. 研究生期间如何成为科研大佬?
  6. linux网卡端口绑定bond,Linux下双网卡绑定bond0
  7. 高接低挡,Isilon三款新品铺开战线
  8. 公众号实现一键添加联系人到手机通讯录
  9. [渝粤教育] 西南科技大学 会计电算化 在线考试复习资料2021版
  10. 【华人学者风采】周亚金 浙江大学
  11. 2021年深圳南山区工业企业租金补贴申报时间及条件,补贴300万
  12. Arduino 数码管 硬件 4位数码管 TM1637驱动芯片 库文件 示例
  13. java设计模式-观察者模式(广播机制,消息订阅)
  14. 电脑快捷键:Ctrl+26英文字母组合,新人必会!
  15. ActiveMQ点对点消息传递
  16. XDU 1028 G.锘爷考驾照
  17. 交换机和路由器技术-18-热备份路由选择协议HSRP
  18. 去哪儿实习面经(拿到offer)
  19. 3.1.1计算机网络(数据链路层 差错控制 循环冗余码 海明码 流量控制)
  20. 2017面向对象程序设计(Java)第六周学习总结

热门文章

  1. 数据结构2:中序线索化二叉树为什么要通过pre设置后继结点
  2. signature=c4f11bb5142d9f6ce0876b3cc0d888af,PROVISIONAL SIGNATURE SCHEMES
  3. js轮询导致服务器瘫痪_演进:Tengine 从 Web 代理服务器 到 分布式推送服务器
  4. dos命令行设置网络优先级_海康威视二层接入网络交换机DS-3E2326-H 26口_DS-3E2326-H_DS-3E2326-H...
  5. java高淇_高淇java300集JAVA常用类作业
  6. cdn托管html资源,七牛自定义域名cdn加速,静态资源托管至对象存储
  7. android美颜功能,Android
  8. 结合泛函极值_泛函极值及变分法教程.doc
  9. C++编程进阶4(C++中的强制类型转换运算符、不要返回自定义类内部成员的指针,引用和迭代器)
  10. ES6的这些操作技巧,你会吗?