Java——三代日期类

一、简要介绍

Java 的日期处理经历了三个主要的阶段:java.util.Datejava.util.Calendar(第一代)、Java 8 的 java.time(第二代),以及后来的Java 9 和后续版本对 java.time 的改进(第三代)。下面我将分别详细介绍这三个阶段。

二、第一代日期类

1、java.util.Date

1)简要介绍

Java 的最初日期类。它表示特定的瞬时时间,内部使用的是从1970年1月1日00:00:00 UTC开始的毫秒数。
该类有一些设计缺陷,比如缺乏对时区的明确支持等。现在其中许多方法已被标记为过时。

2)使用示例

一般情况下,Date 类是与 SimpleDateFormat 类配合使用的,SimpleDateFormat 是专门设计格式化和解析 Date 对象的。

示例一:获取当前时间并格式化

import java.text.SimpleDateFormat;
import java.util.Date;

public class Example {
	public static void main(String[] args) {
		// 创建一个 SimpleDateFormat 实例,指定日期格式
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		// 获取当前日期
		Date currentDate = new Date();
		System.out.println("当前日期对象: " + currentDate);

		// 使用 SimpleDateFormat 将 Date 对象格式化为特定格式字符串
		String formattedDate = dateFormat.format(currentDate);
		System.out.println("格式化后的日期字符串: " + formattedDate);
	}
}

运行结果:

运行结果

示例二:解析一个字符串表示的时间

给出的字符串的格式需要与你创建的 SimpleDateFormat 的格式一致,不然会抛出 parseException 异常,这个异常是编译时异常,必须处理。

import java.text.SimpleDateFormat;
import java.util.Date;

public class Example {
	public static void main(String[] args) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		// 解析字符串为 Date 对象
		String dateString = "2023-04-10 14:30:00";
		try {
			// 使用 parse 方法可能抛出 ParseException,
			// 这个异常是编译时异常,所以必须处理
			Date parsedDate = dateFormat.parse(dateString);
			System.out.println("解析后的日期对象: " + parsedDate);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

运行结果:

运行结果

示例三:使用毫秒数指定时间并格式化

注意这里如果输入的毫秒数的值比较大,则需使用 L 表示数值是 long 类型。

import java.text.SimpleDateFormat;
import java.util.Date;

public class Example {
	public static void main(String[] args) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		// 使用毫秒数创建 Date 对象
		Date date = new Date(1732871526000L);

		// 将 Date 对象格式化,然后输出
		System.out.println("格式化时间:" + dateFormat.format(date));
	}
}

运行结果:

运行结果

2、java.util.Calendar

1)简要介绍

为了解决 Date 类的一些不足,Java引入了 Calendar 类。它提供了对日期和时间的更灵活的操作。Calendar 是一个抽象类,它不能被直接实例化,但是它提供了许多的静态方法来获得 Calendar 实现类的实例(例如 Calendar.getInstance())。该类支持多种日历系统和时区,提供了更多的日期操作方法,例如增加天数、获取月份等。

使用 Calendar.getInstance() 方法。通常会根据系统的当前时区和默认语言环境返回一个 Calendar 的实现类(通常是 GregorianCalendar 的实例)

2)一些常用字段

Calendar 类中定义了一些常量字段,常用的包括:

  • Calendar.YEAR:年份
  • Calendar.MONTH:月份
  • Calendar.DAY_OF_MONTH:一个月中的日期
  • Calendar.HOUR:12小时制的小时
  • Calendar.HOUR_OF_DAY:24小时制的小时
  • Calendar.MINUTE:分钟
  • Calendar.SECOND:秒
  • Calendar.MILLISECOND:毫秒
  • Calendar.DAY_OF_WEEK:一周中的日期

显然这些字段都是静态的,它们实际上都被编了号,通过这些编号,我们可以通过 Calendar 的实例来调用 public int get(int field) 方法来获取实例的某个字段,所以上面这些静态常量字段的作用就是用来作为 field 参数。

我们可以查看这些静态常量的定义:

    public final static int ERA = 0;
    public final static int YEAR = 1;
    public final static int MONTH = 2;
    public final static int WEEK_OF_YEAR = 3;
    public final static int WEEK_OF_MONTH = 4;
    public final static int DATE = 5;
    public final static int DAY_OF_MONTH = 5;
    public final static int DAY_OF_YEAR = 6;
    public final static int DAY_OF_WEEK = 7;

3)使用示例

import java.util.Calendar;

public class Example {
	public static void main(String[] args) {
		// 获取当前日期和时间的 Calendar 实例
		Calendar calendar = Calendar.getInstance();

		// 获取当前年份
		int year = calendar.get(Calendar.YEAR);
		System.out.println("年份: " + year);

		// 获取当前月份
		// 注意对于月份计数是从 0 开始的,所以获取到月份后要加一
		int month = calendar.get(Calendar.MONTH) + 1; // 由于月份从0开始,需加1
		System.out.println("月份: " + month);

		// 获取当前日期
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		System.out.println("日期: " + day);

		// 获取当前小时(24小时制)
		int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
		System.out.println("24小时制的小时: " + hourOfDay);

		// 获取当前分钟
		int minute = calendar.get(Calendar.MINUTE);
		System.out.println("分钟: " + minute);

		// 获取当前秒
		int second = calendar.get(Calendar.SECOND);
		System.out.println("秒: " + second);

		// 获取当前星期几
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		System.out.println("星期几: " + dayOfWeek);

		// 设置日期为2024年1月1日
		calendar.set(Calendar.YEAR, 2024);
		calendar.set(Calendar.MONTH, Calendar.JANUARY); // 设置为1月
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		// 打印设置后的日期
		System.out.println("设置后的日期: " + calendar.getTime());

		// 增加10天
		calendar.add(Calendar.DAY_OF_MONTH, 10);
		System.out.println("增加10天后的日期: " + calendar.getTime());

		// 减少一个月
		calendar.add(Calendar.MONTH, -1);
		System.out.println("减少一个月后的日期: " + calendar.getTime());

		// 获取当前时间的毫秒值
		long millis = calendar.getTimeInMillis();
		System.out.println("自1970年1月1日以来的毫秒数: " + millis);
	}
}

运行结果:

运行结果

3、补充

  1. 可变性
    • Date 对象是可变的,这意味着在使用它时可能会不小心修改其值。这会导致在多线程环境中出现意外的并发问题。
  2. 线程不安全
    • 由于 Date 对象是可变的,多个线程同时访问同一个 Date 实例可能会导致不一致的结果。

三、第二代日期类

1、简要介绍

Java 8 引入了新的日期和时间 API,位于 java.time 包中,旨在补充和改进之前的日期和时间类。这个新的 API 灵感来自于 Joda-Time 库,更加现代、易用且线程安全。主要的类有:

  • LocalDate:表示没有时区的日期(年、月、日)。
  • LocalTime:表示没有时区的时间(时、分、秒)。
  • LocalDateTime:结合了日期和时间。
  • ZonedDateTime:表示具有时区的日期和时间。
  • Instant:表示时间戳(从1970年1月1日00:00:00 UTC起的时间点)。

2、LocalDate

LocalDate 表示没有时区的日期(年、月、日)。

import java.time.LocalDate;

public class Example {
	public static void main(String[] args) {
		// 获取当前日期
		LocalDate today = LocalDate.now();
		System.out.println("今天的日期: " + today);

		// 创建特定日期
		LocalDate specificDate = LocalDate.of(2024, 1, 1);
		System.out.println("特定日期: " + specificDate);

		// 获取日期的年份、月份、日
		int year = today.getYear();
		int month = today.getMonthValue();
		int day = today.getDayOfMonth();
		System.out.println("年份: " + year + ", 月份: " + month + ", 日期: " + day);

		// 增加天数
		LocalDate nextWeek = today.plusDays(7);
		System.out.println("一周后的日期: " + nextWeek);

		// 减少天数
		LocalDate lastWeek = today.minusDays(7);
		System.out.println("一周前的日期: " + lastWeek);

		// 判断是否是闰年
		boolean isLeapYear = today.isLeapYear();
		System.out.println("是否是闰年: " + isLeapYear);
	}
}

运行结果:

运行结果

3、LocalTime

LocalTime 表示没有时区的时间(时、分、秒)。

import java.time.LocalTime;

public class Example {
	public static void main(String[] args) {
		// 获取当前时间
		LocalTime now = LocalTime.now();
		System.out.println("当前时间: " + now);

		// 创建特定时间
		LocalTime specificTime = LocalTime.of(11, 45, 14); // 11:45:14
		System.out.println("特定时间: " + specificTime);

		// 获取时间的小时、分钟、秒
		int hour = now.getHour();
		int minute = now.getMinute();
		int second = now.getSecond();
		System.out.println("小时: " + hour + ", 分钟: " + minute + ", 秒: " + second);

		// 增加分钟
		LocalTime later = now.plusMinutes(30);
		System.out.println("30分钟后的时间: " + later);

		// 减少秒
		LocalTime earlier = now.minusSeconds(45);
		System.out.println("45秒前的时间: " + earlier);
	}
}

运行结果:

运行结果

4、LocalDateTime

LocalDateTime 结合了日期和时间。

import java.time.LocalDateTime;

public class Example {
	public static void main(String[] args) {
		// 获取当前日期和时间
		LocalDateTime now = LocalDateTime.now();
		System.out.println("当前日期和时间: " + now);

		// 创建特定日期和时间
		LocalDateTime specificDateTime = LocalDateTime.of(2024, 1, 1, 11, 45, 14);
		System.out.println("特定日期和时间: " + specificDateTime);

		// 获取日期和时间的各个部分
		int year = now.getYear();
		int month = now.getMonthValue();
		int day = now.getDayOfMonth();
		int hour = now.getHour();
		int minute = now.getMinute();
		int second = now.getSecond();
		System.out.println("年份: " + year + ", 月份: " + month + ", 日期: " + day +
				", 小时: " + hour + ", 分钟: " + minute + ", 秒钟: " + second);

		// 增加天数
		LocalDateTime nextWeek = now.plusWeeks(1);
		System.out.println("一周后的日期和时间: " + nextWeek);

		// 减少小时
		LocalDateTime earlierTime = now.minusHours(2);
		System.out.println("两小时前的日期和时间: " + earlierTime);
	}
}

运行结果:

运行结果

5、ZonedDateTime

ZonedDateTime 表示具有时区的日期和时间。

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Example {
	public static void main(String[] args) {
		// 获取当前上海时区的日期和时间
		ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
		System.out.println("当前上海时区的日期和时间: " + now);

		// 创建特定上海时区的日期和时间
		ZonedDateTime specificZonedDateTime = ZonedDateTime.of(2024, 1, 1, 12, 0, 0, 0, ZoneId.of("Asia/Shanghai"));
		System.out.println("特定上海时区的日期和时间: " + specificZonedDateTime);

		// 获取时区信息
		ZoneId zoneId = now.getZone();
		System.out.println("当前时区: " + zoneId);

		// 增加天数
		ZonedDateTime nextWeek = now.plusDays(7);
		System.out.println("一周后的日期和时间: " + nextWeek);

		// 减少小时
		ZonedDateTime earlierTime = now.minusHours(5);
		System.out.println("五小时前的日期和时间: " + earlierTime);
	}
}

运行结果:

运行结果

6、Instant

Instant 表示时间戳(从1970年1月1日00:00:00 UTC 起的时间点)。

import java.time.Instant;

public class Example {
	public static void main(String[] args) {
		// 获取当前时间戳
		Instant now = Instant.now();
		System.out.println("当前时间戳: " + now);

		// 创建特定时间戳
		Instant specificInstant = Instant.parse("2024-01-01T00:00:00Z");
		System.out.println("特定时间戳: " + specificInstant);

		// 转换为毫秒
		long millis = now.toEpochMilli();
		System.out.println("自1970年1月1日以来的毫秒数: " + millis);

		// 增加秒数
		Instant later = now.plusSeconds(3600); // 增加1小时
		System.out.println("一小时后的时间戳: " + later);

		// 减少秒数
		Instant earlier = now.minusSeconds(3600); // 减少1小时
		System.out.println("一小时前的时间戳: " + earlier);
	}
}

运行结果:

运行结果

7、DateTimeFormater

上面我们提到了对于 Date 类的专用格式化类 SimpleDateFormatter

这里我们介绍了 LocalDateTime 类,实际上对于这个类,也有专用的格式化类,也就是 DateTimeFormatter

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Example {
	public static void main(String[] args) {
		// 创建 LocalDateTime 实例
		LocalDateTime now = LocalDateTime.now();

		// 定义格式化模式
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

		// 使用格式化器格式化 LocalDateTime
		String formattedDateTime = now.format(formatter);

		// 输出格式化后的日期时间
		System.out.println("当前日期时间: " + formattedDateTime);
	}
}

运行结果:

在这里插入图片描述

四、第三代日期类

1、简要介绍

Java 9 在 java.time 包中添加了一些新功能和改进,例如可用于更好地处理日期的 MonthDayYearMonthDuration 类。

  • MonthDay:表示没有年份的日期(只包含月份和日期),可用于处理周期性事件(如每年的节日)。
  • YearMonth:表示没有具体日期的年月组合。
  • Duration:表示两个时间点之间的时间量(以秒和纳秒为单位)。

2、MonthDay

MonthDay 表示没有年份的日期(只包含月份和日期),可用于处理周期性事件(如每年的节日)。

import java.time.MonthDay;

public class Example {
	public static void main(String[] args) {
		// 创建特定的MonthDay
		MonthDay monthDay = MonthDay.of(1, 1); // 1月1日
		System.out.println("特定的月份和日期: " + monthDay);

		// 获取月份和日期
		int month = monthDay.getMonthValue();
		int day = monthDay.getDayOfMonth();
		System.out.println("月份: " + month + ", 日期: " + day);

		// 检查某个日期是否与当前MonthDay相同
		MonthDay today = MonthDay.now();
		boolean isToday = today.equals(monthDay);
		System.out.println("今天是否是" + monthDay + ": " + isToday);

		// 增加月数
		MonthDay nextMonthDay = monthDay.withMonth((month % 12) + 1);
		System.out.println("下一个月份和日期: " + nextMonthDay);
	}
}

运行结果:

运行结果

3、YearMonth

YearMonth 表示没有具体日期的年月组合。

import java.time.YearMonth;

public class Example {
	public static void main(String[] args) {
		// 创建特定的YearMonth
		YearMonth yearMonth = YearMonth.of(2024, 1); // 2024年1月
		System.out.println("特定的年份和月份: " + yearMonth);

		// 获取年份和月份
		int year = yearMonth.getYear();
		int month = yearMonth.getMonthValue();
		System.out.println("年份: " + year + ", 月份: " + month);

		// 获取该月的天数
		int daysInMonth = yearMonth.lengthOfMonth();
		System.out.println("此月的天数: " + daysInMonth);

		// 增加月份
		YearMonth nextYearMonth = yearMonth.plusMonths(1);
		System.out.println("下一个年份和月份: " + nextYearMonth);

		// 减少年份
		YearMonth previousYearMonth = yearMonth.minusYears(1);
		System.out.println("去年同月: " + previousYearMonth);
	}
}

运行结果:

运行结果

4、Duration

Duration 表示两个时间点之间的时间量(以秒和纳秒为单位)。

import java.time.Duration;
import java.time.LocalTime;

public class Example {
	public static void main(String[] args) {
		// 创建两个时间点
		LocalTime start = LocalTime.of(10, 30);
		LocalTime end = LocalTime.of(12, 45);

		// 计算持续时间
		Duration duration = Duration.between(start, end);
		System.out.println("持续时间(小时:分钟:秒): " + duration.toHours() + ":" + duration.toMinutesPart() + ":" + duration.toSecondsPart());

		// 获取持续时间的总秒数
		long totalSeconds = duration.getSeconds();
		System.out.println("持续时间的总秒数: " + totalSeconds);

		// 增加持续时间
		Duration addedDuration = duration.plusHours(1).plusMinutes(30);
		System.out.println("增加1小时30分钟后的持续时间(小时:分钟:秒): " + addedDuration.toHours() + ":" + addedDuration.toMinutesPart() + ":" + addedDuration.toSecondsPart());

		// 减少持续时间
		Duration reducedDuration = duration.minusMinutes(15);
		System.out.println("减少15分钟后的持续时间(小时:分钟:秒): " + reducedDuration.toHours() + ":" + reducedDuration.toMinutesPart() + ":" + reducedDuration.toSecondsPart());
	}
}

运行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值