Date类的概述
1.JDK提供date类表示特定的瞬间,精确到毫秒。
继续查阅Date类的描述,发现Date拥有多个构造函数,只是部分已经过时,但是其中有未过时的构造函数可以把毫秒值转成日期对象。
//创建日期对象,把当前的毫秒值转成日期对象
Date date = new Date(124355676160L);
System.out.println(date);
//Mon Dec 10 15:14:36 CST 1973
可是将毫秒值转成日期后,输出的格式不利于我们阅读,继续查阅API,Date中有getYear、getMouth等方法,可以他们已经过时,继续往下查阅,还有让我们参见toLocaleString方法,点进去,这个方法也过时了,从JDK 1.1 开始,由 DateFormat.format(Date date) 取代。
既然这个方法被DateFormat.format(Date date)取代,那么就要去查阅DateFormat类。
date常用的方法:
把日期对象转换成对应的时间毫秒值
2.DateFormat的概述:DateFormat是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。日期/时间格式化子类(如SimpleDateFormat类)允许进行格式化(也就是日期-> 文本)、解析(文本->日期)和标准化。
我们通过这个类可以帮我们完成日期和文本之间的转换。
DateFormat 可帮助进行格式化并解析任何语言环境的日期。对于月、星期,甚至日历格式(阴历和阳历),其代码可完全与语言环境的约定无关。
(1.)日期格式:日期-->文本要格式化一个当前语言环境下的日期也就是日期 -> 文本),要通过下面的方法来完成。DateFormat是抽象类,我们需要使用其子类SimpleDateFormat来创建对象。
//创建日期格式化对象,在获取格式化对象时可以指定风格
DateFormat df= new SimpleDateFormat("yyyy-MM-dd");//对日期进行格式化
Date date = new Date(124355676160L);
String str_time = df.format(date);
System.out.println(str_time);//1973年12月10日
l DateFormat类的作用:即可以将一个Date对象转换为一个符合指定格式的字符串,也可以将一个符合指定格式的字符串转为一个Date对象。
指定格式的具体规则我们可参照SimpleDateFormat类的说明,这里做简单介绍,规则是在一个字符串中,会将以下字母替换成对应时间组成部分,剩余内容原样输出:
l 当出现y时,会将y替换成年
2 当出现M时,会将M替换成月
3 当出现d时,会将d替换成日
4 当出现H时,会将H替换成时
5 当出现m时,会将m替换成分
6 当出现s时,会将s替换成秒
2.DateFormat类常用方法
format方法,用来将Date对象转换成String
parse方法,用来将String转换成Date(转换时,该String要符合指定格式,否则不能转换)。
代码演示:
练习一:把Date对象转换成String
Date date = new Date(124355676160L);
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");
String str = df.format(date);
System.out.println(str);
//str中的内容为1973年12月10日
练习二:把String转换成Date对象
String str = "1973年12月10日";
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");
Date date = df.parse( str );
System.out.println(str);
Calendar类概述:
Calendar是日历类,在Date后出现,替换掉了许多Date的方法。该类将所有可能用到的时间信息封装为静态成员变量,方便获取。
Calendar为抽象类,由于语言敏感性,Calendar类在创建对象时并非直接创建,而是通过静态方法创建,将语言敏感内容处理好,再返回子类对象,如下:
Calendar类静态方法
Calendar c = Calendar.getInstance(); //返回当前时间
Calendar类常用方法:
public int get(int field) //获取时间字段值,字段参见帮助文档
YEAR 年
MONTH 月,从0开始算起,最大11;0代表1月,11代表12月。
DATE 天
HOUR 时
MINUTE分
SECOND秒
代码演示:
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
public void add(int field,int amount) //指定字段增加某值
代码演示:
Calendar c = Calendar.getInstance();
//修改当前时间为3天后
c.add(Calendar.DATE, 3);
//修改当前时间为5小时后
c.add(Calendar.HOUR, 5);
public final void set(int field,int value)//设置指定字段的值
代码演示:
Calendar c = Calendar.getInstance();
//设置时间为2020年5月20日
c.set(Calendar.YEAR, 2020);
c.set(Calendar.MONTH, 4);
c.set(Calendar.DATE, 20);
public final Date getTime() //获取该日历对象转成的日期对象
代码演示:
Calendar c = Calendar.getInstance();
Date d = c.getTime();
注意事项:
西方星期的开始为周日,中国为周一。
在Calendar类中,月份的表示是以0-11代表1-12月。
日期是有大小关系的,时间靠后,时间越大。
上述总结:
l Date: 日期/时间类
构造方法:
public Date()// 系统当前日期时间
public Date(long date) 得到一个1970年1月1日0点这个时间基础上,加上参数date毫秒值对应的日期时间
方法:
public long getTime() 获取日期所对应的毫秒值
2 DateFormat:是日期/时间格式化子类的抽象类, 使用其子类SimpleDateFormat 实例化
构造方法:
public SimpleDateFormat() 默认的格式化操作
public SimpleDateFormat(String pattern) 按照指定的格式,进行日期格式化
日期和时间模式
y 年
M 年中的月份
d 月份中的天数
H 一天中的小时数(0-23)
m 小时中的分钟数
s 分钟中的秒数
S 毫秒数
方法:
public final String format(Date date) 把日期 格式化成字符串
public Date parse(String source) 把日期字符串 转换成 日期对象
3 Calendar:日历类,可获取日期中指定字段的值
方法:
public static Calendar getInstance() //获取日期对象
public int get(int field) //获取时间字段值
public void add(int field,int amount) //指定字段增加某值
public final void set(int field,int value)//设置指定字段的值
public final Date getTime() //获取该日历对象转成的日期对象
4.Joda-Time (http://www.joda.org/joda-time/userguide.html)
架构概述
下面介绍Joda-Time的主要构建模块。这些是即时,间隔,持续时间,周期,年代和时区的概念。接下来我们谈一谈关于界面在图书馆设计中的作用,这与标准略有不同。我们结束对包装结构的几句话。即时的使用示例会延迟到指南的以下部分。间隔,持续时间和周期的例子可以在文档的“重要概念”部分的相应部分找到。
瞬间
Joda-Time中最常用的概念是即时的概念。“即时”定义为从1970-01-01T00:00Z指定为数毫秒的日期时间连续区中的时刻。毫秒的定义与日期或日历中的JDK的定义一致。这两个API之间的互操作非常简单。
在Joda-Time中,一个瞬间由ReadableInstant接口表示。这个接口的主要实现和普通API用户需要最熟悉的类是DateTime。DateTime是不可变的 - 一旦创建,值不会改变。因此,这个类可以安全地传递,并在多个线程中使用,而无需同步。
毫秒瞬间可以转换成任何日期时间字段使用年表。为了解决这个问题,在DateTime上提供了一些方法来作为getter的最常用的日期和时间字段。
在这个概述中,我们将进一步讨论年表概念。
DateTime的伴随可变类是MutableDateTime。这个类的对象可以被修改,而且不是线程安全的。
ReadableInstant的其他实现包括Instant和已弃用的DateMidnight。
字段
DateTime的主要API 一直保持很小,仅限于获取每个日历字段的方法。因此,例如,通过调用getDayOfYear()方法可以检索“日历”日历字段。有关字段及其说明的完整列表,请参阅字段参考。
属性
然而,通过使用所谓的财产,有更多的权力可用。每个日历字段都与这样的属性相关联。因此,getDayOfYear()方法直接返回值的“day-of-year” 也与dayOfYear()方法返回的属性相关联。与DateTime关联的属性类是DateTime.Property。
了解财产的方法是充分利用API的秘诀。我们在本文后面的使用属性上有更多的话要说。
间隔
的间隔在约达时间表示时间从一个时刻到另一时刻的间隔。这两个时刻都是在日期时间连续统一时间完全指定的时间,完整的时区。
间隔实现为半开放,也就是说开始时刻是包含的,但结束时刻是独占的。结束总是大于或等于开始。两个终点都被限制在相同的年代和相同的时区。
提供了两个实现,Interval和MutableInterval,都是ReadableInterval的特化。
持续时间
甲持续时间在约达时间表示以毫秒计的时间的持续时间。持续时间通常是从一个时间间隔获得的。
持续时间是一个非常简单的概念,实现也很简单。他们没有年代或时区,只有毫秒的时间。
持续时间可以被添加到一个瞬间,或者到一个时间间隔的任何一端来改变这些对象。在日期时间的数学,你可以说:
即时+持续时间=即时
目前,ReadableDuration接口只有一个实现:持续时间。
期
甲期间在约达时间表示一段时间中的字段来定义,例如,3年5月2天及7小时。这与持续时间的不同之处在于毫秒数不准确。通过指定与时间有关的时刻(包括时间顺序和时区),一个时段只能被解析为精确的毫秒数。
例如,考虑一个月的时间。如果你把这段时间加到2月1日(ISO)那么你将会在3月1日。如果你在3月1日增加相同的时间,你将会在4月1日。但是在这两种情况下增加的时间(以毫秒为单位)是非常不同的。
作为第二个例子,考虑在夏令时边界添加1天。如果您使用一段时间来进行添加,那么23或25小时将被适当添加。如果你创建了一个24小时的持续时间,那么你最终会得到错误的结果。
期间是作为一组int字段实现的。一段时间内的标准字段集合是年,月,周,日,时,分,秒和毫秒。所述PeriodType类允许这个组字段被限制,例如以elimate周。当将持续时间或时间间隔转换为时间段时,这是非常重要的,因为计算需要知道应该填充哪些时间段。
方法存在期间获得每个字段值。时期不与时间顺序或时区有关。
可以将时间段添加到即时,或者间隔的任一末尾以更改这些对象。在日期时间的数学,你可以说:
即时+周期=即时
ReadablePeriod接口有两个实现:Period和MutablePeriod。
年表
乔达时代的设计是基于年表。它是一个计算引擎,支持日历系统的复杂规则。它封装了按需使用的字段对象,将绝对时间瞬间分割成可识别的日历字段,如“星期几”。它实际上是一个可插拔的日历系统。
年表的实际计算分为Chronology类本身和字段类DateTimeField和DurationField。这三个类的子类一起构成了库中的大部分代码。大多数用户将永远不需要使用或直接引用子类。相反,他们将简单地获得年表,并将其用作单例,如下所示:
Chronology coptic = CopticChronology.getInstance();
在内部,所有的年表,领域等等都保持为单身。因此,在使用Joda-Time时有一个初始设置成本,但之后只有主要API实例类(DateTime,Interval,Period等)具有创建和垃圾收集器成本。
虽然年代学是设计的关键,但它并不是使用API的关键!
对于大多数应用来说,年代学可以被忽略,因为它将默认为ISOC年代学。这适用于大多数用途。如果您在1582年10月15日之前需要准确的日期,或者Julian日历在您感兴趣的地区停止,那么您可以更改它。如果您需要像以前所示的科普特日历这样的特定日历,还可以更改它。
时区
年表类也支持时区功能。这是通过装饰设计模式应用于底层年表。所述DateTimeZone类,可以访问这些区主要通过一个工厂的方法,如下所示:
DateTimeZone zone = DateTimeZone.forID(“Europe / London”);
除了命名时区,Joda-Time还支持固定时区。最简单的是UTC,它被定义为一个常量:
DateTimeZone zoneUTC = DateTimeZone.UTC;
DateTimeZone zoneUTC = DateTimeZone.forOffsetHours(hours);
时区实施基于公共IANA 时区数据库提供的数据。时区id的完整列表可以在这里找到
Joda-Time提供了一个默认时区,在没有指定时区的情况下,该时区在很多操作中都会使用。这在概念上类似于java.util.TimeZone类的默认时区。该值可以通过静态方法访问和更新:
DateTimeZone defaultZone = DateTimeZone.getDefault(); DateTimeZone.setDefault(的myZone);
接口使用
正如你所看到的,Joda-Time定义了许多在javadoc中可见的新接口。最重要的是目前有4个实现的ReadableInstant。其他重要的接口包括ReadableInterval和ReadablePeriod。这些目前分别被用作仅值类和可变类的概括。
这里要提到的一个重点是Joda接口的使用方式与JDK Collections Framework接口不同。当使用集合接口(如List或Map)时,通常会将您的变量作为List或Map的类型保存,只有在创建对象时才引用具体的类。
List list = new ArrayList(); Map map = new HashMap();
DateTime dt = new DateTime();
为了获得最大的灵活性,您可以选择使用Joda-Time界面来声明您的方法参数。接口上的方法可以获得方法中使用的具体类。
公共无效进程(ReadableDateTime dateTime){ DateTime dt = dateTime.toDateTime(); }
包结构
包结构被设计为将公共API中的方法与私有API分开。公共包是根包(在org.joda.time下)和格式包。私人包是基地,计时,转换,领域和tz包。大多数应用程序不需要从私有包中导入类。
使用DateTime
施工
日期时间对象是通过使用DateTime构造函数创建的。默认的构造函数使用如下
DateTime dt = new DateTime();
要创建代表特定日期和时间的日期时间对象,可以使用初始化字符串:
DateTime dt = new DateTime(“2004-12-13T21:39:45.618-08:00”);
DateTime还提供其他构造函数来使用各种标准字段创建特定的日期和时间。这也允许使用任何日历和时区。
JDK互操作性
的日期时间类有一个构造它接受一个对象作为输入。特别是这个构造函数可以传递一个JDK Date,JDK Calendar或者JDK GregorianCalendar(它也接受一个ISO8601格式的字符串,或者一个表示毫秒的Long对象)。这是与JDK互操作性的一半。与JDK的互操作性的另一半由返回JDK对象的DateTime方法提供。
因此,Joda DateTime和JDK Date之间的转换可以如下进行
//从Joda到JDK DateTime dt = new DateTime(); 日期jdkDate = dt.toDate(); //从JDK到Joda dt = new DateTime(jdkDate);
同样,对于JDK 日历:
//从Joda到JDK DateTime dt = new DateTime(); 日历jdkCal = dt.toCalendar(Locale.CHINESE); //从JDK到Joda dt = new DateTime(jdkCal);
和JDK GregorianCalendar:
//从Joda到JDK DateTime dt = new DateTime(); GregorianCalendar jdkGCal = dt.toGregorianCalendar(); //从JDK到Joda dt = new DateTime(jdkGCal);
查询日期时间
日历字段(计算的分离DateTimeField字段从日历时刻(的表示)的DateTime)使一个强大和灵活的API。两者之间的连接由属性(DateTime.Property)维护,该属性提供对该字段的访问。
例如,直接获取特定DateTime的星期值的方法涉及到调用方法
int iDoW = dt.getDayOfWeek();
public static final int MONDAY = 1; 公共静态最终诠释TUESDAY = 2; 公共静态最终诠释WEDNESDAY = 3; 公共静态最终诠释THURSDAY = 4; public static final int FRIDAY = 5; public static final int SATURDAY = 6; public static final int SUNDAY = 7;
访问字段
直接方法对于简单的使用来说很好,但是通过属性/字段机制可以实现更多的灵活性。星期几财产是通过
DateTime.Property pDoW = dt.dayOfWeek();
String strST = pDoW.getAsShortText(); //返回“Mon”,“Tue”等 String strT = pDoW.getAsText(); //返回“星期一”,“星期二”等
String strTF = pDoW.getAsText(Locale.FRENCH); //返回“Lundi”等
当然,该字段的原始整数值仍然可以被访问为
iDoW = pDoW.get();
实际上,实际上不会创建中间pDoW变量。如果在匿名中间对象上调用方法,代码更容易阅读。因此,例如,
strT = dt.dayOfWeek()。getAsText(); iDoW = dt.dayOfWeek()。get();
注意:对于获取字段数值的单个情况,我们建议在主DateTime对象上使用get方法,因为效率更高。
iDoW = dt.getDayOfWeek();
日期字段
该日期时间实现提供了标准的日历字段的完整列表:
dt.getEra(); dt.getYear(); dt.getWeekyear(); dt.getCenturyOfEra(); dt.getYearOfEra(); dt.getYearOfCentury(); dt.getMonthOfYear(); dt.getWeekOfWeekyear(); dt.getDayOfYear(); dt.getDayOfMonth(); dt.getDayOfWeek();
正如您所期望的那样,我们上面在星期几示例中显示的所有方法都可以应用于这些属性中的任何一个。例如,要从日期时间中提取标准的月份,日期和年份字段,我们可以编写
String month = dt.monthOfYear()。getAsText(); int maxDay = dt.dayOfMonth()。getMaximumValue(); boolean leapYear = dt.yearOfEra()。isLeap();
时间字段
另一组属性访问字段代表时间计算的日间持续时间。因此,为了计算由DateTime表示的时刻的小时,分钟和秒,我们将写
int hour = dt.getHourOfDay(); int min = dt.getMinuteOfHour(); int sec = dt.getSecondOfMinute();
操作日期时间
DateTime对象具有值语义,并且在构造之后不能被修改(它们是不可变的)。因此,日期时间对象的最简单的操作涉及构建新的日期时间作为原始的修改副本。
警告:使用不可变类的常见错误是忘记将结果赋值给变量。请记住,在一个不可移动的对象上调用add或set方法对该对象没有影响 - 只有结果被更新。
修改字段
一种方法是在属性上使用方法。为了回到我们之前的例子,如果我们希望通过将星期几字段更改为星期一来修改dt对象,我们可以通过使用属性的setCopy方法来实现:
DateTime result = dt.dayOfWeek()。setCopy(DateTimeConstants.MONDAY);
要添加到日期,您可以使用addToCopy方法。
DateTime结果= dt.dayOfWeek()。addToCopy(3);
DateTime方法
完成类似计算的另一种方法是在DateTime对象本身上使用方法。因此,我们可以直接添加3天到dt,如下所示:
DateTime结果= dt.plusDays(3);
使用MutableDateTime
上述方法适用于涉及一个或两个字段的简单计算。在需要修改多个字段的情况下,创建日期时间的可变副本,修改副本并最终创建新的日期时间值会更有效。
MutableDateTime mdt = dt.toMutableDateTime(); //对mdt进行各种计算 ... DateTime结果= mdt.toDateTime();
改变时区
DateTime支持一些常见的时区计算。例如,如果你想在这个时间在伦敦的当地时间,你会做到以下几点
//获取默认时区的当前时刻 DateTime dt = new DateTime(); //翻译伦敦当地时间 DateTime dtLondon = dt.withZone(DateTimeZone.forID(“Europe / London”));
这里还有一个反向操作的支持,即获得的日期时间(毫秒绝对值)相对应的时刻,伦敦拥有相同的本地时间作为缺省时区存在的现在。这如下完成
//获取默认时区的当前时刻 DateTime dt = new DateTime(); //找到伦敦将有同一时间的时刻 dtLondonSameTime = dt.withZoneRetainFields(DateTimeZone.forID(“Europe / London”));
通过调用DateTimeZone.getAvailableIDs()可以获得一组所有TimeZone ID字符串(如“Europe / London” )。这里提供了完整的可用时区列表。
改变年表
该日期时间类也有改变日历的一种方法。这使您可以更改给定时刻的日历。因此,如果你想获得当前的日期时间,但在佛教日历,你会这样做
//获取默认时区的当前时刻 DateTime dt = new DateTime(); dt.getYear(); //返回2004年 //改为佛教年代 DateTime dtBuddhist = dt.withChronology(BuddhistChronology.getInstance()); dtBuddhist.getYear(); //返回2547
输入和输出
具有自定义格式的外部来源的日期时间信息是具有日期时间计算的应用程序的常见要求。写入自定义格式也是一个常见的要求。
许多自定义格式可以用日期格式字符串来表示,这些字符串指定一系列日历字段以及表示(数字,名称字符串等)和字段长度。例如,模式“yyyy”将代表4位数的年份。其他格式不是很容易表示。例如,两位数年份的模式“yy”并不唯一标识它所属的世纪。在输出上,这不会造成问题,但是输入上有解释的问题。
另外,现在有几种常用的日期/时间序列化标准,特别是ISO8601。这些也必须由大多数日期时间的应用程序支持。
Joda-Time通过灵活的架构支持这些不同的需求。现在我们将描述这个架构的各种元素。
格式化程序
所有打印和解析都使用DateTimeFormatter对象执行。给定这样一个对象fmt,解析执行如下
String strInputDateTime; //字符串以某种方式填充日期时间字符串 ... DateTime dt = fmt.parseDateTime(strInputDateTime);
String strOutputDateTime = fmt.print(dt);
标准格式化器
ISODateTimeFormat类提供了对基于ISO8601的标准格式的支持。这提供了许多工厂方法。
例如,如果您想要使用datetime的ISO标准格式,即yyyy-MM-dd'T'HH:mm:ss.SSSZZ,则可以将fmt初始化为
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
自定义格式化程序
如果您需要一个自定义格式化程序,可以用格式模式来描述,则可以使用DateTimeFormat类提供的工厂方法。因此,要得到一个4位数的年份,2位数的月份和2位数的日期的格式化程序,即yyyyMMdd的格式,你会做
DateTimeFormatter fmt = DateTimeFormat.forPattern(“yyyyMMdd”);
您可能需要打印或解析特定的语言环境。这是通过在格式化程序上调用withLocale方法来实现的,该方法返回基于原始格式的另一格式化程序。
DateTimeFormatter fmt = DateTimeFormat.forPattern(“yyyyMMdd”); DateTimeFormatter frenchFmt = fmt.withLocale(Locale.FRENCH); DateTimeFormatter germanFmt = fmt.withLocale(Locale.GERMAN);
怪异的格式化程序
最后,如果你有一个不容易被模式字符串表示的格式,Joda-Time架构公开了一个构建器类,可以用来构建一个自定义的格式化程序,这个格式化程序是以编程方式定义的。因此,如果您希望格式化程序打印并解析“22-Jan-65”形式的日期,则可以执行以下操作:
DateTimeFormatter fmt = new DateTimeFormatterBuilder() .appendDayOfMonth(2) .appendLiteral( ' - ') .appendMonthOfYearShortText() .appendLiteral( ' - ') .appendTwoDigitYear(1956)// pivot = 1956 .toFormatter();
这种格式特别有趣的是两位数的年份。由于对两位数年份的解释是不明确的,所以appendTwoDigitYear通过指定范围的中点来获取定义两位数的100年范围的额外参数。在这个例子中,范围将是(1956 - 50)= 1906到(1956 + 49)= 2005。因此,04将是2004年,但07年将是1907年。这种转换对于普通格式的字符串是不可能的, Joda时间格式体系结构。
直接访问
为了简化对格式化器体系结构的访问,已经在datetime类(如DateTime)上提供了方法。
DateTime dt = new DateTime(); String a = dt.toString(); 字符串b = dt.toString(“dd:MM:yy”); String c = dt.toString(“EEE”,Locale.FRENCH); DateTimeFormatter fmt = ...; String d = dt.toString(fmt);
高级功能
更改当前时间
Joda-Time允许您更改当前时间。所有获取当前时间的方法都是通过DateTimeUtils进行的。这样可以改变当前的时间,这对测试非常有用。
//查询当前时间总是返回同一时间 DateTimeUtils.setCurrentMillisFixed(米利斯); //抵消实时 DateTimeUtils.setCurrentMillisOffset(米利斯);
转换器
API中每个主要具体类的构造函数都将Object作为参数。这被传递到转换器子系统,该子系统负责将对象转换为Joda-Time可接受的对象。例如,转换器可以将JDK Date对象转换为DateTime。如果需要,您可以将自己的转换器添加到Joda-Time提供的转换器中。
安全
Joda-Time包含了针对敏感更改的标准JDK安全机制。这些包括更改时区处理程序,更改当前时间和更改转换器。有关详细信息,请参阅JodaTimePermission。