java日期的简单梳理

一、JDK8之前的API:

  1. System类的currentTimeMillis()

    获取当前时间对应的毫秒数,long类型,时间戳
    当前时间与1970年1月1日0时0分0秒之间的毫秒数
    常用来计算时间差

  2. 两个Date类
    |–java.util.Date

    两个构造器的使
    两个方法的使用:①toString() ② long getTime()
    |----java.sql.Date: 对应着数据库中的date类型

Date date1 = new Date(); //创建一个基于当前系统时间的Date的实例
System.out.println(date1.toString());//Mon Dec 05 11:56:26 CST 2022

long milliTimes = date1.getTime();
System.out.println("对应的毫秒数为:" + milliTimes); //1670212256045

Date date2 = new Date(1370202256045L); //创建一个基于指定时间戳的Date的实例
System.out.println(date2.toString());
  1. SimpleDateFormat类
    SimpleDateFormat类:用于日期时间的格式化和解析

    格式化:日期—>字符串
    解析:字符串 —> 日期

    SimpleDateFormat sdf = new SimpleDateFormat();
     //格式化:日期--->字符串
     Date date1 = new Date();
     String strDate = sdf.format(date1);
     System.out.println(strDate);//22-12-5 下午2:21
    
     //解析:字符串 ---> 日期
     Date date2 = sdf.parse("22-12-5 下午3:21");
     System.out.println(date2);
    
     SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
     sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     //格式化:日期--->字符串
     Date date1 = new Date();
     String strDate = sdf.format(date1);
     System.out.println(strDate);//2022-12-05 14:27:19
    
     //解析:字符串 ---> 日期
     Date date2 = sdf.parse("2022-12-05 14:27:19");
     System.out.println(date2);
    
     //解析失败。因为参数的字符串不满足SimpleDateFormat可以识别的格式。
     //        Date date3 = sdf.parse("22-12-5 下午2:21");
     //        System.out.println(date2);
    
  2. Calendar类(日历类):抽象类
    Calendar:日历类
    ① 实例化 由于Calendar是一个抽象类,所以我们需要创建其子类的实例。这里我们通过Calendar的静态方法
    getInstance()即可获取

    ②常用方法:get(int field) / set(int field,xx) / add(int field,xx) / getTime() / setTime()

    calendar面临的问题是:

    • 可变性:像日期和时间这样的类应该是不可变的。

    • 偏移性:Date中的年份是从1900开始的,而月份都从0开始。

    • 格式化:格式化只对Date有用,Calendar则不行。

    • 此外,它们也不是线程安全的;不能处理闰秒等。

      闰秒,是指为保持协调世界时接近于世界时时刻,由国际计量局统一规定在年底或年中(也可能在季末)对协调世界时增加或减少1秒的调整。由于地球自转的不均匀性和长期变慢性(主要由潮汐摩擦引起的),会使世界时(民用时)和原子时之间相差超过到±0.9秒时,就把协调世界时向前拨1秒(负闰秒,最后一分钟为59秒)或向后拨1秒(正闰秒,最后一分钟为61秒); 闰秒一般加在公历年末或公历六月末。

      目前,全球已经进行了27次闰秒,均为正闰秒。

    总结:对日期和时间的操作一直是Java程序员最痛苦的地方之一

 Calendar calendar = Calendar.getInstance();

 //        System.out.println(calendar.getClass());

 //测试方法
 //get(int field)
 System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
 System.out.println(calendar.get(Calendar.DAY_OF_YEAR));

 //set(int field,xx)
 calendar.set(Calendar.DAY_OF_MONTH,23);
 System.out.println(calendar.get(Calendar.DAY_OF_MONTH));

 //add(int field,xx)
 calendar.add(Calendar.DAY_OF_MONTH,3);
 calendar.add(Calendar.DAY_OF_MONTH,-5);
 System.out.println(calendar.get(Calendar.DAY_OF_MONTH));

 //getTime():Calender --> Date
 Date date = calendar.getTime();
 System.out.println(date);

 //setTime():使用指定Date重置Calendar
 Date date1 = new Date();
 calendar.setTime(date1);
 System.out.println(calendar.get(Calendar.DAY_OF_MONTH));

如何将一个java.util.Date的实例转换为java.sql.Date的实例
拓展:
将控制台获取的年月日(比如:2022-12-13)的字符串数据,保存在数据库中。
(简化为得到java.sql.Date的对象,此对象对应的时间为2022-12-13)。

/*
    * 练习:
    如何将一个java.util.Date的实例转换为java.sql.Date的实例
    * */
    @Test
    public void test1(){
        Date date1 = new Date();
        //错误的:
//        java.sql.Date date2 = (java.sql.Date) date1;
//        System.out.println(date2);

        //正确的:
        java.sql.Date date2 = new java.sql.Date(date1.getTime());
        System.out.println(date2);
    }

    /*
    * 拓展:
        将控制台获取的年月日(比如:2022-12-13)的字符串数据,保存在数据库中。
        (简化为得到java.sql.Date的对象,此对象对应的时间为2022-12-13)。
        *
        * 字符串 ---> java.util.Date ---> java.sql.Date
    * */
    @Test
    public void test2() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String pattern = "2022-12-13";
        //得到java.util.Date
        Date date1 = sdf.parse(pattern);
        //转换为java.sql.Date
        java.sql.Date date2 = new java.sql.Date(date1.getTime());
        System.out.println(date2);
    }

二、JDK8中的API:

  1. LocalDate,LocalTime,LocalDateTime —>类似于Calendar

实例化:now() / of(xxx,xx,xx)
方法:get() / withXxx() / plusXxx() / minusXxx()

//now():获取当前日期和时间对应的实例
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);//2022-12-05
System.out.println(localTime);//15:43:51.474
System.out.println(localDateTime); //2022-12-05T15:43:51.475

//of():获取指定的日期、时间对应的实例
LocalDate localDate1 = LocalDate.of(2021, 5, 23);
LocalDateTime localDateTime1 = LocalDateTime.of(2022, 12, 5, 11, 23, 45);
System.out.println(localDate1);
System.out.println(localDateTime1);

//getXXX()
LocalDateTime localDateTime2 = LocalDateTime.now();
System.out.println(localDateTime2.getDayOfMonth());
//体现不可变性
//withXxx()
LocalDateTime localDateTime3 = localDateTime2.withDayOfMonth(15);
System.out.println(localDateTime2);//2022-12-05T15:48:48.399
System.out.println(localDateTime3);//2022-12-15T15:48:48.399
//plusXxx()
LocalDateTime localDateTime4 = localDateTime2.plusDays(5);
System.out.println(localDateTime2);//2022-12-05T15:50:21.864
System.out.println(localDateTime4);//2022-12-10T15:50:21.864
  1. Instant:瞬时 —>类似于Date

    Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。

    • 时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

    java.time.Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。

    方法描述
    now()静态方法,返回默认UTC时区的Instant类的对象
    ofEpochMilli(long epochMilli)静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象
    atOffset(ZoneOffset offset)结合即时的偏移来创建一个 OffsetDateTime
    toEpochMilli()返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳

    中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。

    instant.atOffset(ZoneOffset.ofHours(8));

实例化:now() / ofEpochMilli()
方法:toEpochMilli()


DateTimeFormatter该类提供了三种格式化方法:

  • (了解)预定义的标准格式。如:ISO_LOCAL_DATE_TIME、ISO_LOCAL_DATE、ISO_LOCAL_TIME

  • (了解)本地化相关的格式。如:ofLocalizedDate(FormatStyle.LONG)

    // 本地化相关的格式。如:ofLocalizedDateTime()
    // FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
    				
    // 本地化相关的格式。如:ofLocalizedDate()
    // FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
    
  • 自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)

ofPattern(String pattern)静态方法,返回一个指定字符串格式的DateTimeFormatter
format(TemporalAccessor t)格式化一个日期、时间,返回字符串
parse(CharSequence text)将指定格式的字符序列解析为一个日期、时间
    //now():
    Instant instant = Instant.now();
    System.out.println(instant);//2022-12-05T07:56:27.327Z
    //了解:
    OffsetDateTime instant1 = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(instant1);//2022-12-05T15:56:27.327+08:00

    Instant instant2 = Instant.ofEpochMilli(24123123312L);
    System.out.println(instant2); //1970-10-07T04:52:03.312Z
    
    long milliTime = instant.toEpochMilli();
    System.out.println(milliTime);
    
    System.out.println(new Date().getTime());

   DateTimeFormatter ---> 类似于SimpleDateFormat
   用于格式化和解析LocalDate,LocalTime,LocalDateTime

    //自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

    //格式化:日期、时间-->字符串
    LocalDateTime localDateTime = LocalDateTime.now();
    String strDateTime = dateTimeFormatter.format(localDateTime);
    System.out.println(strDateTime);//2022/12/05 16:04:44

    //解析:字符串 ---> 日期、时间
    TemporalAccessor temporalAccessor = dateTimeFormatter.parse("2022/12/05 15:04:44");
    LocalDateTime localDateTime1 = LocalDateTime.from(temporalAccessor);
    System.out.println(localDateTime1);//2022-12-05T15:04:44


    //ctrl + alt 显示类的关系图

指定时区日期时间:ZondId和ZonedDateTime

  • ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris

  • ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。

    • 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等
  • 常见时区ID:

Asia/Shanghai
UTC
America/New_York
  • 可以通过ZondId获取所有可用的时区ID:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;

public class TestZone {
    @Test
    public void test01() {
        //需要知道一些时区的id
        //Set<String>是一个集合,容器
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        //快捷模板iter
        for (String availableZoneId : availableZoneIds) {
            System.out.println(availableZoneId);
        }
    }

    @Test
    public void test02(){
        ZonedDateTime t1 = ZonedDateTime.now();
        System.out.println(t1);

        ZonedDateTime t2 = ZonedDateTime.now(ZoneId.of("America/New_York"));
        System.out.println(t2);
    }
}

持续日期/时间:Period和Duration

  • 持续时间:Duration,用于计算两个“时间”间隔
  • 日期间隔:Period,用于计算两个“日期”间隔
import org.junit.Test;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;

public class TestPeriodDuration {
    @Test
    public void test01(){
        LocalDate t1 = LocalDate.now();
        LocalDate t2 = LocalDate.of(2018, 12, 31);
        Period between = Period.between(t1, t2);
        System.out.println(between);

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

    @Test
    public void test02(){
        LocalDateTime t1 = LocalDateTime.now();
        LocalDateTime t2 = LocalDateTime.of(2017, 8, 29, 0, 0, 0, 0);
        Duration between = Duration.between(t1, t2);
        System.out.println(between);

        System.out.println("相差的总天数:"+between.toDays());
        System.out.println("相差的总小时数:"+between.toHours());
        System.out.println("相差的总分钟数:"+between.toMinutes());
        System.out.println("相差的总秒数:"+between.getSeconds());
        System.out.println("相差的总毫秒数:"+between.toMillis());
        System.out.println("相差的总纳秒数:"+between.toNanos());
        System.out.println("不够一秒的纳秒数:"+between.getNano());
    }
    @Test
    public void test03(){
        //Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
		LocalTime localTime = LocalTime.now();
		LocalTime localTime1 = LocalTime.of(15, 23, 32);
		//between():静态方法,返回Duration对象,表示两个时间的间隔
		Duration duration = Duration.between(localTime1, localTime);
		System.out.println(duration);

		System.out.println(duration.getSeconds());
		System.out.println(duration.getNano());

		LocalDateTime localDateTime = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
		LocalDateTime localDateTime1 = LocalDateTime.of(2017, 6, 12, 15, 23, 32);

		Duration duration1 = Duration.between(localDateTime1, localDateTime);
		System.out.println(duration1.toDays());
    }
}

TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用 TemporalAdjuster 的实现。

@Test
public void test1(){
    // TemporalAdjuster:时间校正器
	// 获取当前日期的下一个周日是哪天?
	TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
	LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
	System.out.println(localDateTime);
	// 获取下一个工作日是哪天?
	LocalDate localDate = LocalDate.now().with(new TemporalAdjuster() {
   	 	@Override
   	 	public Temporal adjustInto(Temporal temporal) {
        	LocalDate date = (LocalDate) temporal;
     	  	if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
           		return date.plusDays(3);
        	} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
            	return date.plusDays(2);
        	} else {
            	return date.plusDays(1);
        	}
    	}
	});
	System.out.println("下一个工作日是:" + localDate);
    /**
      *2024-05-19T11:00:51.039147
	  *下一个工作日是:2024-05-17 

}

自己的测试代码

public class DateParse {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = simpleDateFormat.format(date);
        System.out.println(format);

        Calendar instance = Calendar.getInstance();
        System.out.println(instance);
        String calendarType = instance.getCalendarType();
        System.out.println(calendarType);
        /**
         * Thu May 16 09:40:02 CST 2024
         * 2024-05-16
         * java.util.GregorianCalendar[time=1715823602121,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2024,MONTH=4,WEEK_OF_YEAR=20,WEEK_OF_MONTH=3,DAY_OF_MONTH=16,DAY_OF_YEAR=137,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,HOUR=9,HOUR_OF_DAY=9,MINUTE=40,SECOND=2,MILLISECOND=121,ZONE_OFFSET=28800000,DST_OFFSET=0]
         * gregory 格里高利历或公历 所以为啥十月革命在1917年十一月发生,这个“十月”是儒略历的十月,“十一月”是格里历的十一月 俄罗斯直到1918年才承认格里历
         */
        System.out.println("-------------------------");
        Date date1 = new Date(1715758583857L);
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(date1);
        System.out.println(simpleDateFormat.format(date1));
        System.out.println(simpleDateFormat1.format(date1));
        Date parse = null;
        try {
            parse = simpleDateFormat1.parse("2024-05-25 15:36:23");
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        System.out.println(parse);
        /**
         * Wed May 15 15:36:23 CST 2024
         * 2024-05-15
         * 2024-05-15 15:36:23
         * Sat May 25 15:36:23 CST 2024
         */
        System.out.println("-----------------");
        Date time = instance.getTime();
        System.out.println(time);
        int day = instance.get(Calendar.DAY_OF_YEAR);
        int monthDay = instance.get(Calendar.DAY_OF_MONTH);
        int month = instance.get(Calendar.MONTH);
        int year = instance.get(Calendar.YEAR);

        System.out.println("一年中的第" + day + "天");
        System.out.println("monthDay:" + monthDay);
        System.out.println("month:" + month);
        System.out.println("year:" + year);

        /**
         * Thu May 16 10:07:18 CST 2024
         * 一年中的第137天
         * monthDay:16
         * month:4(月份从0开始)
         */
        System.out.println("-------------");
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDate);
        System.out.println(localTime);
        System.out.println(localDateTime);
        /**
         * 2024-05-16
         * 10:10:26.960086400
         * 2024-05-16T10:10:26.960086400
         */
        System.out.println("-------------------------");
        instance.add(Calendar.DAY_OF_MONTH,10);
        System.out.println(instance.getTime());
        LocalDate localDate1 = localDate.withDayOfMonth(25);
        System.out.println("localDate:" + localDate);
        System.out.println("localDate1:" + localDate1);
        /**
         * Calender会改变原有日期变量,增加了10天
         * Sun May 26 10:15:24 CST 2024
         * 不变性
         * localDate:2024-05-16
         * localDate1:2024-05-25
         */
        System.out.println("---------------------");
        Instant now = Instant.now();
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);
        System.out.println(now);
        Instant instant = Instant.ofEpochMilli(1715758583857L);
        System.out.println(instant);
        OffsetDateTime offsetDateTime1 = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime1);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        System.out.println(dateTimeFormatter.format(localTime));
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("");
        System.out.println(dateTimeFormatter1.format(localTime));


        /**
         * 默认不是东8区,是中时区时间
         * 2024-05-16T10:25:19.906403700+08:00
         * 2024-05-16T02:25:19.906403700Z
         * 2024-05-15T07:36:23.857Z
         * 2024-05-15T15:36:23.857+08:00
         * patten出错,"yyyy-MM-dd HH:mm:ss" Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
         * 10:30:57
         * 解析不了输出空字符串
         */
        System.out.println("-----------------------");
        // TemporalAdjuster:时间校正器
        // 获取当前日期的下一个周日是哪天?
        TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
        LocalDateTime localDateTime3 = LocalDateTime.now().with(temporalAdjuster);
        System.out.println(localDateTime3);
        // 获取下一个工作日是哪天?
        LocalDate localDate3 = LocalDate.now().with(new TemporalAdjuster() {
            @Override
            public Temporal adjustInto(Temporal temporal) {
                LocalDate date = (LocalDate) temporal;
                if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
                    return date.plusDays(3);
                } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                    return date.plusDays(2);
                } else {
                    return date.plusDays(1);
                }
            }
        });
        System.out.println("下一个工作日是:" + localDate3);

    }
}
/**
  * 2024-05-19T11:00:51.039147
  * 下一个工作日是:2024-05-17
  */

本文参考了尚硅谷宋红康老师的讲义

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值