一、Calendar类
我们现在已经能够格式化并创建一个日期对象了,但是我们如何才能设置和获取日期数据的特定部分呢,比如说小时,日,或者分钟? 我们又如何在日期的这些部分加上或者减去值呢? 答案是使用Calendar 类。
Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些。
Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可。
创建一个代表系统当前日期的Calendar对象
Calendar c = Calendar.getInstance();//默认是当前日期
创建一个指定日期的Calendar对象
使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。
//创建一个代表2009年6月12日的Calendar对象
Calendar c1 = Calendar.getInstance();
c1.set(2009, 6 - 1, 12);
Calendar类对象字段类型
Calendar类中用一下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
Calendar类对象信息的设置
Set设置
如:
Calendar c1 = Calendar.getInstance();
调用:
public final void set(int year,int month,int date)
c1.set(2009, 6 - 1, 12);//把Calendar对象c1的年月日分别设这为:2009、5、12
利用字段类型设置
如果只设定某个字段,例如日期的值,则可以使用如下set方法:
public void set(int field,int value)
把 c1对象代表的日期设置为10号,其它所有的数值会被重新计算
c1.set(Calendar.DATE,10);
把c1对象代表的年份设置为2008年,其他的所有数值会被重新计算
c1.set(Calendar.YEAR,2008);
其他字段属性set的意义以此类推
Add设置
Calendar c1 = Calendar.getInstance();
把c1对象的日期加上10,也就是c1所表的日期的10天后的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, 10);
把c1对象的日期减去10,也就是c1所表的日期的10天前的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, -10);
其他字段属性的add的意义以此类推
Calendar类对象信息的获得
Calendar c1 = Calendar.getInstance();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c1.get(Calendar.DAY_OF_WEEK);
GregorianCalendar类
Calendar类实现了公历日历,GregorianCalendar是Calendar类的一个具体实现。
Calendar 的getInstance()方法返回一个默认用当前的语言环境和时区初始化的GregorianCalendar对象。GregorianCalendar定义了两个字段:AD和BC。这些代表公历定义的两个时代。
下面列出GregorianCalendar对象的几个构造方法:
序号 | 构造函数和说明 |
1 | GregorianCalendar() 在具有默认语言环境的默认时区内使用当前时间构造一个默认的 GregorianCalendar。 |
2 | GregorianCalendar(int year, int month, int date) 在具有默认语言环境的默认时区内构造一个带有给定日期设置的 GregorianCalendar |
3 | GregorianCalendar(int year, int month, int date, int hour, int minute) 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar。 |
4 | GregorianCalendar(int year, int month, int date, int hour, int minute, int second) 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar。 |
5 | GregorianCalendar(Locale aLocale) 在具有给定语言环境的默认时区内构造一个基于当前时间的 GregorianCalendar。 |
6 | GregorianCalendar(TimeZone zone) 在具有默认语言环境的给定时区内构造一个基于当前时间的 GregorianCalendar。 |
7 | GregorianCalendar(TimeZone zone, Locale aLocale) 在具有给定语言环境的给定时区内构造一个基于当前时间的 GregorianCalendar。 |
这里是GregorianCalendar 类提供的一些有用的方法列表:
序号 | 方法和说明 |
1 | void add(int field, int amount) 根据日历规则,将指定的(有符号的)时间量添加到给定的日历字段中。 |
2 | protected void computeFields() 转换UTC毫秒值为时间域值 |
3 | protected void computeTime() 覆盖Calendar ,转换时间域值为UTC毫秒值 |
4 | boolean equals(Object obj) 比较此 GregorianCalendar 与指定的 Object。 |
5 | int get(int field) 获取指定字段的时间值 |
6 | int getActualMaximum(int field) 返回当前日期,给定字段的最大值 |
7 | int getActualMinimum(int field) 返回当前日期,给定字段的最小值 |
8 | int getGreatestMinimum(int field) 返回此 GregorianCalendar 实例给定日历字段的最高的最小值。 |
9 | Date getGregorianChange() 获得格里高利历的更改日期。 |
10 | int getLeastMaximum(int field) 返回此 GregorianCalendar 实例给定日历字段的最低的最大值 |
11 | int getMaximum(int field) 返回此 GregorianCalendar 实例的给定日历字段的最大值。 |
12 | Date getTime() 获取日历当前时间。 |
13 | long getTimeInMillis() 获取用长整型表示的日历的当前时间 |
14 | TimeZone getTimeZone() 获取时区。 |
15 | int getMinimum(int field) 返回给定字段的最小值。 |
16 | int hashCode() 重写hashCode. |
17 | boolean isLeapYear(int year) 确定给定的年份是否为闰年。 |
18 | void roll(int field, boolean up) 在给定的时间字段上添加或减去(上/下)单个时间单元,不更改更大的字段。 |
19 | void set(int field, int value) 用给定的值设置时间字段。 |
20 | void set(int year, int month, int date) 设置年、月、日的值。 |
21 | void set(int year, int month, int date, int hour, int minute) 设置年、月、日、小时、分钟的值。 |
22 | void set(int year, int month, int date, int hour, int minute, int second) 设置年、月、日、小时、分钟、秒的值。 |
23 | void setGregorianChange(Date date) 设置 GregorianCalendar 的更改日期。 |
24 | void setTime(Date date) 用给定的日期设置Calendar的当前时间。 |
25 | void setTimeInMillis(long millis) 用给定的long型毫秒数设置Calendar的当前时间。 |
26 | void setTimeZone(TimeZone value) 用给定时区值设置当前时区。 |
27 | String toString() 返回代表日历的字符串。 |
实例
import java.util.*;
public class GregorianCalendarDemo {
public static void main(String args[]) {
String months[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
int year;
// 初始化 Gregorian 日历
// 使用当前时间和日期
// 默认为本地时间和时区
GregorianCalendar gcalendar = new GregorianCalendar();
// 显示当前时间和日期的信息
System.out.print("Date: ");
System.out.print(months[gcalendar.get(Calendar.MONTH)]);
System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
System.out.println(year = gcalendar.get(Calendar.YEAR));
System.out.print("Time: ");
System.out.print(gcalendar.get(Calendar.HOUR) + ":");
System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
System.out.println(gcalendar.get(Calendar.SECOND));
// 测试当前年份是否为闰年
if(gcalendar.isLeapYear(year)) {
System.out.println("当前年份是闰年");
}
else {
System.out.println("当前年份不是闰年");
}
}
}
以上实例编译运行结果如下:
Date: Apr 22 2009
Time: 11:25:27
当前年份不是闰年
二、周期方法
周期是以年,月和日为单位的时间跨度。
支持负周期。
持续时间也是以秒和纳秒为单位测量的时间跨度。
持续时间表示机器的精确纳秒数。一个时期更适合人类。
1天,2个月,3天,4个月和5天都是周期的实例。2个月期间可能意味着不同的天数,具体取决于不同的月份。
我们可以使用以下方法创建 Period
。
static Period of(int years,int months, int days)
static Period ofDays(int days)
static Period ofMonths(int months)
static Period ofWeeks(int weeks)
static Period ofYears(int years)
以下代码显示了如何创建Period。
import java.time.Period;
public class Main {
public static void main(String[] args) {
Period p1 = Period.of(2, 3, 5); // 2 years, 3 months, and 5 days
Period p2 = Period.ofDays(2); // 2 days
Period p3 = Period.ofMonths(-3); // -3 months
Period p4 = Period.ofWeeks(3); // 3 weeks
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
System.out.println(p4);
}
}
上面的代码生成以下结果。
例2
Period支持加法,减法,乘法和求反运算。
除法运算执行整数除法,例如,除以3除以7为2。
以下代码显示如何使用周期上的操作。
import java.time.Period;
public class Main {
public static void main(String[] args) {
Period p1 = Period.ofDays(15);
System.out.println(p1);
Period p2 = p1.plusDays(12);
System.out.println(p2);
Period p3 = p1.minusDays(12);
System.out.println(p3);
Period p4 = p1.negated();
System.out.println(p4);
Period p5 = p1.multipliedBy(3);
System.out.println(p5);
}
}
上面的代码生成以下结果。
例3
Period plus()
向另一个周期添加一个周期。
Period minus()
从另一个周期中减去一个周期。
周期normalized()方法标准化年和月。该方法确保月份值保持在0到11之间。“2年零16个月"被标准化为“3年零4个月"。
import java.time.Period;
public class Main {
public static void main(String[] args) {
Period p1 = Period.of(2, 3, 5);
Period p2 = Period.of(1, 15, 28);
System.out.println(p1);
System.out.println(p2);
System.out.println(p1.minus(p2));
System.out.println(p1.plus(p2));
System.out.println(p1.plus(p2).normalized());
}
}
上面的代码生成以下结果。
Period Between
Date-Time API提供了计算两个日期和时间之间的已用时间的方法。
我们可以在ChronoUnit枚举中的一个常量上使用 between()
方法。
ChronoUnit枚举between()方法需要两个datetime对象并返回一个long。 如果第二个参数出现在第一个参数之前,它返回一个负数。
返回金额是两个日期和时间之间的完整单位数。 例如,在06:00和09:30之间调用HOURS.between(),返回值为3,而不是3.5。 而MINUTES.在06:00至09:30之间返回210。
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
LocalDate ld1 = LocalDate.of(2014, Month.JANUARY, 7);
LocalDate ld2 = LocalDate.of(2014, Month.MAY, 21);
long days = ChronoUnit.DAYS.between(ld1, ld2);
System.out.println(days);
LocalTime lt1 = LocalTime.of(6, 0);
LocalTime lt2 = LocalTime.of(9, 30);
long hours = ChronoUnit.HOURS.between(lt1, lt2);
System.out.println(hours);
long minutes = ChronoUnit.MINUTES.between(lt1, lt2);
System.out.println(minutes);
}
}
上面的代码生成以下结果。
Period Util
Date-Time API提供了计算两个日期和时间之间的已用时间的方法。
我们可以对一个日期时间相关类使用 until(end_date_or_time,time_unit)
方法,例如LocalDate,LocalTime,LocalDateTime,ZonedDateTime等。
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
LocalDate ld1 = LocalDate.of(2014, Month.JANUARY, 7);
LocalDate ld2 = LocalDate.of(2014, Month.MAY, 18);
LocalTime lt1 = LocalTime.of(7, 0);
LocalTime lt2 = LocalTime.of(9, 30);
long days = ld1.until(ld2, ChronoUnit.DAYS);
System.out.println(days);
long hours = lt1.until(lt2, ChronoUnit.HOURS);
System.out.println(hours);
long minutes = lt1.until(lt2, ChronoUnit.MINUTES);
System.out.println(minutes);
}
}
上面的代码生成以下结果。
三、Java 日期时间调整器
我们可能要将日期和时间调整为该月的第一个星期一或下一个星期二。
我们可以使用 TemporalAdjuster
界面来调整日期和时间。接口有一个方法, adjustInto()
,它接受一个时间并返回一个时间。
TemporalAdjusters
类包含返回不同类型的预定义日期调整器的静态方法。
以下代码显示了如何计算2014年1月1日之后的第一个星期一:
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
LocalDate ld1 = LocalDate.of(2014, Month.JANUARY, 1);
LocalDate ld2 = ld1.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println(ld1);
System.out.println(ld2);
}
}
上面的代码生成以下结果。
TemporalAdjusters
TemporalAdjusters定义了一些可用于调整日期的有用方法。
next(DayOfWeek dayOfWeek)
nextOrSame(DayOfWeek dayOfWeek)
previous(DayOfWeek dayOfWeek)
previousOrSame(DayOfWeek dayOfWeek)
firstInMonth(DayOfWeek dayOfWeek)
lastInMonth(DayOfWeek dayOfWeek)
dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)
firstDayOfMonth()
lastDayOfMonth()
firstDayOfYear()
lastDayOfYear()
firstDayOfNextMonth()
firstDayOfNextYear()
ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster)
以下代码显示了如何使用 dayOfWeekInMonth
。
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
LocalDate ld1 = LocalDate.of(2014, Month.MAY, 21);
System.out.println(ld1);
LocalDate ld2 = ld1.with(TemporalAdjusters.dayOfWeekInMonth(5, DayOfWeek.SUNDAY));
System.out.println(ld2);
}
}
上面的代码生成以下结果。
自定义调整
您可以使用ofDateAdjuster()方法为LocalDate创建自己的日期调整器。
以下代码创建日期调整程序。
import java.time.LocalDate;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
// Create an adjuster that retruns a date after 3 months and 2 days
TemporalAdjuster adjuster = TemporalAdjusters
.ofDateAdjuster((LocalDate date) -> date.plusMonths(3).plusDays(2));
LocalDate today = LocalDate.now();
LocalDate dayAfter3Mon2Day = today.with(adjuster);
System.out.println("Today: " + today);
System.out.println("After 3 months and 2 days: " + dayAfter3Mon2Day);
}
}
上面的代码生成以下结果: