日期时间类

  • 一、JDK8之前日期时间
  • 二、JDK8中日期时间

一、JDK8之前日期时间

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_sql


1. 获取时间:System.currentTimeMillis()

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_sql_02


关于计算时间的标准可参考https://baijiahao.baidu.com/s?id=1732139602203523267&wfr=spider&for=pc我国处于东八区,与中时区时差为8小时,也就是UTC+8。

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_03

2. 获取日期:java.util.Date

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_java_04

// java.util.Date
// 1.无参构造  获取本地当前时间戳 以特定格式表示
Date date1 = new Date();
System.out.println(date1);// Fri Mar 24 14:07:18 CST 2023
//        System.out.println(date1.toString());
long time = date1.getTime();  // 获取当前日期时间对应的时间戳,单位ms
System.out.println(time);  // 1679638038632
// 2.有参构造
Date date2=new Date(time);  // 将输入的表示时间戳的time转换为特定格式输出
System.out.println(date2);// Fri Mar 24 14:07:18 CST 2023
System.out.println(date2.getTime());  // 1679638038632

2.1. 获取日期:java.sql.Date

  • 继承于java.util.Date,专门用于表示数据库语言SQL中的日期类型
  • 仅有有参构造,输入为表示时间戳(单位ms)的long型整数,构造以特定格式表示时间的Date对象;

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_05

// java.sql.Date
java.sql.Date date = new java.sql.Date(1679638038632L);
System.out.println(date);  // 2023-03-24
System.out.println(date.toString());  // 2023-03-24
System.out.println(date.getTime());  // 1679638038632

2.2.两种日期类的转换:

// java.sql.Date->java.util.Date  子类到父类,直接赋值即可
 // java.util.Date-> java.sql.Date 父类转子类
 // 情况1,最初实际声明的还是子类对象,直接强制转换即可
//        Date date=new java.sql.Date(1679638038632L);
//        java.sql.Date date1=(java.sql.Date)date;
//        System.out.println(date);  // 2023-03-24
//        System.out.println(date1);  // 2023-03-24
 // 情况2,最初实际声明的是父类对象,无法直接强制转换
 // 可先通过Date对象的getTime()方法获取时间戳,然后实例化java.sql.Date即可
 Date date=new Date(1679638038632L);
 java.sql.Date date1 = new java.sql.Date(date.getTime());
 System.out.println(date);  // Fri Mar 24 14:07:18 CST 2023
 System.out.println(date1);  // 2023-03-24

3. 获取格式化日期:java.text.SimpleDateFormat

继承自java.text.DateFormat,可对日期类Date对象进行指定形式的格式化,或者对满足指定格式的字符串解析为Date对象

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_System_06

  • 使用无参构造new SimpleDateFormat()进行实例化后,则在对Date对象进行格式化或对字符串进行解析时,会使用默认的格式;
  • 如果想指定日期时间的格式,需要通过使用有参构造new SimpleDateFormat(String pattern)中的参数pattern进行指定,关于pattern的指定可参考官方文档,其中使用的字符含义如下:
@Test
    public void formatDemo() throws Exception{
        // 测试java.text.SimpleDateFormat
        SimpleDateFormat format = new SimpleDateFormat("yyyy+MM+dd - hh:mm:ss");
        Date date = new Date();
        System.out.println(date);  // Fri Mar 24 21:44:41 CST 2023
        // 格式化操作
        String formattedDate = format.format(date);  // 2023+03+24 - 09:44:41
        System.out.println(formattedDate);

        // 解析操作
        String dateStr="2023+03+24 - 09:44:41";
        Date parsedDate = format.parse(dateStr);
        System.out.println(parsedDate);
    }

3.1 相关练习
练习1:将表示时间的字符串Str转换为java.sql.Date对象

  • 1.java.sql.Date只可通过有参构造实例化;
  • 2.字符串可通过java.text.SimpleDateFormat的parse方法解析为java.util.Date对象;
  • 3.java.util.Date可转换为java.sql.Date对象;

练习2:“三天打渔两日晒网”,从1990-01-01为基准,随机指定一个日期某年某月某日,问这一天是在打渔还是晒网?

  • 1.“三天打渔两日晒网”流程以5天为一个完整周期,其中距离基准为0,1,2天的时间为打渔,距离为3,4的为晒网,比如1990-01-02距离基准1990-01-01为1天,则这天在打渔;
  • 2.思路:确定指定日期距离基准日期的天数,然后对周期5进行取余,其中距离基准为0,1,2天的时间为打渔,距离为3,4的为晒网;计算天数的方法有两种:1)计算指定日期的时间戳与基准时间戳的差值,该差值表示二者之间距离的毫秒数,将其转化为天数即可;2)直接对二者之间的天数进行计数,其中涉及闰年判断,整年计数、整月计数等,可借助java.util.Calendar日历类实现;
package com.northsmile.dateandtime;

import lombok.SneakyThrows;
import org.junit.Test;

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

/**
 * Author:NorthSmile
 * Date:2023/3/25 8:40
 * JDK8之前日期时间类例题
 */
public class Example {
//    **练习1:将表示时间的字符串Str转换为java.sql.Date对象**
//
//            - 1.java.sql.Date只可通过有参构造实例化;
//            -  2.字符串可通过java.text.SimpleFormat的parse方法解析为java.util.Date对象;
//            -  3.java.util.Date可转换为java.sql.Date对象;
    @SneakyThrows
    @Test
    public void strToSqlDate(){
        String dateStr="2020-09-08 12:02:03";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // str->java.util.Date
        Date date = dateFormat.parse(dateStr);
        System.out.println(date);
        // java.util.Date->java.sql.Date
        java.sql.Date resDate = new java.sql.Date(date.getTime());
        System.out.println(resDate);
    }

//    **练习2:“三天打渔两日晒网”,从1990-01-01为基准,随机指定一个日期某年某月某日,问这一天是在打渔还是晒网?**
//
//            - 1.“三天打渔两日晒网”流程以5天为一个完整周期,其中距离基准为0,1,2天的时间为打渔,距离为3,4的为晒网,比如1990-01-02距离基准1990-01-01为1天,则这天在打渔;
//            - 2.思路:确定指定日期距离基准日期的天数,然后对周期5进行取余,其中距离基准为0,1,2天的时间为打渔,距离为3,4的为晒网;计算天数的方法有两种:1)计算指定日期的时间戳与基准时间戳的差值,该差值表示二者之间距离的毫秒数,将其转化为天数即可;
//            2)直接对二者之间的天数进行计数,其中涉及闰年判断,整年计数、整月计数等,可借助java.util.Calendar日历类实现;
    @SneakyThrows
    public static void dateDiff(String curDate){
        System.out.println(curDate);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String base="1990-01-01";
        // 方法一:使用时间戳
//        long baseTime=dateFormat.parse(base).getTime();
//        // 解析字符串
//        long curTime = dateFormat.parse(curDate).getTime();
//        long days = (curTime - baseTime) / (1000 * 60 * 60*24);  // 计算时差,并转换为天数

        // 方法二:将时间差分为三部分,1)基准年总天数-基准日期距离年初的天数;2)中间的完整年份;3)当前日期距离年初的天数;
        // 借助Calendar日历类实现
        Calendar calendar = Calendar.getInstance();
        // 1)基准年总天数-基准日期距离年初的天数;
        calendar.setTime(dateFormat.parse(base));
        int baseYear = calendar.get(Calendar.YEAR);
        int days=365-calendar.get(Calendar.DAY_OF_YEAR);
        days+=(isLeapYear(baseYear)?1:0);

        calendar.setTime(dateFormat.parse(curDate));
        int curYear = calendar.get(Calendar.YEAR);  // 当前年
        // 2)中间的完整年份;
        days+=((curYear-1-baseYear)*365);
        for (int year=baseYear+1;year<curYear;year++){
            if (isLeapYear(year)){
                days++;
            }
        }
        // 3)当前日期距离年初的天数;
        days+=(calendar.get(Calendar.DAY_OF_YEAR));
        System.out.println(days);
        long sign=days%5;
        if (sign<3){
            System.out.println(curDate+"在打渔");
        }else{
            System.out.println(curDate+"在晒网");
        }

    }

    // 判断是否为闰年
    private static boolean isLeapYear(int year) {
        if (year%400==0||(year%4==0&&year%100!=0)){
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请按照yyyy-mm-dd格式输入需查询的日期:");
        while (scanner.hasNext()){
            String curDate = scanner.nextLine();
            dateDiff(curDate);
            System.out.println("请按照yyyy-mm-dd格式输入需查询的日期:");
        }
    }
}

4. 日历类:java.util.Calendar

  • 该类为抽象类,无法直接进行实例化,其实例化方式有两种:1)使用子类构造器GregorianCalendar;2).调用静态方法getInstance()即可;
  • 默认表示系统当前日历时间,可对该时间进行修改设置;
  • Calendar的属性有两个需要注意:DAY_OF_WEEK_IN_MONTH和WEEK_OF_MONTH,他们都表示当前月第几周,区别在于:
    WEEK_OF_MONTH参考标准为日历时间,当天在公历中当月属于第几周就是多少,以周日为起点,周六表示一周结束;DAY_OF_WEEK_IN_MONTH参考标准为当月总天数,以当前月第一天为第一周的第一天,如此计算;比如2023.3.26,对于WEEK_OF_MONTH来说属于第5周(3.1-3.4属于第一周,5号是新的一周开始),而DAY_OF_WEEK_IN_MONTH为第4周(3*7+5=26);

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_07

public static void main(String[] args) {
        // 实例化方式:
        // 1.使用子类构造器
//        Calendar calendar=new GregorianCalendar();
        // 2.调用静态方法getInstance()
        Calendar ca = Calendar.getInstance();
//        System.out.println(calendar);

        // 1)获取日期相关属性值
        // 年月日
//        System.out.println(ca.get(Calendar.YEAR));
//        System.out.println(ca.get(Calendar.MONTH)+1);  // 1-12月使用0-11表示
//        System.out.println(ca.get(Calendar.DATE));

//        System.out.println(ca.get(Calendar.DAY_OF_YEAR));  // 该年第几天
//        System.out.println(ca.get(Calendar.DAY_OF_MONTH));  // 该月第几天
//        System.out.println(ca.get(Calendar.DAY_OF_WEEK));  // 该周第几天 周日-周六使用1-7表示
//        ca.add(Calendar.DATE,-24);
//        System.out.println(ca.get(Calendar.DATE));
//        System.out.println(ca.get(Calendar.DAY_OF_WEEK));  // 该周第几天 周日-周六使用1-7表示
//        System.out.println(ca.get(Calendar.DAY_OF_WEEK_IN_MONTH));  // 视当月第一天为周日,表示当前月当天属于第几周,以当前月天数进行计算
//        System.out.println(ca.get(Calendar.WEEK_OF_MONTH));  //当月第几周 以周日为一周的开始
//        System.out.println(ca.get(Calendar.WEEK_OF_YEAR));  // 当年第几周


        // 时分秒
//        System.out.println(ca.get(Calendar.HOUR_OF_DAY));  // 一天的第几个小时
//        System.out.println(ca.get(Calendar.HOUR));
//        System.out.println(ca.get(Calendar.MINUTE));
//        System.out.println(ca.get(Calendar.SECOND));
        // 2)设置日期相关属性值
        ca.set(Calendar.DATE,1);
        System.out.println(ca.get(Calendar.DATE));
        // 3)修改日期相关属性值
        ca.add(Calendar.DATE,-1);
        System.out.println(ca.get(Calendar.DATE));
        System.out.println(ca.get(Calendar.MONTH));

        // java.util.Date与java.util.Calendar互相转换
        // java.util.Date->java.util.Calendar
//        Date base=new Date();
//        System.out.println(base);
//        ca.setTime(base;
//        // java.util.Calendar-->java.util.Date
//        Date time = ca.getTime();
//        System.out.println(time);

    }

二、JDK8中日期时间

JDK8之前的日期时间类存在一些问题,新的API可解决这些问题:

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_sql_08


Joda-Time是一个第三方库,可解决之前日期时间类的问题,JDK8时借鉴Joda-Time实现了新的API。在使用JDK8以前API时,可添加Joda-Time对应jar包使用其提供的良好性能的日期时间API。

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_java_09

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_10


java.time.LocalDate/java.time.LocalDateTime/java.time.LocalTime:

这一系列类可近似为java.util.Calendar类处理:

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_11

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_sql_12


瞬时:java.time.Instant

该类可近似为java.util.Date类处理:

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_sql_13


java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_java_14


日期时间格式化:java.time.format.DateTimeFormatter:

类似于java.text.SimpleDateFormat处理:

格式化方式有以下三种,常用方式为自定义格式化。

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_System_15

package com.northsmile.dateandtime;

import org.junit.Test;

import javax.print.attribute.standard.DateTimeAtCompleted;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
import java.util.Date;

/**
 * @author NorthSmile
 * @version 1.0
 * @date 2023/3/26&15:46
 * LocalDate/LocalDateTime/LocalTime/Instant/DateTimeFormatter测试
 */
public class LocalAndInstantDemo {
    @Test
    public void localDemo(){
        // 获取实例:本地日期、时间(默认格式显示)
//        LocalDate localDate = LocalDate.now();
//        System.out.println(localDate);
//        LocalTime localTime = LocalTime.now();
//        System.out.println(localTime);
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);
        // 指定日期时间创建对应实例
//        LocalDateTime localDateTime2 = LocalDateTime.of(2023, 3, 27, 13, 45, 56);
//        System.out.println(localDateTime2);
        // 获取指定时区日期时间
        LocalDateTime dateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        LocalDateTime dateTime1 = LocalDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.println(dateTime);
        System.out.println(dateTime1);

        // 获取localDateTime的属性信息
        // 年月
//        System.out.println(localDateTime.getYear());
//        System.out.println(localDateTime.getMonth()+":"+localDateTime.getMonthValue());
//
//        System.out.println(localDateTime.getDayOfYear());   // 当年第多少天
//        System.out.println(localDateTime.getDayOfMonth());  // 当月第多少天
//
//        System.out.println(localDateTime.getDayOfWeek());  // 星期几
//
//        // 时分秒
//        System.out.println(localDateTime.getHour());
//        System.out.println(localDateTime.getMinute());
//        System.out.println(localDateTime.getSecond());

        // 设置localDateTime的属性信息
//        LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(4); // 创建新的对象,原对象内容不变
//        System.out.println(localDateTime);
//        System.out.println(localDateTime1);

        // 修改localDateTime的属性信息
//        LocalDateTime localDateTime1 = localDateTime.plusYears(1);
//        System.out.println(localDateTime1);
//        LocalDateTime localDateTime2 = localDateTime.minusYears(1);
//        System.out.println(localDateTime2);
    }

    @Test
    public void instantDemo(){
        // 获取默认UTC时区日期时间:为国内时间减去8小时对应时间
        Instant now = Instant.now();
        System.out.println(now);
        // 根据时差偏移创建OffsetDateTime对象
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);
        // 获取时间戳
        System.out.println(now.toEpochMilli());
        //  根据指定时间戳实例化对虾干
        Instant now1 = Instant.ofEpochMilli(now.toEpochMilli());
        System.out.println(now1);
    }

    @Test
    public void formatDemo(){
        // 实例化格式化对象
        // 方式一:
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ISO_TIME;
//        System.out.println(dateTimeFormatter2);
        System.out.println(dateTimeFormatter2.format(LocalTime.now()));
//        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
//        System.out.println(dateTimeFormatter1);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd & HH:mm:ss");
//        System.out.println(dateTimeFormatter);
        // 格式化操作
        String str = dateTimeFormatter.format(LocalDateTime.now());
        System.out.println(str);
        // 解析操作
        TemporalAccessor date = dateTimeFormatter.parse(str);
        System.out.println(date);

    }
}

其他日期时间API:

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_16


JDK8前后日期时间API之间的转换:

java 可以知晓哪些时区开启了夏令时和冬令时吗 java的时间_数据库_17