百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Java 8 新特性:Date-Time API

toyiye 2024-06-27 00:44 11 浏览 0 评论

Java 8 引入的 Date-Time API (java.time 包) 为日期和时间处理带来了显著的改进,解决了 java.util.Date 类的许多痛点:


  1. 非线程安全
  2. 时区处理麻烦
  3. 格式化和时间计算繁琐
  4. 设计有缺陷,Date 类同时包含日期和时间;还有一个 java.sql.Date,容易混淆。


本文将详细讲解 Java 8 新的 Date-Time API,并通过源码和示例代码对比 Java 8 之前的实现方式,深入剖析其设计的用意和目的。


java.time 主要类


java.util.Date 既包含日期又包含时间,而 java.time 将它们进行了分离:


  • LocalDateTime:日期和时间,格式为 yyyy-MM-ddTHH:mm:ss.SSS
  • LocalDate:仅日期,格式为 yyyy-MM-dd
  • LocalTime:仅时间,格式为 HH:mm:ss


格式化


Java 8 之前:


java


public void oldFormat(){
    Date now = new Date();
    //格式化 yyyy-MM-dd
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    String date  = sdf.format(now);
    System.out.println(String.format("date format : %s", date));

    //格式化 HH:mm:ss
    SimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");
    String time = sdft.format(now);
    System.out.println(String.format("time format : %s", time));

    //格式化 yyyy-MM-dd HH:mm:ss
    SimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String datetime = sdfdt.format(now);
    System.out.println(String.format("dateTime format : %s", datetime));
}



Java 8 之后:


java


public void newFormat(){
    //格式化 yyyy-MM-dd
    LocalDate date = LocalDate.now();
    System.out.println(String.format("date format : %s", date));

    //格式化 HH:mm:ss
    LocalTime time = LocalTime.now().withNano(0);
    System.out.println(String.format("time format : %s", time));

    //格式化 yyyy-MM-dd HH:mm:ss
    LocalDateTime dateTime = LocalDateTime.now();
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateTimeStr = dateTime.format(dateTimeFormatter);
    System.out.println(String.format("dateTime format : %s", dateTimeStr));
}



字符串转日期格式


Java 8 之前:


java


//已弃用
Date date = new Date("2021-01-26");
//替换为
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2021-01-26");



Java 8 之后:


java


LocalDate date = LocalDate.of(2021, 1, 26);
LocalDate.parse("2021-01-26");

LocalDateTime dateTime = LocalDateTime.of(2021, 1, 26, 12, 12, 22);
LocalDateTime.parse("2021-01-26T12:12:22");

LocalTime time = LocalTime.of(12, 12, 22);
LocalTime.parse("12:12:22");



Java 8 之前 的转换需要借助 SimpleDateFormat 类,而 Java 8 之后 只需要使用 LocalDate、LocalTime、LocalDateTime 的 of 或 parse 方法。


日期计算


以下以计算 一周后的日期 为例,其他单位(年、月、日、时等)类似。这些单位都在 java.time.temporal.ChronoUnit 枚举中定义。


Java 8 之前:


java


public void afterDay(){
    //一周后的日期
    SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
    Calendar ca = Calendar.getInstance();
    ca.add(Calendar.DATE, 7);
    Date d = ca.getTime();
    String after = formatDate.format(d);
    System.out.println("一周后日期:" + after);

    //算两个日期间隔多少天,计算间隔多少年,多少月方法类似
    String dates1 = "2021-12-23";
    String dates2 = "2021-02-26";
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    Date date1 = format.parse(dates1);
    Date date2 = format.parse(dates2);
    int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
    System.out.println(dates1 + "和" + dates2 + "相差" + day + "天");
}



Java 8 之后:


java


public void pushWeek(){
    //一周后的日期
    LocalDate localDate = LocalDate.now();
    //方法1
    LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);
    //方法2
    LocalDate after2 = localDate.plusWeeks(1);
    System.out.println("一周后日期:" + after);

    //算两个日期间隔多少天,计算间隔多少年,多少月
    LocalDate date1 = LocalDate.parse("2021-02-26");
    LocalDate date2 = LocalDate.parse("2021-12-23");
    Period period = Period.between(date1, date2);
    System.out.println("date1 到 date2 相隔:" + period.getYears() + "年" + period.getMonths() + "月" + period.getDays() + "天");

    //获取总天数
    long day = date2.toEpochDay() - date1.toEpochDay();
    System.out.println(date1 + "和" + date2 + "相差" + day + "天");
}



获取指定日期


获取特定一个日期,如本月最后一天或第一天。


Java 8 之前:


java


public void getDay() {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    //获取当前月第一天:
    Calendar c = Calendar.getInstance();
    c.set(Calendar.DAY_OF_MONTH, 1);
    String first = format.format(c.getTime());
    System.out.println("first day:" + first);

    //获取当前月最后一天
    Calendar ca = Calendar.getInstance();
    ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
    String last = format.format(ca.getTime());
    System.out.println("last day:" + last);

    //当年最后一天
    Calendar currCal = Calendar.getInstance();
    Calendar calendar = Calendar.getInstance();
    calendar.clear();
    calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
    calendar.roll(Calendar.DAY_OF_YEAR, -1);
    Date time = calendar.getTime();
    System.out.println("last day:" + format.format(time));
}



Java 8 之后:


java


public void getDayNew() {
    LocalDate today = LocalDate.now();
    //获取当前月第一天:
    LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
    //获取当前月最后一天:
    LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
    //获取下一天:
    LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
    //获取当年最后一天:
    LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear());
    //2021年最后一个周日
    LocalDate lastSundayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}



java.time.temporal.TemporalAdjusters 提供了很多便捷的方法来获取特定日期。


JDBC 和 Java 8


现在 JDBC 时间类型和 Java 8 时间类型的对应关系是:


  1. Date ---> LocalDate
  2. Time ---> LocalTime
  3. Timestamp ---> LocalDateTime


而之前统统对应 Date 类型。


时区


java.util.Date 对象实际上存储的是 1970 年 1 月 1 日 0 点(GMT)至 Date 对象所表示时刻所经过的毫秒数。因此,它记录的毫秒数与时区无关,但在使用上需要转换成当地时间,这就涉及到了时间的国际化。java.util.Date 本身并不支持国际化,需要借助 TimeZone。


java


//北京时间
Date date = new Date();
SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//北京时区
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date));

//东京时区
SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));
System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date));

//直接打印会自动转成当前时区时间
System.out.println(date);



在新特性中引入了 java.time.ZonedDateTime 来表示带时区的时间。它可以看成是 LocalDateTime + ZoneId。


java


//当前时区时间
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println("当前时区时间: " + zonedDateTime);

//东京时间
ZoneId zoneId = ZoneId.of(ZoneId.SHORT_IDS.get("JST"));
ZonedDateTime tokyoTime = zonedDateTime.withZoneSameInstant(zoneId);
System.out.println("东京时间: " + tokyoTime);

// ZonedDateTime 转 LocalDateTime
LocalDateTime localDateTime = tokyoTime.toLocalDateTime();
System.out.println("东京时间转当地时间: " + localDateTime);

//LocalDateTime 转 ZonedDateTime
ZonedDateTime localZoned = localDateTime.atZone(ZoneId.systemDefault());
System.out.println("本地时区时间: " + localZoned);



java.time 包与 Joda-Time 的对比


Java 8 引入的 java.time 包是对日期和时间处理的一次重大改进,它借鉴了许多 Joda-Time 的设计理念,并在此基础上进行了优化。那么,java.time 包与 Joda-Time 相比有哪些优势和劣势呢?


1. 设计理念和 API 风格


Joda-Time


  • 设计理念:Joda-Time 旨在提供一个更直观和更强大的日期时间处理库,弥补 java.util.Date 和 java.util.Calendar 的不足。
  • API 风格:Joda-Time 的 API 风格非常直观,类名和方法名都非常清晰易懂。例如,DateTime 类表示日期和时间,LocalDate 类表示仅日期。


Java 8 java.time


  • 设计理念:java.time 包是基于 JSR 310 的规范实现,吸收了 Joda-Time 的优点,并在此基础上进行了优化和改进。
  • API 风格:java.time 包的 API 风格与 Joda-Time 类似,但在命名和结构上更加规范。例如,LocalDateTime 表示日期和时间,LocalDate 表示仅日期,LocalTime 表示仅时间。


2. 集成和兼容性


Joda-Time


  • 集成:Joda-Time 是一个独立的第三方库,需要手动添加依赖。
  • 兼容性:Joda-Time 与 Java SE 8 之前的版本兼容,适用于所有版本的 Java。


Java 8 java.time


  • 集成:java.time 包是 Java SE 8 的一部分,无需额外添加依赖。
  • 兼容性:java.time 包仅适用于 Java SE 8 及以上版本,对于 Java 8 之前的版本,需要额外的兼容性库(如 ThreeTen-Backport)。


3. 性能和线程安全


Joda-Time


  • 性能:Joda-Time 的性能相对较好,但在某些操作上可能不如 java.time 包高效。
  • 线程安全:Joda-Time 的大多数类是不可变的,因此是线程安全的。


Java 8 java.time


  • 性能:java.time 包在设计时考虑了性能优化,尤其是在日期计算和格式化等高频操作上性能更优。
  • 线程安全:java.time 包中的所有类都是不可变的,因此也是线程安全的。


4. 功能和扩展性


Joda-Time


  • 功能:Joda-Time 提供了丰富的功能,支持各种日期时间操作、格式化、解析、时区转换等。
  • 扩展性:Joda-Time 提供了一些扩展功能,例如自定义时间单位和字段。


Java 8 java.time


  • 功能:java.time 包提供了与 Joda-Time 类似的功能,并在某些方面进行了增强。例如,提供了更丰富的日期调整器(TemporalAdjuster)和更强大的时间量(Duration 和 Period)。
  • 扩展性:java.time 包也提供了良好的扩展性,允许用户自定义时间单位和字段。


示例对比


Joda-Time 示例


java


import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

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

        // 格式化
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDate = now.toString(formatter);
        System.out.println("格式化后的时间: " + formattedDate);

        // 解析
        DateTime parsedDate = DateTime.parse("2021-01-26 12:12:22", formatter);
        System.out.println("解析后的时间: " + parsedDate);

        // 日期计算
        DateTime oneWeekLater = now.plusWeeks(1);
        System.out.println("一周后的时间: " + oneWeekLater);
    }
}



Java 8 java.time 示例


java


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

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

        // 格式化
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDate = now.format(formatter);
        System.out.println("格式化后的时间: " + formattedDate);

        // 解析
        LocalDateTime parsedDate = LocalDateTime.parse("2021-01-26 12:12:22", formatter);
        System.out.println("解析后的时间: " + parsedDate);

        // 日期计算
        LocalDateTime oneWeekLater = now.plusWeeks(1);
        System.out.println("一周后的时间: " + oneWeekLater);
    }
}



总结


优势


  1. 集成:java.time 包是 Java 8 的一部分,无需额外依赖,集成更方便。
  2. 性能:java.time 包在性能上进行了优化,尤其是在高频日期时间操作上。
  3. 线程安全:java.time 包中的所有类都是不可变的,因此线程安全。
  4. 标准化:java.time 包是基于 JSR 310 的规范实现,更加标准化。


劣势


  1. 兼容性:java.time 包仅适用于 Java SE 8 及以上版本,对于 Java 8 之前的版本需要额外的兼容性库。
  2. 学习成本:对于熟悉 Joda-Time 的开发者来说,迁移到 java.time 包可能需要一定的学习成本。


使用 java.time 包中的类处理时间间隔和持续时间


在 Java 8 的 java.time 包中,处理时间间隔和持续时间有两个主要的类:Duration 和 Period。Duration 用于表示基于时间的间隔(以秒和纳秒为单位),而 Period 用于表示基于日期的间隔(以年、月、日为单位)。


1. Duration 类


Duration 类用于表示两个时间点之间的时间间隔,精确到秒和纳秒。它常用于计算精确的时间差,如秒、分钟、小时等。


示例代码


import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class DurationExample {
    public static void main(String[] args) {
        // 当前时间
        LocalDateTime startTime = LocalDateTime.now();
        System.out.println("开始时间: " + startTime);

        // 模拟一个耗时操作
        try {
            Thread.sleep(3000); // 休眠3秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 结束时间
        LocalDateTime endTime = LocalDateTime.now();
        System.out.println("结束时间: " + endTime);

        // 计算时间间隔
        Duration duration = Duration.between(startTime, endTime);
        System.out.println("时间间隔: " + duration.getSeconds() + " 秒 " + duration.getNano() + " 纳秒");

        // 其他常用方法
        System.out.println("时间间隔(分钟): " + duration.toMinutes());
        System.out.println("时间间隔(毫秒): " + duration.toMillis());

        // 使用ChronoUnit计算时间间隔
        long secondsBetween = ChronoUnit.SECONDS.between(startTime, endTime);
        System.out.println("时间间隔(ChronoUnit): " + secondsBetween + " 秒");
    }
}



2. Period 类


Period 类用于表示两个日期之间的时间间隔,精确到年、月、日。它常用于计算日期间的差异,如天数、月数、年数等。


示例代码


java


import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;

public class PeriodExample {
    public static void main(String[] args) {
        // 当前日期
        LocalDate startDate = LocalDate.now();
        System.out.println("开始日期: " + startDate);

        // 目标日期
        LocalDate endDate = startDate.plusYears(1).plusMonths(2).plusDays(3);
        System.out.println("结束日期: " + endDate);

        // 计算日期间隔
        Period period = Period.between(startDate, endDate);
        System.out.println("日期间隔: " + period.getYears() + " 年 " + period.getMonths() + " 月 " + period.getDays() + " 天");

        // 其他常用方法
        System.out.println("总月数: " + period.toTotalMonths());

        // 使用ChronoUnit计算日期间隔
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        System.out.println("日期间隔(ChronoUnit): " + daysBetween + " 天");
    }
}



选择 Duration 和 Period 的适用场景


选择 Duration 的场景


  • 需要精确到秒和纳秒的时间计算。
  • 计时操作,如测量代码执行时间、任务的持续时间等。
  • 时区无关的时间计算,如两个时间点之间的间隔。


选择 Period 的场景


  • 需要基于年、月、日的日期计算。
  • 计算两个日期之间的年、月、日差异。
  • 日历相关操作,如计算某个日期之后的某年某月某日。


比较两个日期之间的差异


示例代码


java


import java.time.LocalDate;
import java.time.Period;

public class PeriodDifferenceExample {
    public static void main(String[] args) {
        // 两个日期
        LocalDate startDate = LocalDate.of(2020, 1, 1);
        LocalDate endDate = LocalDate.of(2021, 6, 15);

        // 计算日期间隔
        Period period = Period.between(startDate, endDate);
        System.out.println("日期间隔: " + period.getYears() + " 年 " + period.getMonths() + " 月 " + period.getDays() + " 天");
    }
}



使用 Duration 进行时区无关的时间计算


示例代码


java


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

public class ZonedDateTimeExample {
    public static void main(String[] args) {
        // 纽约时间
        ZonedDateTime startDateTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        System.out.println("纽约开始时间: " + startDateTime);

        // 东京时间
        ZonedDateTime endDateTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        System.out.println("东京结束时间: " + endDateTime);

        // 计算时间间隔
        Duration duration = Duration.between(startDateTime, endDateTime);
        System.out.println("时间间隔: " + duration.toHours() + " 小时");
    }
}



使用 ChronoUnit 枚举


ChronoUnit 枚举提供了一系列用于时间单位的常量,支持基于时间和日期的计算。


示例代码


java


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

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

        // 计算一周后的时间
        LocalDateTime oneWeekLater = now.plus(1, ChronoUnit.WEEKS);
        System.out.println("一周后的时间: " + oneWeekLater);

        // 计算一年前的日期
        LocalDate oneYearAgo = LocalDate.now().minus(1, ChronoUnit.YEARS);
        System.out.println("一年前的日期: " + oneYearAgo);

        // 计算两个时间点之间的小时数
        long hoursBetween = ChronoUnit.HOURS.between(now, oneWeekLater);
        System.out.println("时间间隔(小时): " + hoursBetween + " 小时");
    }
}



总结


使用 Java 8 java.time 包中的 Duration 和 Period 类可以方便地处理时间间隔和持续时间。Duration 用于表示基于时间的间隔,如秒、分钟、小时等;而 Period 用于表示基于日期的间隔,如年、月、日等。此外,ChronoUnit 枚举提供了一系列用于时间单位的常量,支持基于时间和日期的计算。

?

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码