1. jdk8 之前的日期 API
1.1. System 类 currentTimeMillis();
@Test
public void test1() {
long timeMillis = System.currentTimeMillis();
System.out.println("timeMillis = " + timeMillis);
}
1.2. java.util.Date 和 java.sql.Date
java.sql.Date
是java.util.Date
的子类:- 两个构造器的使用
new Date()
==> 获取当前的时间new Date(long timeMills)
==> 获取指定时间戳下的时间
- 两个方法的使用
- toString()
- getTime()==>获取当前Data对象的时间戳
Date date1 = new Date();
System.out.println("date1 = " + date1); //date1 = Tue Jul 06 09:47:42 CST 2021
System.out.println("date1.getTime() = " + date1.getTime()); //date1.getTime() = 1625536103670
Date date2 = new Date(123456789L);
System.out.println("date2 = " + date2); //date2 = Fri Jan 02 18:17:36 CST 1970
java.sql.Date date3 = new java.sql.Date(123456789L);
System.out.println("date3 = " + date3); //date3 = 1970-01-02
//将java.util.Date转换成java.sql.Date
java.sql.Date date4 = new java.sql.Date(date1.getTime());
System.out.println("date4 = " + date4); //date4 = 2021-07-06
1.3. java.text.SimpleDateFormat
@Test
public void test1() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat();
//格式化
Date date = new Date();
System.out.println("date = " + date);
String format = sdf.format(date);
System.out.println("format = " + format);
//解析
String str = "2019-08-12 12:00:00";
//设置解析日期字符串的模式,可以在创建SimpleDateFormat(String pattern);设置
sdf.applyPattern("yyyy-MM-dd hh:mm:ss");
sdf.parse(str);
System.out.println("str = " + str);
}
1.4. 线程安全的日期格式化工具类
public class DataUtils {
/**
* ThreadLocal 提供一种 lombda 构造方式
* 返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,
* 但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法
* 对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。
*/
private static ThreadLocal<DateFormat> threadLocal
= ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static Date parse(String date) {
try {
return threadLocal.get().parse(date);
} catch (Exception e) {
return null;
}
}
public static String format(Date date){
return date != null ? threadLocal.get().format(date) : null;
}
public static Date parse(String date, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(date);
} catch (Exception e) {
return null;
}
}
public static String format(Date date, String pattern){
return date != null ? new SimpleDateFormat(pattern).format(date) : null;
}
}
Letter | Date or Time Component | Examples |
---|---|---|
G | Era designator | AD |
y | Year | 1996; 96 |
Y | Week year | 2009; 09 |
M | Month in year (context sensitive) | July; Jul; 07 |
L | Month in year (standalone form) | July; Jul; 07 |
w | Week in year | 27 |
W | Week in month | 2 |
D | Day in year | 189 |
d | Day in month | 10 |
F | Day of week in month | 2 |
E | Day name in week | Tuesday; Tue |
u | Day number of week (1 = Monday, …, 7 = Sunday) | 1 |
a | Am/pm marker | PM |
H | Hour in day (0-23) | 0 |
k | Hour in day (1-24) | 24 |
K | Hour in am/pm (0-11) | 0 |
h | Hour in am/pm (1-12) | 12 |
m | Minute in hour | 30 |
s | Second in minute | 55 |
S | Millisecond | 978 |
z | Time zone | Pacific Standard Time; PST; GMT-08:00 |
Z | Time zone | -0800 |
X | Time zone | -08; -0800; -08:00 |
1.5. java.util.Calendar(日历)
Date
类的API大部分被废弃了,替换为Calendar
。Calendar
类是一个抽象类,主用用于完成日期字段之间相互操作的功能。- 获取
Calendar
实例的方法- 使用
Calendar.getInstance()
方法 - 调用它的子类
GregorianCalendar
(公历)的构造器。
- 使用
修饰符和类型 | 方法 | 描述 |
---|---|---|
static Calendar | getInstance() | 获取使用默认时区和区域设置的日历。 |
static Calendar | getInstance(Locale aLocale) | 获取使用默认时区和指定区域设置的日历。 |
static Calendar | getInstance(TimeZone zone) | 获取使用指定时区和默认区域设置的日历。 |
static Calendar | getInstance(TimeZone zone, Locale aLocale) | 获取具有指定时区和区域设置的日历。 |
Calendar 的相关方法:
public int get(int field)
:返回给定日历字段的值public void set(int field,int value)
:将给定的日历字段设置为指定的值public void add(int field,int amount)
:根据日历的规则,为给定的日历字段添加或者减去指定的时间量public final Date getTime()
:将Calendar转成Date对象public final void setTime(Date date)
:使用指定的Date对象重置Calendar的时间
其中 field
的值为 Calendar
的一组静态常量:YEAR
、MONTH
、DAY_OF_WEEK
、HOUR_OF_DAY
、MINUTE
、SECOND
等;
1.6. jdk8 之前的时间 API 缺陷
- 可变性:像日期、时间这样的类应该是不可变的;
- 偏移性:
Date
中的年份都是从 1900 年开始,月份都是从 0 开始的; - 格式化:格式化只对
Date
类型数据有效,无法应用于Calendar
; - 安全性:
Date
、Calendar
都是线程不安全的,此外还不能处理闰秒的情况;
2. jdk8 新增的时间 API
新的日期 API
java.time
:包含值对象的基础包java.time.chrono
:提供对不同的日历系统的访问java.time.format
:格式化和解析时间和日期java.time.temporal
:包括底层框架和扩展特性java.time.zone
:包含时区支持的类
大多数情况只会用到基础包和 format
包,偶尔会用到 temporal
包
2.1. LocalDate、LocalTime、LocalDateTime
LocalDate
代表 IOS 格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。LocalTime
表示一个时间,而不是日期。LocalDateTime
是用来表示日期和时间的,这是一个最常用的类之一。
方法 | 描述 |
---|---|
now()/now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
of(xx,xx,xx,xx,xx,xxx) | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth()/getDayOfYear() | 获得月份天数(1-31) /获得年份天数(1-366) |
getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
getMonth() | 获得月份, 返回一个 Month 枚举值 |
getMonthValue() / getYear() | 获得月份(1-12) /获得年份 |
getHours()/getMinute()/getSecond() | 获得当前对象对应的小时、分钟、秒 |
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
with(TemporalAdjuster t) | 将当前日期时间设置为校对器指定的日期时间 |
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
plus(TemporalAmount t)/minus(TemporalAmount t) | 添加或减少一个 Duration 或 Period |
isBefore()/isAfter() | 比较两个 LocalDate |
isLeapYear() | 判断是否是闰年(在LocalDate类中声明) |
format(DateTimeFormatter t) | 格式化本地日期、时间,返回一个字符串 |
parse(Charsequence text) | 将指定格式的字符串解析为日期、时间 |
@Test
public void test1() {
System.out.println("now()==============================");
//now(): 获取当前日期,时间,日期+时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDate = " + localDate); //2021-07-06
System.out.println("localTime = " + localTime); //18:05:16.139
System.out.println("localDateTime = " + localDateTime); //2021-07-06T18:05:16.140
System.out.println("of()===============================");
//of(): 根据指定日期/时间创建对象(没有偏移量)
LocalDateTime localDateTimeWithOf = LocalDateTime.of(1999, 06, 12, 6, 30, 0);
System.out.println("localDateTimeWithOf = " + localDateTimeWithOf); ///1999-06-12T06:30
//getXxx():
System.out.println("getXxx()===========================");
int dayOfMonth = localDateTime.getDayOfMonth();
System.out.println("dayOfMonth = " + dayOfMonth); //6
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
System.out.println("dayOfWeek = " + dayOfWeek); //TUESDAY
System.out.println("dayOfWeek.getValue() = " + dayOfWeek.getValue()); //2
System.out.println("with()=============================");
//with(): 修改指定值===>返回一个新的对象
LocalDateTime localDateTime1 = localDateTimeWithOf.withYear(2021);
System.out.println("localDateTime1 = " + localDateTime1); //2021-06-12T06:30
LocalDateTime localDateTime2 = localDateTime1.withDayOfYear(120);
System.out.println("localDateTime2 = " + localDateTime2); //2021-04-30T06:30
System.out.println("plusXxx()==========================");
//plusXxx(): 在指定的年月日/时间上加上指定的值===>返回新的对象
LocalDateTime localDateTime3 = localDateTime2.plusSeconds(30);
System.out.println("localDateTime3 = " + localDateTime3); //2021-04-30T06:30:30
LocalDateTime localDateTime4 = localDateTime3.plusHours(8);
System.out.println("localDateTime4 = " + localDateTime4); //2021-04-30T14:30:30
System.out.println("minusXxx()=========================");
//minusXxx(): 在指定的年月日/时间上减去指定的值===>返回新的对象
LocalDateTime localDateTime5 = localDateTime4.minusHours(8);
System.out.println("localDateTime5 = " + localDateTime5); //2021-04-30T06:30:30
LocalDateTime localDateTime6 = localDateTime5.minusDays(120);
System.out.println("localDateTime6 = " + localDateTime6); //2020-12-31T06:30:30
}
2.2. Instant
@Test
public void test1() {
//now(): 获取本初子午线对应的标准时间
Instant instant = Instant.now();
System.out.println("instant = " + instant);
//获取指定偏移量的标准时间,+表示东区;-表示西区
//获取东八区,即北京时间
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
//获取标准时间对应的时间戳
System.out.println("instant.toEpochMilli() = " + instant.toEpochMilli());
//通过指定的毫秒数,获取Instant实例
Instant instant1 = Instant.ofEpochMilli(1625569576277L);
System.out.println("instant1 = " + instant1.atOffset(ZoneOffset.ofHours(8)));
}
2.3. DateFormatter
格式化和解析日期时间
- 预定义的标准格式:ISO_LOCAL_DATE_TIME; ISO_LOCAL_DATE; ISO_LOCAL_TIME
- 本地化相关的格式:
ofLocalizedDateTime(FormatStyle.LONG)
FormatStyle.LONG
:2021年7月6日 下午07时52分01秒FormatStyle.MEDIUM
:2021-7-6 19:52:14FormatStyle.SHORT
:21-7-6 下午7:52
ofLocalizedDate(FormatStyle.LONG)
FormatStyle.FULL
:2021年7月6日 星期二FormatStyle.LONG
:2021年7月6日FormatStyle.MEDIUM
:2021-7-6FormatStyle.SHORT
:21-7-6
- 自定义的格式:ofPattern()
@Test
public void test1() {
//1.预定义的标准格式:ISO_LOCAL_DATE_TIME; ISO_LOCAL_DATE; ISO_LOCAL_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime localDateTime = LocalDateTime.now();
String format = formatter.format(localDateTime);
System.out.println("format = " + format); //2021-07-06T19:57:29.391
TemporalAccessor parse = formatter.parse("2021-07-06T19:42:01.801");
//将TemporalAccessor转为LocalDateTime
LocalDateTime localDateTime1 = LocalDateTime.from(parse);
System.out.println("localDateTime1 = " + localDateTime1); //2021-07-06T19:42:01.801
//2.本地化相关的格式:ofLocalizedDateTime(FormatStyle.LONG)
//提供了三个常量:
// FormatStyle.LONG: 2021年7月6日 下午07时52分01秒
// FormatStyle.MEDIUM: 2021-7-6 19:52:14
// FormatStyle.SHORT: 21-7-6 下午7:52
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
System.out.println(dateTimeFormatter.format(localDateTime)); //21-7-6 下午7:57
//3.本地化相关的格式:ofLocalizedDate(FormatStyle.LONG)
//提供了四个常量:
// FormatStyle.FULL: 2021年7月6日 星期二
// FormatStyle.LONG: 2021年7月6日
// FormatStyle.MEDIUM: 2021-7-6
// FormatStyle.SHORT: 21-7-6
dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
System.out.println(dateTimeFormatter.format(localDateTime)); //21-7-6
//4.自定义的格式:ofPattern()
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(dateTimeFormatter.format(localDateTime)); //2021-07-06
}
2.4. ZoneId 类中包含了所有的时区信息
ZoneId.getAvailableZoneIds();
获取所有的时区集LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
获取指定时区的时间
@Test
public void test1() {
//获得所有的时区集
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
//获取上海时区的当前时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("localDateTime = " + localDateTime); //2021-07-06T20:44:54.828
}
2.5. ZonedDateTime
带时区的日期时间
- ZonedDateTime.now(); 获取本时区的对象,不带时区
- ZonedDateTime.now(ZoneId.of(“Asia/Shanghai”)); 获取指定时区的对象
@Test
public void test2() {
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println("zonedDateTime = " + zonedDateTime); //2021-07-06T20:44:22.490+08:00[Asia/Shanghai]
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("zonedDateTime1 = " + zonedDateTime1); //2021-07-06T20:44:22.490+08:00[Asia/Shanghai]
}
2.6. Duration
用于计算两个“时间”间隔,以秒和纳秒为基准
Duration.between(TemporalAccessor time1, TemporalAccessor time2);
返回一个Duration
对象实例duration.getSeconds();
返回两个时间之间相差的秒数duration.getNano();
返回两个时间相差的毫微妙(Long),对1秒取余duration1.toDays();
返回两个时间相差的天数
@Test
public void test3() throws InterruptedException {
LocalTime localTime1 = LocalTime.now();
Thread.sleep(9543L);
LocalTime localTime2 = LocalTime.now();
Duration duration = Duration.between(localTime1, localTime2);
System.out.println("duration = " + duration); //duration = PT9.639S
System.out.println("duration.getSeconds() = " + duration.getSeconds());
//返回毫微妙级的long值
System.out.println("duration.getNano() = " + duration.getNano());
LocalDateTime localDateTime1 = LocalDateTime.of(2019, 6, 13, 8, 0, 0);
LocalDateTime localDateTime2 = LocalDateTime.of(2019, 6, 15, 13, 30, 0);
Duration duration1 = Duration.between(localDateTime1, localDateTime2);
System.out.println("duration1 = " + duration1);
System.out.println("duration1.toDays() = " + duration1.toDays());
}
2.7. Period
用于计算两个“日期”间隔,以年、月、日衡量
Period.between(localDate2, localDate1);
返回一个Period
对象实例period1.getYears()
、period1.getMonths()
、period1.getDays()
相差的年月日,三者拼在一起才是两个日期只差period1.withYears(int year);
设置Period
对象实例;period1.addTo(TemporalAccessor time);
把当前Period
对象记录的日期差加到指定的日期上,返回一个TemporalAccessor
@Test
public void test4() {
LocalDate localDate1 = LocalDate.of(2021, 7, 6);
LocalDate localDate2 = LocalDate.of(2020, 6, 13);
Period period1 = Period.between(localDate2, localDate1);
System.out.println("period1 = " + period1);
System.out.println("period1.getYears() = " + period1.getYears()); //1
System.out.println("period1.getMonths() = " + period1.getMonths()); //0
System.out.println("period1.getDays() = " + period1.getDays()); //23
//所以两个日期相差了1年零23天
//设置period1的值
Period period2 = period1.withYears(2);
//把当前相差的日期加到localDate1上,返回一个Date
Temporal temporal = period1.addTo(localDate1);
System.out.println("period2 = " + period2);
System.out.println("temporal = " + temporal);
}
2.8. TemporalAdjuster
时间校正器
@Test
public void test5() {
//获取当前日期的下一个周日是哪一天
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDate localDate = LocalDate.now().with(temporalAdjuster);
System.out.println("localDate = " + localDate);
//返回当前日期的下一个工作日是哪一天
LocalDate localDate2 = LocalDate.now().with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate date = (LocalDate) temporal;
if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
return date.plusDays(3);
} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
return date.plusDays(2);
} else {
return date.plusDays(1);
} }
});
System.out.println("localDate2 = " + localDate2);
}