Java中的JDK7和JDK8时间类详解

目录

一、JDK7时间类

1. Date类

2. Calendar类

3. SimpleDateFormat类

二、JDK8时间类

1. LocalDate类

2. LocalTime类

3. LocalDateTime类

4. ZoneId和时区处理

5. ZonedDateTime类

6. Instant类

7. DateTimeFormatter类

8. ChronoUnit枚举

9. Duration和Period类

10. Local类之间的关系

三、JDK7和JDK8时间类对比

四、从JDK7到JDK8的迁移

替换对应关系

转换代码示例

五、面试常见问题

总结


一、JDK7时间类

1. Date类

● Date类是一个JDK写好的javabean类,用来描述时间,精确到毫秒

● 利用空参构造创建的对象,默认表示系统当前时间

● 利用有参构造创建的对象,表示指定时间

构造方法说明

构造方法说明
public Date()创建Date对象,表示当前时间
public Date(long date)创建Date对象,表示指定毫秒值对应的时间

常用方法说明

方法名说明
public void setTime(long time)设置/修改时间的毫秒值
public long getTime()获取时间对象的毫秒值

使用示例

// 创建表示当前时间的Date对象
Date now = new Date();
System.out.println(now); // 输出如:Sun May 11 10:23:45 CST 2025

// 创建表示指定时间的Date对象(毫秒值)
Date specifiedDate = new Date(1000); // 1970年1月1日加上1000毫秒
System.out.println(specifiedDate);

// 获取Date对象的毫秒值
long timeInMillis = now.getTime();
System.out.println("毫秒值:" + timeInMillis);

2. Calendar类

● Calendar代表了系统当前时间的日历对象,可以单独修改、获取时间中的年,月,日

● 细节:Calendar是一个抽象类,不能直接创建对象

● 细节:

月份:范围是0~11,0代表1月

星期:在老外眼中,星期日是一个星期的第一天

即:1(星期日)2(星期一)3(星期二)4(星期三)5(星期四)6(星期五)7(星期六)

获取对象方法

方法名说明
public static Calendar getInstance()获取Calendar对象,默认表示当前时间

常用方法说明

方法名说明
public int get(int field)获取某个字段的值
public void set(int field, int value)设置某个字段的值
public void add(int field, int amount)为某个字段增加/减少指定量
public final Date getTime()转换成Date对象
public long getTimeInMillis()获取时间的毫秒值

常用字段常量

常量说明
Calendar.YEAR
Calendar.MONTH月(0-11)
Calendar.DAY_OF_MONTH
Calendar.HOUR12小时制小时
Calendar.HOUR_OF_DAY24小时制小时
Calendar.MINUTE分钟
Calendar.SECOND
Calendar.DAY_OF_WEEK星期几(1-7,1代表星期日)

使用示例

// 获取Calendar对象
Calendar calendar = Calendar.getInstance();

// 获取年、月、日
int year = calendar.get(Calendar.YEAR);
// 注意:月份从0开始,0代表1月,11代表12月
int month = calendar.get(Calendar.MONTH) + 1; // +1转换为人类习惯
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(year + "年" + month + "月" + day + "日");

// 设置年、月、日
calendar.set(Calendar.YEAR, 2026);
calendar.set(Calendar.MONTH, 0); // 1月
calendar.set(Calendar.DAY_OF_MONTH, 1);

// 也可以一次性设置年、月、日
calendar.set(2026, 0, 1); // 2026年1月1日

// 日期计算
calendar.add(Calendar.DAY_OF_MONTH, 10); // 增加10天
calendar.add(Calendar.MONTH, -1); // 减少1个月

// 转换成Date对象
Date date = calendar.getTime();

3. SimpleDateFormat类

● 格式化:把时间变成我们喜欢的格式

● 解析:把字符串表示的时间变成Date对象

构造方法说明

构造方法说明
public SimpleDateFormat()构造一个SimpleDateFormat,使用默认格式
public SimpleDateFormat(String pattern)构造一个SimpleDateFormat,使用指定的格式

常用方法说明

方法名说明
public final String format(Date date)格式化(日期对象 -> 字符串)
public Date parse(String source)解析(字符串 -> 日期对象)

常用的模式字母

字母含义
y
M
d
H小时(24小时制)
h小时(12小时制)
m分钟
s
S毫秒
E星期几
a上午/下午标记

使用示例

// 创建日期对象
Date date = new Date();

// 使用默认格式化器
SimpleDateFormat defaultFormat = new SimpleDateFormat();
String defaultStr = defaultFormat.format(date);
System.out.println("默认格式:" + defaultStr); // 默认格式如:5/11/25 10:23 AM

// 自定义格式化器
SimpleDateFormat customFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String customStr = customFormat.format(date);
System.out.println("自定义格式:" + customStr); // 如:2025年05月11日 10:23:45

// 解析字符串为日期对象
try {
    String dateStr = "2025-05-11 10:23:45";
    SimpleDateFormat parseFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date parsedDate = parseFormat.parse(dateStr);
    System.out.println("解析结果:" + parsedDate);
} catch (Exception e) {
    e.printStackTrace();
}

注意事项

  • SimpleDateFormat不是线程安全的,在多线程环境下应该为每个线程创建独立的实例
  • 解析时,字符串的格式必须与SimpleDateFormat的模式匹配,否则会抛出ParseException
  • 默认格式说明
    无参构造函数 SimpleDateFormat() 使用的默认格式取决于当前 Java 虚拟机的区域设置(Locale)。常见 Locale 的默认格式示例如下:

    Locale日期默认格式时间默认格式日期 + 时间默认格式
    中文(中国)yyyy-M-dH:mm:ssyyyy-M-d H:mm:ss
    英文(美国)M/d/yyyyh:mm:ss aM/d/yyyy h:mm:ss a
    日文(日本)yyyy/MM/ddH:mm:ssyyyy/MM/dd H:mm:ss

二、JDK8时间类

1. LocalDate类

● LocalDate表示不带时区的日期(年月日)

● 该类是不可变的,所有的修改操作都会返回新的实例

创建对象的方法

方法名说明
public static LocalDate now()获取当前日期
public static LocalDate of(int year, int month, int dayOfMonth)获取指定年、月、日的日期
public static LocalDate parse(CharSequence text)解析字符串获得LocalDate对象

常用方法说明

方法名说明
public int getYear()获取年份
public int getMonthValue()获取月份(1-12)
public int getDayOfMonth()获取月份中的日期
public DayOfWeek getDayOfWeek()获取星期几
public LocalDate plusDays(long days)增加天数
public LocalDate plusMonths(long months)增加月数
public LocalDate plusYears(long years)增加年数
public LocalDate minusDays(long days)减少天数
public boolean isLeapYear()判断是否是闰年
public boolean isBefore(LocalDate other)判断是否在指定日期之前
public boolean isAfter(LocalDate other)判断是否在指定日期之后
public LocalDate withYear(int year)修改年份
public LocalDate withMonth(int month)修改月份
public LocalDate withDayOfMonth(int dayOfMonth)修改日期

使用示例

// 获取当前日期
LocalDate today = LocalDate.now();
System.out.println("今天的日期:" + today); // 输出如:2025-05-11

// 创建指定日期
LocalDate birthday = LocalDate.of(1990, 5, 15);
System.out.println("生日:" + birthday); // 输出:1990-05-15

// 解析日期字符串
LocalDate parsedDate = LocalDate.parse("2025-05-11");
System.out.println("解析的日期:" + parsedDate);

// 获取年、月、日信息
System.out.println("年:" + today.getYear());
System.out.println("月:" + today.getMonthValue()); // 注意:这里返回1-12
System.out.println("日:" + today.getDayOfMonth());
System.out.println("星期:" + today.getDayOfWeek()); // 返回如:SUNDAY

// 日期计算
LocalDate tomorrow = today.plusDays(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate lastYear = today.minusYears(1);

// 日期比较
boolean isBefore = today.isBefore(tomorrow); // true
boolean isAfter = today.isAfter(lastYear);   // true

// 修改日期
LocalDate changedDate = today.withYear(2030).withMonth(12).withDayOfMonth(25);
System.out.println("修改后的日期:" + changedDate); // 2030-12-25

2. LocalTime类

● LocalTime表示不带时区的时间(时分秒纳秒)

● 该类是不可变的,所有的修改操作都会返回新的实例

创建对象的方法

方法名说明
public static LocalTime now()获取当前时间
public static LocalTime of(int hour, int minute, int second)获取指定时、分、秒的时间
public static LocalTime parse(CharSequence text)解析字符串获得LocalTime对象

常用方法说明

方法名说明
public int getHour()获取小时
public int getMinute()获取分钟
public int getSecond()获取秒
public int getNano()获取纳秒
public LocalTime plusHours(long hours)增加小时
public LocalTime plusMinutes(long minutes)增加分钟
public LocalTime minusSeconds(long seconds)减少秒
public LocalTime withHour(int hour)修改小时
public LocalTime withMinute(int minute)修改分钟
public LocalTime withSecond(int second)修改秒

使用示例

// 获取当前时间
LocalTime now = LocalTime.now();
System.out.println("当前时间:" + now); // 输出如:10:23:45.123

// 创建指定时间
LocalTime specificTime = LocalTime.of(20, 30, 0);
System.out.println("指定时间:" + specificTime); // 输出:20:30:00

// 解析时间字符串
LocalTime parsedTime = LocalTime.parse("10:23:45");
System.out.println("解析的时间:" + parsedTime);

// 获取时间信息
System.out.println("小时:" + now.getHour());
System.out.println("分钟:" + now.getMinute());
System.out.println("秒:" + now.getSecond());

// 时间计算
LocalTime inOneHour = now.plusHours(1);
LocalTime halfHourAgo = now.minusMinutes(30);

// 修改时间
LocalTime changedTime = now.withHour(6).withMinute(30).withSecond(0);
System.out.println("修改后的时间:" + changedTime); // 06:30:00

3. LocalDateTime类

● LocalDateTime表示不带时区的日期和时间(年月日时分秒)

● 该类是不可变的,包含了LocalDate和LocalTime的所有信息

创建对象的方法

方法名说明
public static LocalDateTime now()获取当前日期和时间
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)获取指定日期和时间
public static LocalDateTime of(LocalDate date, LocalTime time)从LocalDate和LocalTime创建

常用方法说明

方法名说明
public LocalDate toLocalDate()转换为LocalDate
public LocalTime toLocalTime()转换为LocalTime
public int getYear()获取年份
public int getMonthValue()获取月份
public int getDayOfMonth()获取日
public int getHour()获取小时
public int getMinute()获取分钟
public LocalDateTime plusDays(long days)增加天数
public LocalDateTime minusMonths(long months)减少月数
public LocalDateTime withYear(int year)修改年份
public LocalDateTime withHour(int hour)修改小时

使用示例

// 获取当前日期和时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期和时间:" + now); // 输出如:2025-05-11T10:23:45.123

// 创建指定日期和时间
LocalDateTime dateTime = LocalDateTime.of(2025, 5, 11, 10, 23, 45);
System.out.println("指定日期和时间:" + dateTime);

// 从LocalDate和LocalTime创建
LocalDateTime combined = LocalDateTime.of(LocalDate.now(), LocalTime.now());

// 获取部分信息
System.out.println("年:" + now.getYear());
System.out.println("月:" + now.getMonthValue());
System.out.println("小时:" + now.getHour());

// 日期时间计算
LocalDateTime nextWeek = now.plusWeeks(1);
LocalDateTime threeHoursLater = now.plusHours(3);

// 转换为LocalDate或LocalTime
LocalDate justDate = now.toLocalDate();
LocalTime justTime = now.toLocalTime();

4. ZoneId和时区处理

● ZoneId表示时区ID,用于识别不同的时区

● Java 8支持多种时区表示方式

创建ZoneId的方法

方法名说明
static Set<String> getAvailableZoneIds()获取Java中支持的所有时区
static ZoneId systemDefault()获取系统默认时区
static ZoneId of(String zoneId)获取一个指定时区

常用时区ID示例

时区ID说明
"Asia/Shanghai"上海时间(北京时间)
"America/New_York"纽约时间
"Europe/London"伦敦时间
"UTC"协调世界时
"GMT+8"GMT偏移时间(北京时间)

使用示例

// 获取所有可用的时区ID
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
System.out.println("可用时区数量:" + zoneIds.size());

// 获取系统默认时区
ZoneId defaultZone = ZoneId.systemDefault();
System.out.println("系统默认时区:" + defaultZone);

// 创建特定时区
ZoneId shanghaiZone = ZoneId.of("Asia/Shanghai");
ZoneId newYorkZone = ZoneId.of("America/New_York");

// 将LocalDateTime转换为特定时区的ZonedDateTime
LocalDateTime dateTime = LocalDateTime.now();
ZonedDateTime shanghaiTime = dateTime.atZone(shanghaiZone);
ZonedDateTime newYorkTime = dateTime.atZone(newYorkZone);

System.out.println("上海时间:" + shanghaiTime);
System.out.println("纽约时间:" + newYorkTime);

5. ZonedDateTime类

● ZonedDateTime表示带时区的日期和时间

● 用于处理不同时区之间的日期时间转换

创建对象的方法

方法名说明
static ZonedDateTime now()获取当前时间的ZonedDateTime对象
static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)获取指定时间和时区的ZonedDateTime对象
static ZonedDateTime ofXxxx(...)获取指定时间的ZonedDateTime对象

常用方法说明

方法名说明
ZonedDateTime withXxx(时间)修改时间系列的方法
ZonedDateTime minusXxx(时间)减少时间系列的方法
ZonedDateTime plusXxx(时间)增加时间系列的方法
ZonedDateTime withZoneSameInstant(ZoneId zone)转换为另一个时区的相同时刻
ZonedDateTime withZoneSameLocal(ZoneId zone)转换为另一个时区的相同本地时间

使用示例

// 获取当前带时区的日期时间
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前日期时间:" + now);

// 创建特定时区的日期时间
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println("东京时间:" + tokyoTime);

// 从LocalDateTime创建ZonedDateTime
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Europe/Paris"));
System.out.println("巴黎时间:" + zonedDateTime);

// 时区转换(保持时刻相同)
ZonedDateTime newYorkTime = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println("纽约时间(同一时刻):" + newYorkTime);

// 时区转换(保持本地时间相同)
ZonedDateTime sydneyTime = zonedDateTime.withZoneSameLocal(ZoneId.of("Australia/Sydney"));
System.out.println("悉尼时间(同一本地时间):" + sydneyTime);

6. Instant类

● Instant表示时间线上的一个点(时间戳),精确到纳秒

● 可以用于记录应用程序中的事件时间戳

创建对象的方法

方法名说明
static Instant now()获取当前时间的Instant对象(标准时间)
static Instant ofEpochMilli(long epochMilli)根据(秒/毫秒/纳秒)获取Instant对象
ZonedDateTime atZone(ZoneId zone)指定时区

常用方法说明

方法名说明
boolean isXxx(Instant otherInstant)判断系列的方法
Instant minusXxx(long millisToSubtract)减少时间系列的方法
Instant plusXxx(long millisToSubtract)增加时间系列的方法
public long toEpochMilli()获取从1970-01-01T00:00:00Z开始的毫秒数
public long getEpochSecond()获取从1970-01-01T00:00:00Z开始的秒数

使用示例

// 获取当前时刻
Instant now = Instant.now();
System.out.println("当前时刻:" + now); // 输出如:2025-05-11T02:23:45.123456Z

// 从毫秒数创建Instant
Instant fromMillis = Instant.ofEpochMilli(System.currentTimeMillis());
System.out.println("从毫秒数创建:" + fromMillis);

// 获取时间戳
long epochSecond = now.getEpochSecond();
System.out.println("秒数:" + epochSecond);
long epochMilli = now.toEpochMilli();
System.out.println("毫秒数:" + epochMilli);

// 时间计算
Instant future = now.plusMillis(10000); // 增加10秒
Instant past = now.minusSeconds(60); // 减少1分钟

// 时间比较
boolean isBefore = past.isBefore(now); // true
boolean isAfter = future.isAfter(now); // true

// 转换为ZonedDateTime
ZonedDateTime zonedDateTime = now.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println("转换为上海时区:" + zonedDateTime);

7. DateTimeFormatter类

● DateTimeFormatter用于格式化和解析日期时间对象

● 该类是线程安全的,不像SimpleDateFormat

创建对象的方法

方法名说明
static DateTimeFormatter ofPattern(String pattern)通过格式模式字符串创建

常用方法说明

方法名说明
String format(TemporalAccessor temporal)按照指定方式格式化
TemporalAccessor parse(CharSequence text)解析字符串为时间对象

常用的预定义格式器

常量说明
ISO_LOCAL_DATE标准日期格式,如:2025-05-11
ISO_LOCAL_TIME标准时间格式,如:10:23:45
ISO_LOCAL_DATE_TIME标准日期时间格式,如:2025-05-11T10:23:45
ISO_OFFSET_DATE_TIME带时区偏移的日期时间,如:2025-05-11T10:23:45+08:00
ISO_ZONED_DATE_TIME带时区ID的日期时间,如:2025-05-11T10:23:45+08:00[Asia/Shanghai]

使用示例

// 创建日期时间对象
LocalDateTime dateTime = LocalDateTime.now();

// 使用预定义格式
String isoDate = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println("ISO日期:" + isoDate); // 如:2025-05-11

// 自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
String formatted = dateTime.format(formatter);
System.out.println("自定义格式:" + formatted); // 如:2025年05月11日 10时23分45秒

// 带时区的格式化
ZonedDateTime zonedDateTime = ZonedDateTime.now();
DateTimeFormatter zoneFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
System.out.println(zonedDateTime.format(zoneFormatter)); // 如:2025-05-11 10:23:45 CST

// 解析字符串
String dateStr = "2025年05月11日";
DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate parsedDate = LocalDate.parse(dateStr, parseFormatter);
System.out.println("解析结果:" + parsedDate);

8. ChronoUnit枚举

● ChronoUnit是TemporalUnit接口的实现,提供了各种时间单位

● 用于在时间点之间进行计算和测量时间差

常用的ChronoUnit常量

常量说明
YEARS
MONTHS
WEEKS
DAYS
HOURS小时
MINUTES分钟
SECONDS
MILLIS毫秒
MICROS微秒
NANOS纳秒
HALF_DAYS半天
DECADES十年
CENTURIES世纪
MILLENNIA千年
ERAS纪元

使用示例

// 创建两个时间点
LocalDateTime today = LocalDateTime.now();
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 0, 0, 0);

// 计算时间差
long years = ChronoUnit.YEARS.between(birthDate, today);
long months = ChronoUnit.MONTHS.between(birthDate, today);
long days = ChronoUnit.DAYS.between(birthDate, today);
long hours = ChronoUnit.HOURS.between(birthDate, today);
long minutes = ChronoUnit.MINUTES.between(birthDate, today);
long seconds = ChronoUnit.SECONDS.between(birthDate, today);
long millis = ChronoUnit.MILLIS.between(birthDate, today);
long micros = ChronoUnit.MICROS.between(birthDate, today);
long nanos = ChronoUnit.NANOS.between(birthDate, today);

System.out.println("相差的年数: " + years);
System.out.println("相差的月数: " + months);
System.out.println("相差的周数: " + ChronoUnit.WEEKS.between(birthDate, today));
System.out.println("相差的天数: " + days);
System.out.println("相差的小时数: " + hours);
System.out.println("相差的分钟数: " + minutes);
System.out.println("相差的秒数: " + seconds);
System.out.println("相差的毫秒数: " + millis);
System.out.println("相差的微秒数: " + micros);
System.out.println("相差的纳秒数: " + nanos);

9. Duration和Period类

● Duration表示两个时间之间的间隔(秒、纳秒)

● Period表示两个日期之间的间隔(年、月、日)

● ChronoUnit用于计算两个"日期"间隔

创建Duration对象的方法

方法名说明
static Duration between(Temporal startInclusive, Temporal endExclusive)计算两个时间之间的差
static Duration ofDays(long days)创建指定天数的Duration
static Duration ofHours(long hours)创建指定小时数的Duration

Duration常用方法

方法名说明
long toDays()将时间间隔转换为天数
long toHours()将时间间隔转换为小时数
long toMinutes()将时间间隔转换为分钟数
long toMillis()将时间间隔转换为毫秒数
long toNanos()将时间间隔转换为纳秒数

创建Period对象的方法

方法名说明
static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive)计算两个日期之间的差
static Period ofDays(int days)创建指定天数的Period
static Period ofMonths(int months)创建指定月数的Period
static Period ofYears(int years)创建指定年数的Period

Period常用方法

方法名说明
int getYears()获取年数
int getMonths()获取月数
int getDays()获取天数
long toTotalMonths()获取总月数

使用示例

// Duration示例 - 计算时间差
LocalDateTime today = LocalDateTime.now();
LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 0, 0, 0);

Duration duration = Duration.between(birthDate, today);
System.out.println("相差的时间间隔对象: " + duration); // 如:PT219637H27M42.639166S

System.out.println("===============================");
System.out.println("相差的天数: " + duration.toDays());
System.out.println("相差的小时数: " + duration.toHours());
System.out.println("相差的分钟数: " + duration.toMinutes());
System.out.println("相差的毫秒数: " + duration.toMillis());
System.out.println("相差的纳秒数: " + duration.toNanos());

// Period示例 - 计算日期差
LocalDate todayDate = LocalDate.now();
LocalDate birthDay = LocalDate.of(2000, 1, 1);

Period period = Period.between(birthDay, todayDate);
System.out.println("相差的时间间隔对象: " + period); // 如:P22Y6M17D

System.out.println("相差的年数: " + period.getYears());
System.out.println("相差的月数: " + period.getMonths());
System.out.println("相差的天数: " + period.getDays());
System.out.println("相差的总月数: " + period.toTotalMonths());

10. Local类之间的关系

JDK8的时间类中,Local系列(LocalDate、LocalTime、LocalDateTime)之间有明确的关系:

  • LocalDateTime 可以看作是 LocalDateLocalTime 的组合
  • 可以通过相互转换方法在它们之间进行转换

转换关系

方法名说明
public LocalDate toLocalDate()LocalDateTime转换成一个LocalDate对象
public LocalTime toLocalTime()LocalDateTime转换成一个LocalTime对象

使用示例

// LocalDateTime与LocalDate、LocalTime的转换
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期时间:" + now);

// 转换为LocalDate
LocalDate date = now.toLocalDate();
System.out.println("提取的日期:" + date);

// 转换为LocalTime
LocalTime time = now.toLocalTime();
System.out.println("提取的时间:" + time);

// 从LocalDate和LocalTime创建LocalDateTime
LocalDateTime combined = LocalDateTime.of(date, time);
System.out.println("组合后的日期时间:" + combined);

三、JDK7和JDK8时间类对比

比较项JDK7JDK8
可变性可变(线程不安全)不可变(线程安全)
月份从几开始0(0代表1月)1(1代表1月)
日期格式化SimpleDateFormat(线程不安全)DateTimeFormatter(线程安全)
时区支持有但不完善完善(ZonedDateTime)
API设计不直观直观、流畅
时间计算复杂简单
代码可读性较差较好
判断方法麻烦简单
计算时间间隔复杂简单(Duration/Period/ChronoUnit)

JDK7的问题与JDK8的改进

  • 代码层面:JDK7代码麻烦,JDK8简单直观
  • 安全层面:JDK7在多线程环境下容易出现数据安全问题,JDK8时间日期对象都是不可变的,解决了这个问题

四、从JDK7到JDK8的迁移

替换对应关系

  1. DateInstantLocalDateTime
  2. CalendarLocalDateLocalTimeLocalDateTimeZonedDateTime
  3. SimpleDateFormatDateTimeFormatter

转换代码示例

// JDK7的Date转换为JDK8的Instant
Date date = new Date();
Instant instant = date.toInstant();

// JDK7的Date转换为LocalDateTime
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

// JDK8的Instant转换回JDK7的Date
Date newDate = Date.from(instant);

// JDK7的Calendar转换为ZonedDateTime
Calendar calendar = Calendar.getInstance();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());

// JDK8的ZonedDateTime转换回Calendar
Calendar newCalendar = GregorianCalendar.from(zonedDateTime);

五、面试常见问题

1. JDK8中为什么要引入新的日期时间API?

旧的日期时间API存在诸多问题:

  • 线程不安全(Date和SimpleDateFormat都是可变的)
  • API设计不良(月份从0开始,年份从1900开始)
  • 时区支持不足
  • 操作复杂且容易出错

JDK8的新API修复了这些问题,提供了更好的设计和更丰富的功能。

2. SimpleDateFormat为什么不是线程安全的?

SimpleDateFormat在格式化或解析过程中会修改内部状态,多线程同时使用同一个实例会导致数据错乱或异常。它内部使用的Calendar对象也是可变的,这进一步加剧了线程安全问题。

3. JDK8中如何实现日期和时间的加减运算?

可以使用LocalDate、LocalTime或LocalDateTime的plus和minus方法,如plusDays()、minusMonths()等。还可以使用with*方法直接设置日期时间的某个字段,如withYear()、withMonth()等。

4. 如何在JDK7和JDK8的日期时间API之间进行转换?

// Date转Instant
Date date = new Date();
Instant instant = date.toInstant();

// Instant转Date
Date newDate = Date.from(instant);

// LocalDateTime转Date
LocalDateTime localDateTime = LocalDateTime.now();
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date = Date.from(instant);

// Date转LocalDateTime
Date date = new Date();
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

5. 如何处理不同时区的时间?

JDK8中使用ZonedDateTime类,它可以表示带时区的完整日期时间信息,并能够正确处理时区转换和夏令时调整。

// 创建不同时区的时间
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));

// 时区转换
ZonedDateTime converted = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));

总结

  1. JDK7的时间API(Date、Calendar、SimpleDateFormat)存在设计缺陷,使用不便且线程不安全。

  2. JDK8引入的新时间API(LocalDate、LocalTime、LocalDateTime、Instant等)解决了旧API的问题:

    • 不可变对象,保证线程安全
    • API设计更合理,月份从1开始
    • 功能更丰富,支持更多日期时间操作
    • 支持链式调用,代码更简洁
  3. 在新项目中应优先使用JDK8的时间API,旧项目可以考虑逐步迁移。

  4. 选择合适的类:

    • 只有日期:LocalDate
    • 只有时间:LocalTime
    • 日期和时间:LocalDateTime
    • 时间戳:Instant
    • 带时区:ZonedDateTime
    • 时间间隔:Duration(秒、纳秒)或Period(年、月、日)
    • 时间单位和计算:ChronoUnit

参考资料:部分JDK7时间类的说明和格式参考了黑马程序员的Java教程内容。API表格和示例代码也有部分来自黑马程序员的教程资料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值