shaokun305的专栏

做J2EE一流架构师 E-Mail:shaokun305@gmail.com

陈少坤ID:shaokun305
135548次访问,排名551好友0人,关注者0
shaokun305的文章
原创 153 篇
翻译 0 篇
转载 22 篇
评论 229 篇
shaokun305的公告
留言板 New
这里是我一个温馨的港湾,记录下我的生活成长和技术成长的经历,随着岁月的流逝,这里将是我的一个最美丽的回忆.
最近评论
hdnero:wow power leveling
hdnero:wow power leveling
hdnero:wow power leveling
jinxinzhang:应该加catalina.sh里面吧

你可以在页面打印出内存看看,效果
miracle9i:非常详细 谢谢
文章分类
收藏
相册
稿笑图库
美女
java相关站点
CSDN
java世界
java研究组织
java解道
与java共舞
中国java
深入struts1.1
朋友的友情连接
http://blog.csdn.net/asklxf/
lxgljj
同事老朱的博客
戈壁草的博客
老康得网站
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

转载 Java API的Date, Calendar日期处理相关类分析 选择自 blue2993 的 Blog 收藏

新一篇: 最近没有什么可写的 | 旧一篇: 中秋快乐,所有光临本站的朋友们!

 

Making Sense of Java's Dates

 

by Philipp K. Janert, Ph.D. translated by humx
06/04/2003

简介

在计算机程序中精确的处理日期是困难的。不仅有显而易见的(英语: January, 法语: Janvier, 德语: Januar, )国际化需求, 而且得考虑不同的日期系统(并非所有的文化都用基督耶稣的生日作为纪年的开始)。如有高精度或非常大规模的时间需要被处理, 就有额外的方面需要被注意,比如闰秒或时间系统的变化。(公历(阳历, 格里高利历法)在西方被普遍接受是在1582,但并非所有的国家在同一天接受!)

尽管有关于闰秒, 时区, 夏令时, 阴历的问题, 度量时间却是一个非常简单的概念: 时间的进行是线性的很容易被忽略。一旦时间轴的区域被定义, 任何时间点被从起点时间的流逝就可以确定。这和地理位置或当地时区是独立的 对任意指定的时间点, 对任意地区, 从起点的过程是相同的(忽略相对论的矫正)


可当我们试图根据某些日历解释这一时间点的时候困难来了, 比如, 根据月, , 或者年来表示它。在这一步上地理信息变得相关: 在时间上的同一个点对应不同的天的某一时间, 依赖于区域 (比如: 时区)。基于解释日期的修正经常是必要的(今天一个月以后是哪一天?) 并且增加了额外的困难: 上溢和下溢(1215号的后一个月是下一年), 且不明确(130号后的一个月是哪一天?).

在最初的JDK 1.0, 一个时间点, 通过把它解释为java.util.Date, 被计算在一起来表示. 虽然相对容易处理, 但它并不支持国际化; JDK 1.1.4 JDK 1.1.5, 多样的负责处理日期的职责被分配到以下类中:

java.util.Date

代表一个时间点.

abstract java.util.Calendar
java.util.GregorianCalendar extends java.util.Calendar

解释和处理Date.

abstract java.util.TimeZone
java.util.SimpleTimeZone extends java.util.TimeZone

代表一个任意的从格林威治的偏移量, 也包含了适用于夏令时(daylight savings rules)的信息.

abstract java.text.DateFormat extends java.text.Format
java.text.SimpleDateFormat extends java.text.DateFormat

变形到格式良好的, 可打印的String, 反之亦然.

java.text.DateFormatSymbols

月份, 星期等的翻译, 作为从Locale取得信息的一种替代选择.

java.sql.Date extends java.util.Date
java.sql.Time extends java.util.Date
java.sql.Timestamp extends java.util.Date

代表时间点, 同时为了在sql语句中使用也包含适当的格式.

注意: DateFormat 和相关的类在java.text.*. 所有的java.sql.*包中日期处理相关类继承了java.util.Date. 所有的其它类在java.util.*包中.

这些""类来自三个分离的继承层次, 其顶层类(Calendar, TimeZone, and DateFormat)是抽象的. 针对每一个抽象类, Java标准类库提供了一个具体的实现.

java.util.Date

java.util.Date代表一个时间点. 在许多应用中, 此种抽象被称为"TimeStamp." 在标准的Java类库实现中, 这个时间点代表Unix纪元January 1, 1970, 00:00:00 GMT开始的毫秒数. 因而概念上来说, 这个类是long的简单封装.

根据此种解释, 类中仅有的没有过期的(除了那些毫秒数的getset方法)是那些排序方法.

这个类依靠System.currentTimeMillis() 来取得当前的时间点. 因此它的准确度和精度由System的实现和它所调用底层(本质是操作系统)决定.

The java.util.Date API

在最初的 Date类使用中名字和约定引起了无尽的混淆. 然而用0-11计算月, 1900计算年的决定模仿了C标准类库的习惯, 调用函数 getTime()返回起始于Unix纪元的毫秒数和 getDate()返回星期的决定显然是Java类设计者自己的.

java.util.Calendar

语义

Calendar代表一个时间点(一个"Date"), 用以在特定的区域和时区适当的解释器. 每一个Calendar 实例有一个包含了自纪元开始的代表时间点的long变量.

这意味着Calendar 不是一个(无状态) 变换者或解释器, 也不是一个修改dates的工厂. 它不支持如下方式:

Month Interpreter.getMonth(inputDate) or

Date Factory.addMonth(inputDate)

Instead, Calendar实例必须被初始化到特定的Date. Calendar实例可以被修改或查询interpreted属性.

奇怪的是, 此类的instances 总是被初始化为当前时间. 获得一个初始化为任意DateCalendar 实例是不可能的—API强制程序员通过一系列的在实例上的方法调用, 比如setTime(date)来显式的设置日期.

访问Interpreted 字段和类常量

Calendar类遵从一不常用的方式来访问interpreted date实例的单个字段. 而不是提供一些dedicated属性 getterssetters方法(比如getMonth()), 它仅提供了一个, 使用一个标示作为参数来获取请求的属性的方法:

int get(Calendar.MONTH) 等等.

注意这个函数总是返回一个int!

这些字段的标示符被定义为Calendar类的public static final变量. (这些identifiersraw的整数, 没有被封装为一个枚举抽象.)

除了对应这些字段标示(键值), Calendar 类定义了许多附加的public static final 变量来保存这些字段的值. 因此, 为测试某一特定date (Calendar 的实例calendar表示) 是否在一年的第一个月, 会有像如下的代码:

if (calendar.get(Calendar.MONTH) == Calendar.JANUARY) {...}

注意月份被叫做 JANUARY, FEBRUARY, 等等, 不管location(相对更中性的名字比如: MONTH_1, MONTH_2, 等等). 也有一个字段UNDECIMBER, 被一些(非公历(阳历, 格里高利历法))日历使用, 代表一年的第十三个月.

不幸的是, 键值和值既没有通过名字也没分组成嵌套的inerface来区分.

处理

Calendar提供了三种办法来修改当前实例代表的日期: set(), add(), roll(). set()方法简单的设置特定的字段为期望的值. add() roll() 的不同在于它们处理over- and underflows: add() 传递变更到"较小""较大"的字段, roll()不影响其它字段. 比如, 当给代表1215号的Calendar实例增加一个月, add()使用年会增加, 但使用roll()不会发生任何变化. 为每一种case对应一个函数的决定的动机是, 它们可能在GUI中不同的使用情形.

由于Calendar实现的方式, 它包含冗余的数据: 所有的字段都可以从给定的时区和纪元开始的毫秒数计算出来,反之亦然. 这个类为这些操作分别定义了抽象方法computeFields()