Java 语言的Calendar,GregorianCalendar (日历),Date(日期), 和DateFormat(日期格式)组成了Java标准的一个基本但是非常重要的部分. 日期是商业逻辑计算一个关键的部分. 所有的开发者都应该能够计算未来的日期, 定制日期的显示格式, 并将文本数据解析成日期对象。学习日期, 日期格式, 日期的解析和日期的计算。
我们将讨论下面的类:
1、 具体类(和抽象类相对)java.util.Date
2、 抽象类java.text.DateFormat 和它的一个具体子类,java.text.SimpleDateFormat
3、 抽象类java.util.Calendar 和它的一个具体子类,java.util.GregorianCalendar
具体类可以被实例化, 但是抽象类却不能. 你首先必须实现抽象类的一个具体子类.
1. java.util.Date及其格式化
Date 类从Java 开发包(JDK) 1.0 就开始进化, 当时它只包含了几个取得或者设置一个日期数据的各个部分的方法, 比如说月, 日, 和年. 这些方法现在遭到了批评并且已经被转移到了Calendar类里去了, 我们将在本文中进一步讨论它. 这种改进旨在更好的处理日期数据的国际化格式. 就象在JDK 1.1中一样, Date 类实际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林尼治标准时间)1970年, 1 月 1日00:00:00这一刻之前或者是之后经历的毫秒数.
1.1. 创建java.util.Date
Java统计从1970年1月1日起的毫秒的数量表示日期。也就是说,例如,1970年1月2日,是在1月1日后的86,400,000毫秒。同样的,1969年12月31日是在1970年1月1日前86,400,000毫秒。Java的Date类使用long类型纪录这些毫秒值.因为long是有符号整数,所以日期可以在1970年1月1日之前,也可以在这之后。Long类型表示的最大正值和最大负值可以轻松的表示290,000,000年的时间,这适合大多数人的时间要求。
让我们看一个使用系统的当前日期和时间创建一个日期对象并返回一个长整数的简单例子. 这个时间通常被称为Java 虚拟机(JVM)主机环境的系统时间.
- importjava.util.Date;
-
importjava.text.SimpleDateFormat;
-
publicclassDateExample1{
-
publicstaticvoidmain(String[]args){
-
- Datedate=newDate();
-
- System.out.println(date.getTime());
- }
- }
在星期六, 2001年9月29日, 下午大约是6:50的样子, 上面的例子在系统输出设备上显示的结果是 1001803809710. 在这个例子中,值得注意的是我们使用了Date 构造函数创建一个日期对象, 这个构造函数没有接受任何参数. 而这个构造函数在内部使用了System.currentTimeMillis() 方法来从系统获取日期.
- java.util.DatemyDate=newjava.util.Date();
- longmyTime=(myDate.getTime()/1000)-60*60*24*365;
- myDate.setTime(myTime*1000);
- StringmDate=formatter.format(myDate);
-
- myDate=newjava.util.Date();
- myTime=(myDate.getTime()/1000)+60*60*24;
- myDate.setTime(myTime*1000);
- mDate=formatter.format(myDate);
-
- SimpleDateFormatmyFormatter=newSimpleDateFormat("yyyy-MM-dd");
- java.util.Datedate=myFormatter.parse("2003-05-1");
- java.util.Datemydate=myFormatter.parse("1899-12-30");
- longday=(date.getTime()-mydate.getTime())/(24*60*60*1000);
-
- SimpleDateFormatformat=newSimpleDateFormat("yyyy-MM-ddhh:mm:ss");
- java.util.Datedate1=format.parse("2002-02-2823:16:00");
-
longTime=(date1.getTime()/1000)+60*30;
- date1.setTime(Time*1000);
- Stringmydate1=formatter.format(date1);
-
- SimpleDateFormatformatter2=newSimpleDateFormat("yyyy-MMFE");
- java.util.Datedate2=formatter2.parse("2003-055星期五");
- SimpleDateFormatformatter3=newSimpleDateFormat("yyyy-MM-dd");
- Stringmydate2=formatter3.format(date2);
-
- mydate=myFormatter.parse("2001-1-1");
- SimpleDateFormatformatter4=newSimpleDateFormat("E");
- Stringmydate3=formatter4.format(mydate);
1.2. Date格式化
能以一种用户明白的格式来显示这个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基类 java.text.DateFormat。那么, 现在我们已经知道了如何获取从1970年1月1日开始经历的毫秒数了. 我们如何才format 就派得上用场了.
// 我们能不能用下面的代码构件出 2001/8/8 8:8
- importjava.io.*;
- importjava.util.*;
- publicclassWhatIsDate
- {
- publicstaticvoidmain(String[]args){
- Datedate=newDate(2001,8,8,8,8,8);
- System.out.println(date);
- }
- }
Java 的编译器竟然报如下信息 (Sun JDK1.3, Windows 2000 中文下)
注意:
WhatIsDate.java 使用或覆盖一个不鼓励使用的API。
注意:
使用-deprecation重新编译,以得到详细信息。!
那么 Date 对象究竟是为了满足哪个需求呢?看来它不是用来实现基于年/月/日小时:分钟 的时间表述。我们查看 Java 的文档,我们看到有 getTime() 方法,它返回的竟然是一个 long 值。
文档进一步又告诉我们这个值代表了当前系统的时间离1970/1/1 0:0 的毫秒差,而且是在 GMT 时区下(也被称为 EPOC)。如果我们指定的时间是在此之前的,那它将返回一个负数值。
这个发现让我们对 Date 对象有了一个全新的认识-Date 存放的是与 EPOC 的偏差值。换而言之我们也可通过 long 类型来表示时间?对了,这个猜想是得到了 Java 的支持:
- longdateInMilliSeconds=System.currentTimeMillis();
- System.out.println(dateInMilliSeconds);
对程序执行效率敏感的程序员可以发现这个方法只是生成一个 Java 的原始类型 (primitive type) long, 不需要实例化一个对象。因此如果我们对时间的处理只是在内部进行时,可以用 long 来代替 Date 对象。
最典型的应用就是在一段代码开始和结束时,分别获得系统当前的时间,然后计算出代码执行所需的时间(微秒级)。
long start = System.currentTimeMillis();
// 代码段
System.out.println("需要 "+(System.currentTimeMillis()-start)+" 微秒");
那么当我们要把这个 long 值已更为友好的表现形式显示处理的时候,我们可以用它来构造 Date 对象:
Date date = new Date(dateInMilliSeconds);
System.out.println(date);
我们看到了在 Java 中对时间最为基本的表示,有通过对EPOC 的偏差值进行处理。Date 对象是对它的一个对象的封装。我们同时也看到了,在现时世界中我们对时间的描述通常是通过"某年某月某日某时某分"来定义的。Date 的显示(实际上是 toString() 方法)描述了这些信息,但 Java 并不建议我们用这种方式直接来构件 Date 对象。因此我们需要找出哪个对象可以实现这个需求。这就是我们下面就要讲述的 Calendar 对象的功能。
在我们进一步研究 Calendar 之前,请记住 Date 只是一个对 long 值(基于 GMT 时区)的对象封装。它所表现出来的年/月/日小时:分钟时区的时间表述,只是它的 toString() 方法所提供的。千万不要为这个假象所迷惑。
假如我们希望定制日期数据的格式, 比方星期六-9月-29日-2001年. 下面的例子展示了如何完成这个工作:
- importjava.text.SimpleDateFormat;
-
importjava.util.Date;
-
publicclassDateExample2{
-
publicstaticvoidmain(String[]args){
- SimpleDateFormatbartDateFormat=newSimpleDateFormat("EEEE-MMMM-dd-yyyy");Datedate=newDate();
- 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 站点获取日期格式化选项的完整的指示.
1.3. 文本数据解析成日期对象
假设我们有一个文本字符串包含了一个格式化了的日期对象, 而我们希望解析这个字符串并从文本日期数据创建一个日期对象. 我们将再次以格式化字符串"MM-dd-yyyy" 调用SimpleDateFormat类, 但是这一次, 我们使用格式化解析而不是生成一个文本日期数据. 我们的例子, 显示在下面, 将解析文本字符串"9-29-2001"并创建一个值为001736000000 的日期对象.
通过parse()方法,DateFormat能够以一个字符串创立一个Date对象。这个方法能抛出ParseException异常,所以你必须使用适当的异常处理技术。
例子程序:
- importjava.text.SimpleDateFormat;
-
importjava.util.Date;
-
publicclassDateExample3{
-
publicstaticvoidmain(String[]args){
-
-
- SimpleDateFormatbartDateFormat=newSimpleDateFormat("MM-dd-yyyy");
-
- StringdateStringToParse="9-29-2001";
-
try{
-
-
-
-
- Datedate=bartDateFormat.parse(dateStringToParse);
-
-
- System.out.println(date.getTime());
- }catch(Exceptionex){
- System.out.println(ex.getMessage());
- }
- }
- }
1.4. 使用标准的日期格式化过程
既然我们已经可以生成和解析定制的日期格式了, 让我们来看一看如何使用内建的格式化过程. 方法 DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过程. 在下面的例子中, 我们获取了四个内建的日期格式化过程. 它们包括一个短的, 中等的, 长的, 和完整的日期格式.
- importjava.text.DateFormat;
-
importjava.util.Date;
-
publicclassDateExample4{
-
publicstaticvoidmain(String[]args){
- Datedate=newDate();
- DateFormatshortDateFormat=DateFormat.getDateTimeInstance(
- DateFormat.SHORT,DateFormat.SHORT);
- DateFormatmediumDateFormat=DateFormat.getDateTimeInstance(
- DateFormat.MEDIUM,DateFormat.MEDIUM);
- DateFormatlongDateFormat=DateFormat.getDateTimeInstance(
- DateFormat.LONG,DateFormat.LONG);
- DateFormatfullDateFormat=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
2. Calendar 日历类
首先请记住 Calendar 只是一个抽象类, 也就是说你无法直接获得它的一个实例,换而言之你可以提供一个自己开发的 Calendar 对象。
那究竟什么是一个 Calendar 呢?中文的翻译就是日历,那我们立刻可以想到我们生活中有阳(公)历、阴(农)历之分。它们的区别在哪呢?
比如有:
月份的定义 - 阳`(公)历 一年12 个月,每个月的天数各不同;阴(农)历,每个月固定28天,每周的第一天 - 阳(公)历星期日是第一天;阴(农)历,星期一是第一天
实际上,在历史上有着许多种纪元的方法。它们的差异实在太大了,比如说一个人的生日是"八月八日" 那么一种可能是阳(公)历的八月八日,但也可以是阴(农)历的日期。所以为了计时的统一,必需指定一个日历的选择。那现在最为普及和通用的日历就是 "Gregorian Calendar"。也就是我们在讲述年份时常用 "公元几几年"。Calendar 抽象类定义了足够的方法,让我们能够表述日历的规则。Java 本身提供了对 "Gregorian Calendar" 规则的实现。我们从 Calendar.getInstance() 中所获得的实例就是一个 "GreogrianCalendar" 对象(与您通过 new GregorianCalendar() 获得的结果一致)。
下面的代码可以证明这一点:
- importjava.io.*;
- importjava.util.*;
- publicclassWhatIsCalendar
- {
- publicstaticvoidmain(String[]args){
- Calendarcalendar=Calendar.getInstance();
- if(calendarinstanceofGregorianCalendar)
- System.out.println("ItisaninstanceofGregorianCalendar");
- }
- }
Calendar 在 Java 中是一个抽象类(Abstract Class),GregorianCalendar 是它的一个具体实现。
Calendar 与 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,否则可能会出现下面的情况:
-
importjava.io.*;
-
importjava.util.*;
-
publicclassWhatIsCalendarWrite
- {
-
publicstaticvoidmain(String[]args)throwsException{
- ObjectOutputStreamout=
-
newObjectOutputStream(
-
newFileOutputStream("calendar.out"));
- Calendarcal1=Calendar.getInstance();
-
cal1.set(2000,7,1,0,0,0);
- out.writeObject(cal1);
- Calendarcal2=Calendar.getInstance();
-
cal2.set(2000,7,1,0,0,0);
-
cal2.set(Calendar.MILLISECOND,0);
- out.writeObject(cal2);
- out.close();
- }
- }
我们将 Calendar 保存到文件中
-
importjava.io.*;
-
importjava.util.*;
-
publicclassWhatIsCalendarRead
- {
-
publicstaticvoidmain(String[]args)throwsException{
- ObjectInputStreamin=
-
newObjectInputStream(
-
newFileInputStream("calendar.out"));
- Calendarcal2=(Calendar)in.readObject();
- Calendarcal1=Calendar.getInstance();
-
cal1.set(2000,7,1,0,0,0);
-
if(cal1.equals(cal2))
-
System.out.println("Equals");
-
else
-
System.out.println("NotEqual");
-
System.out.println("Oldcalendar"+cal2.getTime().getTime());
-
System.out.println("Newcalendar"+cal1.getTime().getTime());
-
cal1.set(Calendar.MILLISECOND,0);
- cal2=(Calendar)in.readObject();
-
if(cal1.equals(cal2))
-
System.out.println("Equals");
-
else
-
System.out.println("NotEqual");
-
System.out.println("ProcessedOldcalendar"+cal2.getTime().getTime());
-
System.out.println("ProcessedNewcalendar"+cal1.getTime().getTime());
- }
- }
然后再另外一个程序中取回来(模拟对数据库的存储),但是执行的结果是:
NotEqual
Old calendar 965113200422 <------------ 最后三位的MilliSecond与当前时间有关
New calendar 965113200059 <-----------/
Equals
Processed Old calendar 965113200000
Processed New calendar 965113200000
另外我们要注意的一点是,Calendar 为了性能原因对 set() 方法采取延缓计算的方法。在 JavaDoc 中有下面的例子来说明这个问题:
- Calendarcal1=Calendar.getInstance();
-
cal1.set(2000,7,31,0,0,0);
-
cal1.set(Calendar.MONTH,Calendar.SEPTEMBER);
-
cal1.set(Calendar.DAY_OF_MONTH,30);
-
System.out.println(cal1.getTime());
在 Calendar 的方法中,get() 和 add() 会让 Calendar 立刻刷新。Set() 的这个特性会给我们的开发带来一些意想不到的结果。我们后面会看到这个问题。
2. Calendar 对象的容错性,Lenient 设置
我们知道特定的月份有不同的日期,当一个用户给出错误的日期时,Calendar 如何处理的呢?
-
importjava.io.*;
-
importjava.util.*;
-
publicclassWhatIsCalendar
- {
-
publicstaticvoidmain(String[]args)throwsException{
- Calendarcal1=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 的,但是我们要注意下面的问题
-
importjava.io.*;
-
importjava.util.*;
-
publicclassUnstableCalendarimplementsSerializable
- {
-
publicstaticvoidmain(String[]args)throwsException{
- Calendarcal1=Calendar.getInstance();
-
cal1.set(2000,7,1,0,0,0);
-
cal1.set(Calendar.MILLISECOND,0);
- ObjectOutputStreamout=
-
newObjectOutputStream(
-
newFileOutputStream("newCalendar.out"));
- out.writeObject(cal1);
- out.close();
- ObjectInputStreamin=
-
newObjectInputStream(
-
newFileInputStream("newCalendar.out"));
- Calendarcal2=(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 重新计算字段。这样字段值就不对了。
下面的代码可以解决这个问题:
-
importjava.io.*;
-
importjava.util.*;
-
publicclassStableCalendarimplementsSerializable
- {
-
publicstaticvoidmain(String[]args)throwsException{
- Calendarcal1=Calendar.getInstance();
-
cal1.set(2000,7,1,0,0,0);
-
cal1.set(Calendar.MILLISECOND,0);
- ObjectOutputSt
相关推荐
根据给定的文件标题、描述、标签以及部分内容,我们可以总结出以下有关 Java 日期处理的知识点: ### 1. 导入必要的包 在 Java 中处理日期时,我们需要导入一些必要的包来支持日期时间的格式化、解析等功能。示例...
以上就是基于给定文件信息整理出的Java日期处理相关知识点,包括如何获取当前时间、不同格式的时间转换以及在JavaScript中获取当前时间等。这些知识点是Java编程中处理日期时间的基础,对于从事软件开发的人来说非常...
Java中的日期处理涉及到多个类,包括Date、Calendar、GregorianCalendar以及日期格式化类如DateFormat和SimpleDateFormat。这些类主要用于管理、操作和格式化日期和时间。以下是对这些类的详细说明: 1. **Date类**...
### Java日期处理大全:掌握时间的艺术 在Java编程中,日期和时间的处理是不可或缺的一部分,尤其是在涉及到数据记录、时间戳、定时任务等场景时。本文将深入探讨Java中的日期处理技术,涵盖从基础到进阶的各种技巧...
以下是一些关于Java日期处理的关键知识点,这些知识点在给定的文件中有所提及: 1. **获取当前日期**: Java通过`java.util.Date`类可以获取服务器上的当前日期。创建一个Date对象即会返回当前系统时间,如`Date ...
本文详细介绍了如何使用Java处理日期合并的问题,通过对`TimeoffDateDTO`类的定义和日期合并算法的具体实现,提供了一种有效的方法来解决实际工作中经常遇到的时间段重叠问题。这种方法不仅适用于员工请假时间的管理...
java中关于日期处理的总结,包含各种日期格式之间的转java.util.Date(已经不提倡使用,该类的方法比较少) java.util.Calendar(抽象类) java.util.GregorianCalendar(是Calendar的子类,日期处理时候经常使用该类)****...
Java中的日期和时间处理是程序开发中常见的任务,涉及到各种日期和时间的计算、格式化以及比较等操作。在Java中,主要使用`java.util.Date`、`java.util.Calendar`和`java.text.SimpleDateFormat`这三个核心类来处理...
获取日期中的某数值。如获取月份 增加日期中某类型的某数值。如增加日期 获取精确的日期 判断字符串是否为日期字符串 获取日期字符串的日期风格。失敗返回null。 将日期字符串转化为日期。失败返回null。 ...
第一部分关于JAVA的Date (参考关于JAVA的Date总结) 第二部分Date工具类(参考一个总结好的很好的关于JAVA的Date工具类)
标签“java日期控件”强调了这个主题关注的是Java中与日期选择相关的控件,不仅仅是Swing,也可能是JavaFX或其他库提供的日期选择组件。但在这里,我们主要讨论的是Swing环境下的实现。 在压缩包的"swing 时间控件...
### Java日期处理基础 在Java中,日期时间处理主要包括两个基本类:`java.util.Date` 和 `java.util.Calendar`。此外,还有用于格式化日期的`java.text.SimpleDateFormat`类。这些类提供了处理日期的基本方法。 ##...
本文将基于标题“Java中对日期的常用处理(转)”来深入探讨Java中的日期处理,结合`DateUtil.java`这个文件名,我们可以推测这是一个包含日期处理工具类的源代码文件。 首先,Java中处理日期的最基础类是`java....
总结来说,Java Swing的DatePicker组件通过第三方库提供了一个方便的方式来处理日期选择,它可以极大地提升用户体验。开发者需要了解如何导入和使用这个库,创建DatePicker实例,定制其外观和行为,并将其集成到GUI...
综合以上步骤,可以实现一个较为完整的日期处理逻辑,如下所示: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.xssf.usermodel....
在Java中,日期处理是一项常见的任务,涉及到多个类和方法。本篇文章主要总结了Java中关于日期处理的基础知识,包括`java.util.Calendar`,`java.util.GregorianCalendar`以及`java.util.Date`这三个核心类。 首先...
Java时间日期处理是Java开发中不可或缺的一部分,涉及到各种时间日期的操作,如获取当前时间、日期的格式化、日期的加减、日期比较等。在Java中,有多种类和API可以用于时间日期处理,包括`java.util.Date`、`java....
在Java编程中,Stream API是Java 8引入的一个强大特性,它允许我们以声明性方式处理数据集合。本文将深入探讨如何使用Stream API对日期进行排序。日期排序在数据分析、日志处理、报表生成等场景中非常常见。下面我们...
在Java编程语言中,处理日期和时间是常见的需求,无论是记录日志、处理用户输入,还是进行数据分析。Java提供了多种库来帮助开发者有效地管理日期和时间。本教程将深入探讨Java处理日期和时间的核心概念、API以及...