Java 日期类 API

1. jdk8 之前的日期 API

1.1. System 类 currentTimeMillis();

java 复制代码
@Test  
public void test1() {  
	long timeMillis = System.currentTimeMillis();  
	System.out.println("timeMillis = " + timeMillis);  
}

1.2. java.util.Date 和 java.sql.Date

  1. java.sql.Datejava.util.Date 的子类:
  2. 两个构造器的使用
    1. new Date() ==> 获取当前的时间
    2. new Date(long timeMills) ==> 获取指定时间戳下的时间
  3. 两个方法的使用
    1. toString()
    2. getTime()==>获取当前Data对象的时间戳
java 复制代码
Date date1 = new Date();
System.out.println("date1 = " + date1);   //date1 = Tue Jul 06 09:47:42 CST 2021
System.out.println("date1.getTime() = " + date1.getTime()); //date1.getTime() = 1625536103670

Date date2 = new Date(123456789L);
System.out.println("date2 = " + date2);  //date2 = Fri Jan 02 18:17:36 CST 1970

java.sql.Date date3 = new java.sql.Date(123456789L);
System.out.println("date3 = " + date3);  //date3 = 1970-01-02

//将java.util.Date转换成java.sql.Date
java.sql.Date date4 = new java.sql.Date(date1.getTime());
System.out.println("date4 = " + date4);  //date4 = 2021-07-06

1.3. java.text.SimpleDateFormat

java 复制代码
@Test
public void test1() throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat();
    //格式化
    Date date = new Date();
    System.out.println("date = " + date);

    String format = sdf.format(date);
    System.out.println("format = " + format);

    //解析
    String str = "2019-08-12 12:00:00";
    //设置解析日期字符串的模式,可以在创建SimpleDateFormat(String pattern);设置
    sdf.applyPattern("yyyy-MM-dd hh:mm:ss");
    sdf.parse(str);
    System.out.println("str = " + str);
}

1.4. 线程安全的日期格式化工具类

java 复制代码
public class DataUtils {
    /**
     * ThreadLocal 提供一种 lombda 构造方式
     * 返回此线程局部变量的当前线程的"初始值"。线程第一次使用 get() 方法访问变量时将调用此方法,
     * 但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法
     * 对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。
     */
    private static ThreadLocal<DateFormat> threadLocal
            = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
 
    public static Date parse(String date) {
	    try {
		    return threadLocal.get().parse(date);
	    } catch (Exception e) {
		    return null;
		}
    }
 
    public static String format(Date date){
        return date != null ? threadLocal.get().format(date) : null;
    }

	public static Date parse(String date, String pattern) {
	    try {
		    return new SimpleDateFormat(pattern).parse(date);
	    } catch (Exception e) {
		    return null;
		}
    }
 
    public static String format(Date date, String pattern){
        return date != null ? new SimpleDateFormat(pattern).format(date) : null;
    }
}
Letter Date or Time Component Examples
G Era designator AD
y Year 1996; 96
Y Week year 2009; 09
M Month in year (context sensitive) July; Jul; 07
L Month in year (standalone form) July; Jul; 07
w Week in year 27
W Week in month 2
D Day in year 189
d Day in month 10
F Day of week in month 2
E Day name in week Tuesday; Tue
u Day number of week (1 = Monday, ..., 7 = Sunday) 1
a Am/pm marker PM
H Hour in day (0-23) 0
k Hour in day (1-24) 24
K Hour in am/pm (0-11) 0
h Hour in am/pm (1-12) 12
m Minute in hour 30
s Second in minute 55
S Millisecond 978
z Time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone -0800
X Time zone -08; -0800; -08:00

1.5. java.util.Calendar(日历)

  • Date 类的API大部分被废弃了,替换为 Calendar
  • Calendar 类是一个抽象类,主用用于完成日期字段之间相互操作的功能。
  • 获取 Calendar 实例的方法
    • 使用 Calendar.getInstance() 方法
    • 调用它的子类 GregorianCalendar(公历)的构造器。
修饰符和类型 方法 描述
static Calendar getInstance() 获取使用默认时区和区域设置的日历。
static Calendar getInstance(Locale aLocale) 获取使用默认时区和指定区域设置的日历。
static Calendar getInstance(TimeZone zone) 获取使用指定时区和默认区域设置的日历。
static Calendar getInstance(TimeZone zone, Locale aLocale) 获取具有指定时区和区域设置的日历。

Calendar 的相关方法:

  • public int get(int field):返回给定日历字段的值
  • public void set(int field,int value):将给定的日历字段设置为指定的值
  • public void add(int field,int amount):根据日历的规则,为给定的日历字段添加或者减去指定的时间量
  • public final Date getTime():将Calendar转成Date对象
  • public final void setTime(Date date):使用指定的Date对象重置Calendar的时间

其中 field 的值为 Calendar 的一组静态常量:YEARMONTHDAY_OF_WEEKHOUR_OF_DAYMINUTESECOND等;

1.6. jdk8 之前的时间 API 缺陷

  1. 可变性:像日期、时间这样的类应该是不可变的;
  2. 偏移性Date 中的年份都是从 1900 年开始,月份都是从 0 开始的;
  3. 格式化 :格式化只对 Date 类型数据有效,无法应用于 Calendar
  4. 安全性DateCalendar 都是线程不安全的,此外还不能处理闰秒的情况;

2. jdk8 新增的时间 API

新的日期 API

  1. java.time:包含值对象的基础包
  2. java.time.chrono:提供对不同的日历系统的访问
  3. java.time.format:格式化和解析时间和日期
  4. java.time.temporal:包括底层框架和扩展特性
  5. java.time.zone:包含时区支持的类

大多数情况只会用到基础包和 format 包,偶尔会用到 temporal

2.1. LocalDate、LocalTime、LocalDateTime

  1. LocalDate 代表 IOS 格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
  2. LocalTime 表示一个时间,而不是日期。
  3. LocalDateTime 是用来表示日期和时间的,这是一个最常用的类之一。
方法 描述
now()/now(ZoneId zone) 静态方法,根据当前时间创建对象/指定时区的对象
of(xx,xx,xx,xx,xx,xxx) 静态方法,根据指定日期/时间创建对象
getDayOfMonth()/getDayOfYear() 获得月份天数(1-31) /获得年份天数(1-366)
getDayOfWeek() 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth() 获得月份, 返回一个 Month 枚举值
getMonthValue() / getYear() 获得月份(1-12) /获得年份
getHours()/getMinute()/getSecond() 获得当前对象对应的小时、分钟、秒
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
with(TemporalAdjuster t) 将当前日期时间设置为校对器指定的日期时间
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours() 向当前对象添加几天、几周、几个月、几年、几小时
minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours() 从当前对象减去几月、几周、几天、几年、几小时
plus(TemporalAmount t)/minus(TemporalAmount t) 添加或减少一个 Duration 或 Period
isBefore()/isAfter() 比较两个 LocalDate
isLeapYear() 判断是否是闰年(在LocalDate类中声明)
format(DateTimeFormatter t) 格式化本地日期、时间,返回一个字符串
parse(Charsequence text) 将指定格式的字符串解析为日期、时间
java 复制代码
@Test
public void test1() {
    System.out.println("now()==============================");
    //now(): 获取当前日期,时间,日期+时间
    LocalDate localDate = LocalDate.now();
    LocalTime localTime = LocalTime.now();
    LocalDateTime localDateTime = LocalDateTime.now();

    System.out.println("localDate = " + localDate);	//2021-07-06
    System.out.println("localTime = " + localTime);	//18:05:16.139
    System.out.println("localDateTime = " + localDateTime);	//2021-07-06T18:05:16.140

    System.out.println("of()===============================");
    //of(): 根据指定日期/时间创建对象(没有偏移量)
    LocalDateTime localDateTimeWithOf = LocalDateTime.of(1999, 06, 12, 6, 30, 0);
    System.out.println("localDateTimeWithOf = " + localDateTimeWithOf);	///1999-06-12T06:30

    //getXxx():
    System.out.println("getXxx()===========================");
    int dayOfMonth = localDateTime.getDayOfMonth();
    System.out.println("dayOfMonth = " + dayOfMonth);	//6
    DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();	
    System.out.println("dayOfWeek = " + dayOfWeek);	    //TUESDAY
    System.out.println("dayOfWeek.getValue() = " + dayOfWeek.getValue()); //2

    System.out.println("with()=============================");
    //with(): 修改指定值===>返回一个新的对象
    LocalDateTime localDateTime1 = localDateTimeWithOf.withYear(2021);
    System.out.println("localDateTime1 = " + localDateTime1);	//2021-06-12T06:30
    LocalDateTime localDateTime2 = localDateTime1.withDayOfYear(120);
    System.out.println("localDateTime2 = " + localDateTime2);	//2021-04-30T06:30

    System.out.println("plusXxx()==========================");
    //plusXxx(): 在指定的年月日/时间上加上指定的值===>返回新的对象
    LocalDateTime localDateTime3 = localDateTime2.plusSeconds(30);
    System.out.println("localDateTime3 = " + localDateTime3);	//2021-04-30T06:30:30
    LocalDateTime localDateTime4 = localDateTime3.plusHours(8);
    System.out.println("localDateTime4 = " + localDateTime4);	//2021-04-30T14:30:30

    System.out.println("minusXxx()=========================");
    //minusXxx(): 在指定的年月日/时间上减去指定的值===>返回新的对象
    LocalDateTime localDateTime5 = localDateTime4.minusHours(8);
    System.out.println("localDateTime5 = " + localDateTime5);	//2021-04-30T06:30:30
    LocalDateTime localDateTime6 = localDateTime5.minusDays(120);
    System.out.println("localDateTime6 = " + localDateTime6);	//2020-12-31T06:30:30
}

2.2. Instant

java 复制代码
@Test
public void test1() {
    //now(): 获取本初子午线对应的标准时间
    Instant instant = Instant.now();
    System.out.println("instant = " + instant);

    //获取指定偏移量的标准时间,+表示东区;-表示西区
    //获取东八区,即北京时间
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));

    //获取标准时间对应的时间戳
    System.out.println("instant.toEpochMilli() = " + instant.toEpochMilli());

    //通过指定的毫秒数,获取Instant实例
    Instant instant1 = Instant.ofEpochMilli(1625569576277L);
    System.out.println("instant1 = " + instant1.atOffset(ZoneOffset.ofHours(8)));
}

2.3. DateFormatter

格式化和解析日期时间

  1. 预定义的标准格式:ISO_LOCAL_DATE_TIME; ISO_LOCAL_DATE; ISO_LOCAL_TIME
  2. 本地化相关的格式:
    1. ofLocalizedDateTime(FormatStyle.LONG)
      1. FormatStyle.LONG:2021年7月6日 下午07时52分01秒
      2. FormatStyle.MEDIUM:2021-7-6 19:52:14
      3. FormatStyle.SHORT:21-7-6 下午7:52
    2. ofLocalizedDate(FormatStyle.LONG)
      1. FormatStyle.FULL:2021年7月6日 星期二
      2. FormatStyle.LONG:2021年7月6日
      3. FormatStyle.MEDIUM:2021-7-6
      4. FormatStyle.SHORT:21-7-6
  3. 自定义的格式:ofPattern()
java 复制代码
@Test
public void test1() {
    //1.预定义的标准格式:ISO_LOCAL_DATE_TIME; ISO_LOCAL_DATE; ISO_LOCAL_TIME
    DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    LocalDateTime localDateTime = LocalDateTime.now();
    String format = formatter.format(localDateTime);
    System.out.println("format = " + format);   //2021-07-06T19:57:29.391

    TemporalAccessor parse = formatter.parse("2021-07-06T19:42:01.801");
    //将TemporalAccessor转为LocalDateTime
    LocalDateTime localDateTime1 = LocalDateTime.from(parse);
    System.out.println("localDateTime1 = " + localDateTime1);       //2021-07-06T19:42:01.801

    //2.本地化相关的格式:ofLocalizedDateTime(FormatStyle.LONG)
    //提供了三个常量:
    // FormatStyle.LONG: 2021年7月6日 下午07时52分01秒
    // FormatStyle.MEDIUM: 2021-7-6 19:52:14
    // FormatStyle.SHORT: 21-7-6 下午7:52
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
    System.out.println(dateTimeFormatter.format(localDateTime));        //21-7-6 下午7:57

    //3.本地化相关的格式:ofLocalizedDate(FormatStyle.LONG)
    //提供了四个常量:
    // FormatStyle.FULL: 2021年7月6日 星期二
    // FormatStyle.LONG: 2021年7月6日
    // FormatStyle.MEDIUM: 2021-7-6
    // FormatStyle.SHORT: 21-7-6
    dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
    System.out.println(dateTimeFormatter.format(localDateTime));        //21-7-6

    //4.自定义的格式:ofPattern()
    dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    System.out.println(dateTimeFormatter.format(localDateTime));        //2021-07-06
}

2.4. ZoneId 类中包含了所有的时区信息

  1. ZoneId.getAvailableZoneIds(); 获取所有的时区集
  2. LocalDateTime.now(ZoneId.of("Asia/Shanghai")); 获取指定时区的时间
java 复制代码
@Test
public void test1() {
    //获得所有的时区集
    Set<String> zoneIds = ZoneId.getAvailableZoneIds();

    //获取上海时区的当前时间
    LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
    System.out.println("localDateTime = " + localDateTime); //2021-07-06T20:44:54.828
}

2.5. ZonedDateTime 带时区的日期时间

  1. ZonedDateTime.now(); 获取本时区的对象,不带时区
  2. ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); 获取指定时区的对象
java 复制代码
@Test
public void test2() {
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    System.out.println("zonedDateTime = " + zonedDateTime); //2021-07-06T20:44:22.490+08:00[Asia/Shanghai]

    ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
    System.out.println("zonedDateTime1 = " + zonedDateTime1); //2021-07-06T20:44:22.490+08:00[Asia/Shanghai]
}

2.6. Duration 用于计算两个"时间"间隔,以秒和纳秒为基准

  1. Duration.between(TemporalAccessor time1, TemporalAccessor time2); 返回一个 Duration 对象实例
  2. duration.getSeconds(); 返回两个时间之间相差的秒数
  3. duration.getNano(); 返回两个时间相差的毫微妙(Long),对1秒取余
  4. duration1.toDays(); 返回两个时间相差的天数
java 复制代码
@Test
public void test3() throws InterruptedException {
    LocalTime localTime1 = LocalTime.now();
    Thread.sleep(9543L);
    LocalTime localTime2 = LocalTime.now();

    Duration duration = Duration.between(localTime1, localTime2);
    System.out.println("duration = " + duration);   //duration = PT9.639S

    System.out.println("duration.getSeconds() = " + duration.getSeconds());
    //返回毫微妙级的long值
    System.out.println("duration.getNano() = " + duration.getNano());


    LocalDateTime localDateTime1 = LocalDateTime.of(2019, 6, 13, 8, 0, 0);
    LocalDateTime localDateTime2 = LocalDateTime.of(2019, 6, 15, 13, 30, 0);
    Duration duration1 = Duration.between(localDateTime1, localDateTime2);
    System.out.println("duration1 = " + duration1);
    System.out.println("duration1.toDays() = " + duration1.toDays());
}

2.7. Period 用于计算两个"日期"间隔,以年、月、日衡量

  1. Period.between(localDate2, localDate1); 返回一个 Period 对象实例
  2. period1.getYears()period1.getMonths()period1.getDays() 相差的年月日,三者拼在一起才是两个日期只差
  3. period1.withYears(int year); 设置 Period 对象实例;
  4. period1.addTo(TemporalAccessor time); 把当前 Period 对象记录的日期差加到指定的日期上,返回一个 TemporalAccessor
java 复制代码
@Test
public void test4() {
    LocalDate localDate1 = LocalDate.of(2021, 7, 6);
    LocalDate localDate2 = LocalDate.of(2020, 6, 13);

    Period period1 = Period.between(localDate2, localDate1);
    System.out.println("period1 = " + period1);
    System.out.println("period1.getYears() = " + period1.getYears());   //1
    System.out.println("period1.getMonths() = " + period1.getMonths()); //0
    System.out.println("period1.getDays() = " + period1.getDays());     //23
    //所以两个日期相差了1年零23天

    //设置period1的值
    Period period2 = period1.withYears(2);
    //把当前相差的日期加到localDate1上,返回一个Date
    Temporal temporal = period1.addTo(localDate1);
    System.out.println("period2 = " + period2);
    System.out.println("temporal = " + temporal);
}

2.8. TemporalAdjuster 时间校正器

java 复制代码
@Test
public void test5() {
    //获取当前日期的下一个周日是哪一天
    TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
    LocalDate localDate = LocalDate.now().with(temporalAdjuster);
    System.out.println("localDate = " + localDate);

    //返回当前日期的下一个工作日是哪一天
    LocalDate localDate2 = 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("localDate2 = " + localDate2);
}
相关推荐
深度学习lover1 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
API快乐传递者2 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍