Java基础快速入门: 时间和日期处理全解析

本文纲要

  1. 世界标准时间与计算机时间原点
  2. Date
    构造方法
    成员方法 getTime()setTime()
  3. SimpleDateFormat 格式化和解析
    格式化:将 Date 转换为字符串
    解析:将字符串转换为 Date
    综合练习:秒杀资格判断(含流程图)
  4. JDK8 新时间类
    为什么需要 JDK8 时间类
    体验 JDK8 的简洁
  5. LocalDateTime 获取时间对象
  6. LocalDateTime 获取时间中的每个值
  7. LocalDateTime 转换方法
  8. LocalDateTime 格式化与解析
  9. plus 系列方法:添加或减少时间
  10. minus 系列方法:减少或增加时间
  11. with 系列方法:修改时间
  12. 时间间隔对象 PeriodDuration
  13. JDK8 时间类小结

世界标准时间与计算机时间原点

在深入学习 Java 时间 API 之前,有必要了解几个背景知识。

  • 世界标准时间:格林威治标准时间(Greenwich Mean Time,GMT),由英国伦敦格林威治天文台提供,现已被更精确的原子钟替代(误差每两千万年仅一秒)。我国采用北京时间,位于东八区,需在标准时间上加 8 小时

  • 时间单位换算1 秒 = 1000 毫秒1 毫秒 = 1000 微秒1 微秒 = 1000 纳秒。其中“1 秒 = 1000 毫秒”使用最频繁。

  • 计算机时间原点:1970 年 1 月 1 日 00:00:00(Unix 纪元),这也是 C 语言的诞生时间,Java 继承了该传统。System.currentTimeMillis() 返回的正是从该原点至今的毫秒数。

Date 类

Java 中 java.util.Date 类表示一个特定的时间,精确到毫秒。本节演示代码位于 com.wb.mydate 包下,项目结构如下:

src 
└── com 
    └── wb 
        ├── mydate 
        │   ├── DateDemo1.java 
        │   ├── DateDemo2.java 
        │   ├── DateDemo3.java 
        │   ├── DateDemo4.java 
        │   └── DateDemo5.java 
        └── jdk8date 
            ├── JDK8DateDemo1.java 
            ├── JDK8DateDemo2.java 
            ...
            └── JDK8DateDemo10.java

1 ) 构造方法

Date 提供两个常用构造:

  • Date():空参构造,封装当前系统时间。
  • Date(long date):带参构造,从时间原点经过指定毫秒后的时间(注意东八区需 +8 小时)。

示例

// DateDemo1.java 
package com.wb.mydate;
 
import java.util.Date;
 
public class DateDemo1 {
    public static void main(String[] args) {
        // 空参构造:表示当前时间 
        Date date1 = new Date();
        System.out.println(date1);
 
        // 带参构造:从时间原点经过 0 毫秒 → 1970-01-01 08:00:00 (东八区)
        Date date2 = new Date(0L);
        System.out.println(date2);
 
        // 表示 1970年1月1日 上午9点(1小时 = 3600秒 × 1000 毫秒)
        Date date3 = new Date(3600L * 1000);
        System.out.println(date3);
    }
}

要点:

  • 空参构造获得当前时间。
  • 带参构造传入毫秒值,基准是 1970-01-01 08:00:00(北京时间)。

2 ) 成员方法 getTime() 和 setTime()

  • getTime():返回该 Date 对象对应的毫秒值(从时间原点开始的毫秒数)。
  • setTime(long time):设置 Date 对象的时间(传入毫秒值)。

示例

// DateDemo2.java 
package com.wb.mydate;
 
import java.util.Date;
 
public class DateDemo2 {
    public static void main(String[] args) {
        // method1();  // 获取毫秒值 
        // method2();  // 设置时间 
    }
 
    // 演示 getTime()
    private static void method1() {
        Date date1 = new Date();                       // 当前时间 
        long time = date1.getTime();                   // 获取毫秒值 
        System.out.println(time);
 
        long time2 = System.currentTimeMillis();       // 与系统方法对比 
        System.out.println(time2);
    }
 
    // 演示 setTime()
    private static void method2() {
        Date date1 = new Date();                       // 当前时间 
        date1.setTime(0L);                             // 设置为时间原点 
        System.out.println(date1);
    }
}

SimpleDateFormat 格式化和解析

SimpleDateFormat 位于 java.text 包,用于将 Date 对象与字符串相互转换,自定义时间显示格式。

常用模式字母:

字母含义
y
M
d
H时(0-23)
m
s

1 ) 格式化:将 Date 转换为字符串

// DateDemo3.java 
package com.wb.mydate;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DateDemo3 {
    public static void main(String[] args) {
        Date date = new Date();                               // 当前时间 
 
        // 创建格式对象,指定输出样式 
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 
        String result = sdf.format(date);                     // 格式化 
        System.out.println(result);
    }
}

格式字符串中的字母必须严格使用上表,其他字符原样输出。

2 ) 解析:将字符串转换为 Date

// DateDemo4.java 
package com.wb.mydate;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DateDemo4 {
    public static void main(String[] args) throws ParseException {
        String s = "2048-01-01";
 
        // 解析时格式必须与字符串格式完全一致 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 
        Date date = sdf.parse(s);                             // 解析成 Date 
        System.out.println(date);
    }
}

解析时若格式不匹配会抛出 ParseException。

3 ) 综合练习:秒杀资格判断

秒杀活动:开始时间 2020 年 11 月 11 日 0:0:0,结束时间同一天 0:10:0。
小贾下单时间:0:03:47,小皮下单时间:0:10:11。判断谁成功参与。

解题思路:将时间字符串转换为毫秒值进行比较。

开始

将开始、结束、下单时间字符串用 SimpleDateFormat 解析为 Date

通过 getTime 获得毫秒值

下单时间 >= 开始 且 <= 结束?

参加成功

未参加

// DateDemo5.java 
package com.wb.mydate;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
public class DateDemo5 {
    public static void main(String[] args) throws ParseException {
        String start = "2020年11月11日 0:0:0";
        String end   = "2020年11月11日 0:10:0";
        String jia   = "2020年11月11日 0:03:47";
        String pi    = "2020年11月11日 0:10:11";
 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
 
        // 所有时间转为毫秒值 
        long startTime = sdf.parse(start).getTime();
        long endTime   = sdf.parse(end).getTime();
        long jiaTime   = sdf.parse(jia).getTime();
        long piTime    = sdf.parse(pi).getTime();
 
        // 判断小贾 
        if (jiaTime >= startTime && jiaTime <= endTime) {
            System.out.println("小贾同学参加上了秒杀活动");
        } else {
            System.out.println("小贾同学没有参加上秒杀活动");
        }
 
        System.out.println("------------------------");
 
        // 判断小皮 
        if (piTime >= startTime && piTime <= endTime) {
            System.out.println("小皮同学参加上了秒杀活动");
        } else {
            System.out.println("小皮同学没有参加上秒杀活动");
        }
    }
}

输出结果:小贾参加成功,小皮失败(10:11 超出了结束时间)。

JDK8 新时间类

JDK7 之前用 Date + SimpleDateFormat 进行时间计算时需要反复转换(字符串 → Date → 毫秒 → 加/减 → Date → 字符串),代码繁琐易错。JDK8 引入了全新的时间 API,代码更简洁、语义更清晰。

体验 JDK8 的简洁

需求:将 2020年11月11日 00:00:00 加 1 天。

JDK7 方式:

// JDK8DateDemo1.java (部分)
private static void JDKMethod() throws ParseException {
    String s = "2020年11月11日 00:00:00";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
    Date date = sdf.parse(s);
    long time = date.getTime();
    time = time + (1000 * 60 * 60 * 24);       // 加一天的毫秒 
    Date newDate = new Date(time);
    String result = sdf.format(newDate);
    System.out.println(result);
}

JDK8 方式:

// JDK8DateDemo1.java 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
public class JDK8DateDemo1 {
    public static void main(String[] args) {
        String s = "2020年11月11日 00:00:00";
 
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        LocalDateTime localDateTime = LocalDateTime.parse(s, pattern);
        LocalDateTime newLocalDateTime = localDateTime.plusDays(1);   // 直接加1天 
        String result = newLocalDateTime.format(pattern);
        System.out.println(result);
    }
}

对比可见,JDK8 API 省去了毫秒值的中间计算,代码更直观

LocalDateTime 获取时间对象

JDK8 将时间细化为三个类:

  • LocalDate:只包含年、月、日。
  • LocalTime:只包含时、分、秒。
  • LocalDateTime:包含年、月、日、时、分、秒。

常用创建方法:

  • now():静态方法,获取当前系统时间。
  • of(int year, int month, int day, int hour, int minute, int second):指定时间。
// JDK8DateDemo2.java 
package com.wb.jdk8date;
 
import java.time.LocalDateTime;
 
public class JDK8DateDemo2 {
    public static void main(String[] args) {
        // 当前时间 
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
 
        // 指定时间:2020年11月11日 11:11:11 
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 11, 11, 11, 11);
        System.out.println(localDateTime);
    }
}

of 方法的参数有范围限制(如月份 1-12),超出会抛出异常。

LocalDateTime 获取时间中的每个值

LocalDateTime 提供了丰富的 get 方法,直接获取各个字段,返回 int 类型:

// JDK8DateDemo3.java 
package com.wb.jdk8date;
 
import java.time.LocalDateTime;
 
public class JDK8DateDemo3 {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 11, 11, 11, 20);
 
        int year = localDateTime.getYear();                    // 年 
        int month = localDateTime.getMonthValue();             // 月 (1-12)
        int day = localDateTime.getDayOfMonth();               // 日 (1-31)
        int dayOfYear = localDateTime.getDayOfYear();          // 一年中的第几天 
        int minute = localDateTime.getMinute();                // 分钟 
        int hour = localDateTime.getHour();                    // 小时 
 
        System.out.println("年:" + year);
        System.out.println("月:" + month);
        System.out.println("日:" + day);
        System.out.println("一年中第 " + dayOfYear + " 天");
        System.out.println("小时:" + hour);
        System.out.println("分钟:" + minute);
    }
}

注意:getMonth() 返回的是枚举类型 Month(如 NOVEMBER),getDayOfWeek() 返回 DayOfWeek 枚举。一般获取数值时推荐使用 getMonthValue()getDayOfMonth() 等。

LocalDateTime 转换方法

若只关心日期或只关心时间,可在 LocalDateTime 基础上转换:

  • toLocalDate() → 仅保留年、月、日。
  • toLocalTime() → 仅保留时、分、秒。
// JDK8DateDemo4.java 
package com.wb.jdk8date;
 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
 
public class JDK8DateDemo4 {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2020, 12, 12, 8, 10, 12);
 
        LocalDate localDate = localDateTime.toLocalDate();   // 2020-12-12 
        LocalTime localTime = localDateTime.toLocalTime();   // 08:10:12 
 
        System.out.println(localDate);
        System.out.println(localTime);
    }
}

LocalDateTime 格式化与解析

JDK8 使用 DateTimeFormatter 替代 SimpleDateFormat,用法类似。

  • 格式化:format() 方法。
  • 解析:静态方法 parse(字符串, 格式器)
// JDK8DateDemo5.java 
package com.wb.jdk8date;
 
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
 
public class JDK8DateDemo5 {
    public static void main(String[] args) {
        // 格式化 
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 12, 13, 14, 15);
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        String s = localDateTime.format(pattern);
        System.out.println(s);
 
        // 解析 
        String str = "2020年11月12日 13:14:15";
        LocalDateTime parse = LocalDateTime.parse(str, pattern);
        System.out.println(parse);
    }
}

plus 系列方法:添加或减少时间

plusXxx() 方法返回一个新的 LocalDateTime 对象,参数为正数时向后添加,负数时向前减少

常用方法:plusYears(), plusMonths(), plusDays(), plusHours(), plusMinutes()

// JDK8DateDemo6.java 
package com.wb.jdk8date;
 
import java.time.LocalDateTime;
 
public class JDK8DateDemo6 {
    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
 
        // 加 1 年 → 2021-11-11 13:14:15 
        LocalDateTime newLocalDateTime = localDateTime.plusYears(1);
        System.out.println(newLocalDateTime);
 
        // 加 -1 年 → 相当于减 1 年 → 2019-11-11 13:14:15 
        LocalDateTime newLocalDateTime2 = localDateTime.plusYears(-1);
        System.out.println(newLocalDateTime2);
    }
}

minus 系列方法:减少或增加时间

minusXxx() 方法与 plus 语义相反:正数向前减少,负数向后增加。

// JDK8DateDemo7.java
package com.wb.jdk8date;

import java.time.LocalDateTime;
 
/**
 * JDK8 时间类减少或者添加时间的方法
 */
public class JDK8DateDemo7 {
    public static void main(String[] args) {
        // public LocalDateTime minusYears(long years)  减去或者添加年
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
 
        // 减 1 年 → 2019-11-11 13:14:15
        LocalDateTime newLocalDateTime1 = localDateTime.minusYears(1);
        System.out.println(newLocalDateTime1);
 
        // 减 -1 年 → 相当于加 1 年 → 2021-11-11 13:14:15
        LocalDateTime newLocalDateTime2 = localDateTime.minusYears(-1);
        System.out.println(newLocalDateTime2);
    }
}

日常开发中更推荐使用 plus 系列,语义更符合直觉

with 系列方法:修改时间

withXxx() 方法用于直接修改某个字段的值,返回新对象。注意参数必须在合法范围内(如月份 1-12),否则抛出异常。

// JDK8DateDemo8.java
package com.wb.jdk8date;
 
import java.time.LocalDateTime;
 
/**
 * JDK8 时间类修改时间 
 */
public class JDK8DateDemo8 {
    public static void main(String[] args) {
        // public LocalDateTime withYear(int year)   修改年
        LocalDateTime localDateTime = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
 
        // 修改年份为 2048 → 2048-11-11 13:14:15
        LocalDateTime newLocalDateTime1 = localDateTime.withYear(2048);
        System.out.println(newLocalDateTime1);
 
        // 修改月份为 20(超出范围)→ 抛出 DateTimeException
        // LocalDateTime newLocalDateTime2 = localDateTime.withMonth(20);
        // System.out.println(newLocalDateTime2);
    }
}

时间间隔对象 Period 和 Duration

JDK8 提供两个类用于计算时间间隔:

  • Period:基于 LocalDate,计算两个日期之间的年、月、日。
    通过 Period.between(开始日期, 结束日期) 获取间隔对象,再调用 getYears()getMonths()getDays()toTotalMonths() 等方法
  • Duration:基于包含时间的类(如 LocalDateTime、LocalTime),计算两个时间之间的秒、毫秒、纳秒。通过 Duration.between(开始时间, 结束时间) 获取间隔对象,再调用 toSeconds()toMillis()toNanos() 等方法。
// JDK8DateDemo9.java
package com.wb.jdk8date;
 
import java.time.LocalDate;
import java.time.Period;
 
/**
 * 计算两个日期的间隔(年、月、日)
 */
public class JDK8DateDemo9 {
    public static void main(String[] args) {
        LocalDate localDate1 = LocalDate.of(2020, 1, 1);
        LocalDate localDate2 = LocalDate.of(2048, 12, 12);
 
        Period period = Period.between(localDate1, localDate2);
        System.out.println(period);                    // P28Y11M11D 
 
        System.out.println("年数:" + period.getYears());       // 28 
        System.out.println("月数:" + period.getMonths());      // 11 
        System.out.println("天数:" + period.getDays());        // 11 
        System.out.println("总月数:" + period.toTotalMonths()); // 347 
    }
}
// JDK8DateDemo10.java
package com.wb.jdk8date;
 
import java.time.Duration;
import java.time.LocalDateTime;
 
/**
 * 计算两个时间的间隔(秒、毫秒、纳秒)
 */
public class JDK8DateDemo10 {
    public static void main(String[] args) {
        LocalDateTime localDateTime1 = LocalDateTime.of(2020, 1, 1, 13, 14, 15);
        LocalDateTime localDateTime2 = LocalDateTime.of(2020, 1, 2, 11, 12, 13);
 
        Duration duration = Duration.between(localDateTime1, localDateTime2);
        System.out.println(duration);                          // PT21H57M58S
 
        System.out.println("秒数:" + duration.toSeconds());    // 79078
        System.out.println("毫秒:" + duration.toMillis());     // 79078000
        System.out.println("纳秒:" + duration.toNanos());      // 79078000000000 
    }
}

JDK8 时间类小结

JDK8 新时间 API 的核心要点:

分类关键类/方法说明
日期时间类LocalDate / LocalTime / LocalDateTime分别表示日期、时间、日期+时间
创建对象now()of(...)当前时间 / 指定时间
获取字段getYear()getMonthValue()getDayOfMonth()获取年、月、日、时、分、秒
转换toLocalDate()toLocalTime()LocalDateTime 提取日期或时间
格式化/解析DateTimeFormatter.ofPattern() + format() / parse()替代 SimpleDateFormat
时间加减plusXxx() / minusXxx()参数正数向前,负数向后
修改字段withXxx()直接修改某个字段,返回新对象
时间间隔Period.between() / Duration.between()计算日期间隔(年月日) / 时间间隔(秒毫秒纳秒)

所有方法均返回新对象,原对象不受影响,符合不可变设计。遇到遗忘的方法,可查阅 JDK API 文档,通过 LocalDateTime 等类名快速定位

从古老的 Date 到简洁的 JDK8 时间类,到现在已经掌握了 Java 时间处理的核心技能。多加练习,熟能生巧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值