学习log-Calendar and LocalDate类的应用

2023-11-11 09:10

本文主要是介绍学习log-Calendar and LocalDate类的应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 引言
    • Calendar
      • 官方介绍
      • 先来段逼格高的源码介绍
      • 构造器
      • 获取实例
      • Calendar使用
        • 常用属性
        • 创建日历实例
        • 获取日历信息
        • 设置未来时间
        • 日历对象获取当前的日期对象
        • 拿到当前日历对象的毫秒值
    • LocalDate
      • LocalDate介绍
      • 先来段逼格高的源码介绍
      • 构造器
    • Calendar使用案例
      • 参考hutool的DateUtil类进行源码解读和使用
        • 获取一天的开始
    • LocalDate案例
      • 场景
      • 实现

引言

工作中安排到某个量化统计的功能实现,发现对Calendar and LocalDate的使用并不太熟练,借此不加班的机会对自己进行一次学习记录
我的方法:观全景,再拆分,然后再copy案例

Calendar

官方介绍

  • java.util.Calendar是一个抽象类,它定义了日历相关的一系列操作,使用
  • java.util.Calendar除了可以表示日期和时间,还可以用它来对时期或时间进行算术运算,比如获取当前日期10天之后的日期。
  • java.util.Calendar由于是一个抽象类,所以我们不能对它进行实例化,如果想获得一个日历实例,可能要用到java.util.GregorianCalendar类。

先来段逼格高的源码介绍

The Calendar class is an abstract class that provides methods for converting between a specific instant in time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for manipulating the calendar fields, such as getting the date of the next week. An instant in time can be represented by a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).
The class also provides additional fields and methods for implementing a concrete calendar system outside the package. Those fields and methods are defined as protected.
Like other locale-sensitive classes, Calendar provides a class method, getInstance, for getting a generally useful object of this type. Calendar’s getInstance method returns a Calendar object whose calendar fields have been initialized with the current date and time:

Calendar rightNow = Calendar.getInstance(); // 获得实例

构造器

/**	无参数构造器,没啥好说的* Constructs a Calendar with the default time zone* and the default {@link java.util.Locale.Category#FORMAT FORMAT}* locale.* @see     TimeZone#getDefault*/protected Calendar(){this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));sharedZone = true;}/** 有参数构造器* Constructs a calendar with the specified time zone and locale.** @param zone the time zone to use。要使用的时区* @param aLocale the locale for the week data。周数据的语言环境*/protected Calendar(TimeZone zone, Locale aLocale){fields = new int[FIELD_COUNT];	// FIELD_COUNT = 17isSet = new boolean[FIELD_COUNT];	// FIELD_COUNT = 17stamp = new int[FIELD_COUNT];	// FIELD_COUNT = 17this.zone = zone;setWeekCountData(aLocale);}/*** Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.* They are used to figure out the week count for a specific date for* a given locale. These must be set when a Calendar is constructed.* @param desiredLocale the given locale.*/private void setWeekCountData(Locale desiredLocale){/* try to get the Locale data from the cache */int[] data = cachedLocaleData.get(desiredLocale);if (data == null) {  /* cache miss */data = new int[2];data[0] = CalendarDataUtility.retrieveFirstDayOfWeek(desiredLocale);data[1] = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(desiredLocale);cachedLocaleData.putIfAbsent(desiredLocale, data);}firstDayOfWeek = data[0];minimalDaysInFirstWeek = data[1];}

就两个构造器

  • 有参数构造器:根据给入的时区与周数据语言环境初始化firstDayOfWeek一周的第一天与minimalDaysInFirstWeek一周的最少天数,加入缓存命中的校验
  • 无参数构造器:就是使用默认的初始化

获取实例

/*** Gets a calendar using the specified time zone and default locale.* The <code>Calendar</code> returned is based on the current time* in the given time zone with the default* {@link Locale.Category#FORMAT FORMAT} locale.** @param zone the time zone to use* @return a Calendar.*/public static Calendar getInstance(TimeZone zone){return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));}private static Calendar createCalendar(TimeZone zone,Locale aLocale){CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();if (provider != null) {try {return provider.getInstance(zone, aLocale);} catch (IllegalArgumentException iae) {// fall back to the default instantiation// 返回到默认实例化}}Calendar cal = null;if (aLocale.hasExtensions()) {String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype != null) {switch (caltype) {case "buddhist":cal = new BuddhistCalendar(zone, aLocale);break;case "japanese":cal = new JapaneseImperialCalendar(zone, aLocale);break;case "gregory":cal = new GregorianCalendar(zone, aLocale);break;}}}if (cal == null) {/*** 如果没有明确指定已知的日历类型,* 请执行创建日历的传统方法:为 th_TH 语言环境创建一个佛教日历,为 ja_JP_JP 语言环境创建一个 JapaneseImperialCalendar,* 或为任何其他语言环境创建一个 GregorianCalendar。* 注意:语言、国家和变体字符串是保留的。*/if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}}return cal;}

简单翻译一下

/*** Gets a calendar using the default time zone and specified locale.* The <code>Calendar</code> returned is based on the current time* in the default time zone with the given locale.** @param aLocale the locale for the week data* @return a Calendar.*/public static Calendar getInstance(Locale aLocale){return createCalendar(TimeZone.getDefault(), aLocale);}/*** Gets a calendar with the specified time zone and locale.* The <code>Calendar</code> returned is based on the current time* in the given time zone with the given locale.** @param zone the time zone to use* @param aLocale the locale for the week data* @return a Calendar.*/public static Calendar getInstance(TimeZone zone,Locale aLocale){return createCalendar(zone, aLocale);}

一共三个getInstance方法,入参不同为重载(Overloading),实际为两个参数反复使用默认应对不同场景

全景就这些了,这就是我看到的全景

Calendar使用

常用属性
属性名解释
YEAR
MONTH
DATE日期
DAY_OF_MONTHdate
DAY_OF_YEAR今年的第几天
DAY_OF_WEEK_IN_MONTH当月的第几周
DAY_OF_WEEK一周的第几天
HOUR12小时时间
HOUR_OF_DAY24小时时间
MINUTE分钟
SECOND
MILLISECOND毫秒
创建日历实例
Calendar cal = Calendar.getInstance();
获取日历信息
		int year = cal.get(Calendar.YEAR);log.info("年 = {}", + year);int month = cal.get(Calendar.MONTH) + 1;log.info("月 = {}", + month);int toDay = cal.get(Calendar.DAY_OF_YEAR);log.info("日 = {}", + toDay);`
设置未来时间
		// 7天后,30分后cal.add(Calendar.DAY_OF_YEAR, 7);cal.add(Calendar.MINUTE, 30);
日历对象获取当前的日期对象
Date date = cal.getTime();
拿到当前日历对象的毫秒值
long time= cal.getTimeInMillis();

LocalDate

LocalDate介绍

  • 在Java 8中引入的LocalDate表示一个格式为yyyy-MM-dd的日期,如2021-06-13。

  • 它不存储时间或时区。

  • LocalDate是一个不可变的类,它是对日期的描述,如生日。

  • LocalDate是一个基于值的类,要比较LocalDate的两个实例,我们应该使用它的equals 方法。

  • 我们可以从LocalDate中获取许多其他的日期字段,如年日(day-of-year)、周日(day-of-week)、月日(month-of-year)等等。

  • LocalDate的格式可以通过DateTimeFormatter的格式方法来改变。

先来段逼格高的源码介绍

A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03.
LocalDate is an immutable date-time object that represents a date, often viewed as year-month-day. Other date fields, such as day-of-year, day-of-week and week-of-year, can also be accessed. For example, the value “2nd October 2007” can be stored in a LocalDate.
This class does not store or represent a time or time-zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
The ISO-8601 calendar system is the modern civil calendar system used today in most of the world. It is equivalent to the proleptic Gregorian calendar system, in which today’s rules for leap years are applied for all time. For most applications written today, the ISO-8601 rules are entirely suitable. However, any application that makes use of historical dates, and requires them to be accurate will find the ISO-8601 approach unsuitable.

构造器

/*** Constructor, previously validated.** @param year  the year to represent, from MIN_YEAR to MAX_YEAR	// 要表示的年份,从 MIN_YEAR 到 MAX_YEAR* @param month  the month-of-year to represent, not null	// 要表示的月份,不为空* @param dayOfMonth  the day-of-month to represent, valid for year-month, from 1 to 31	// // 要表示的日期,对年月有效,从 1 到 31*/private LocalDate(int year, int month, int dayOfMonth) {this.year = year;this.month = (short) month;this.day = (short) dayOfMonth;}

Calendar使用案例

参考hutool的DateUtil类进行源码解读和使用

获取一天的开始

先贴源码举例解读

// 调用beginOfDay方法传入一个Date对象
public static DateTime beginOfDay(Date date) {// calendar:对比传入的Date对象是否和DateTime是同一个实例,如果是则使用((DateTime)date).toCalendar()强转返回Calendar日历对象,如果不是则calendar(date.getTime())获取日期的毫秒去获取Calendar对象的实例,反正就是怎么样都要Calendar呗哈哈哈return new DateTime(beginOfDay(calendar(date)));
}
// 基础支撑calendar(date)获取Calendar对象
public static Calendar calendar(Date date) {return date instanceof DateTime ? ((DateTime)date).toCalendar() : calendar(date.getTime());
}public static Calendar calendar(long millis) {Calendar cal = Calendar.getInstance();cal.setTimeInMillis(millis);return cal;
}// 正点的来了
beginOfDay(calendar(date))
// DAY_OF_MONTH = 5public static Calendar beginOfDay(Calendar calendar) {return truncate(calendar, DateField.DAY_OF_MONTH);}
// TRUNCATE = 0public static Calendar truncate(Calendar calendar, DateField dateField) {return DateModifier.modify(calendar, dateField.getValue(), ModifyType.TRUNCATE);}public static Calendar modify(Calendar calendar, int dateField, DateModifier.ModifyType modifyType) {if (9 == dateField) {boolean isAM = DateUtil.isAM(calendar);switch(modifyType) {// TRUNCATE = 0 所以走的是这一段case TRUNCATE:calendar.set(11, isAM ? 0 : 12);break;case CEILING:calendar.set(11, isAM ? 11 : 23);break;case ROUND:int min = isAM ? 0 : 12;int max = isAM ? 11 : 23;int href = (max - min) / 2 + 1;int value = calendar.get(11);calendar.set(11, value < href ? min : max);}}if (ArrayUtil.contains(ignoreFields, dateField)) {return modify(calendar, dateField + 1, modifyType);} else {for(int i = 14; i > dateField; --i) {if (!ArrayUtil.contains(ignoreFields, i) && 4 != i) {if (4 == dateField) {if (5 == i) {continue;}if (8 == i) {i = 7;}} else if (8 == i) {continue;}modifyField(calendar, i, modifyType);}}return calendar;}}/*** Sets the given calendar field to the given value. The value is not* interpreted by this method regardless of the leniency mode.** @param field the given calendar field.	// 给定的日历字段* @param value the value to be set for the given calendar field.	// 要为给定日历字段设置的值* @throws ArrayIndexOutOfBoundsException if the specified field is out of range*             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).* in non-lenient mode.* @see #set(int,int,int)* @see #set(int,int,int,int,int)* @see #set(int,int,int,int,int,int)* @see #get(int)*/public void set(int field, int value){// If the fields are partially normalized, calculate all the// fields before changing any fields.if (areFieldsSet && !areAllFieldsSet) {computeFields();}internalSet(field, value);isTimeSet = false;areFieldsSet = false;isSet[field] = true;stamp[field] = nextStamp++;if (nextStamp == Integer.MAX_VALUE) {adjustStamp();}}

太多了就不一一解释了,现在是23 23:25分

	// 其实就是给这个数组的指定下标设定值/*** Sets the value of the given calendar field. This method does* not affect any setting state of the field in this* <code>Calendar</code> instance.** @throws IndexOutOfBoundsException if the specified field is out of range*             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).* @see #areFieldsSet* @see #isTimeSet* @see #areAllFieldsSet* @see #set(int,int)*/final void internalSet(int field, int value){fields[field] = value;}/*** The calendar field values for the currently set time for this calendar.* This is an array of <code>FIELD_COUNT</code> integers, with index values* <code>ERA</code> through <code>DST_OFFSET</code>.* @serial*/// 此日历的当前设置时间的日历字段值。这是一个FIELD_COUNT整数数组,索引值从ERA到DST_OFFSET。@SuppressWarnings("ProtectedField")protected int           fields[];
  • 众所周知,对象是存在于堆中的,我们指向的只是堆中的地址值,引用传递更改的就是对象的属性

回到DateTime的构造器

	public DateTime(Calendar calendar) {this(calendar.getTime(), (TimeZone)null);}

创建好DateTime对象就获取到了今日的日期
最后到了这个构造器手上

	public DateTime(long timeMillis, TimeZone timeZone) {super(timeMillis);this.mutable = true;this.firstDayOfWeek = Week.MONDAY;if (null != timeZone) {this.timeZone = timeZone;}}

简单验算一下
在这里插入图片描述
获取起始值关键方法,才将当日的Time重置为今日起始时间,我差点绕偏了
在这里插入图片描述

LocalDate案例

这篇文章的起源
参考博客传送门不知道是否原创,仅为借鉴

场景

获取指定月,每周的开始时间和结束时间

实现

先贴示例
weeks(YearMonth.parse(“2022-06”))

	private static Map<Integer, WeekData> weeks(YearMonth yearMonth){LocalDate start = LocalDate.now().with(yearMonth).with(TemporalAdjusters.firstDayOfMonth());LocalDate end = LocalDate.now().with(yearMonth).with(TemporalAdjusters.lastDayOfMonth());Map<Integer, WeekData> map = Stream.iterate(start, localDate -> localDate.plusDays(1l)).limit(ChronoUnit.DAYS.between(start, end)+1).collect(Collectors.groupingBy(localDate -> localDate.get(WeekFields.of(DayOfWeek.MONDAY, 1).weekOfMonth()),Collectors.collectingAndThen(Collectors.toList(), WeekData::new)));return map;}static class WeekData{// 一周的开始时间private LocalDate start;// 一周的结束时间private LocalDate end;public WeekData(List<LocalDate> localDates) {this.start = localDates.get(0);this.end = localDates.get(localDates.size()-1);}@Overridepublic String toString() {return "开始时间:" + this.start + ",结束时间:" + this.end;}}
  • 第一个步骤,YearMonth转化为List,表示的是这个月的所有日期,这种List的,我第一想法就是用Java8的stream,首先根据yearMonth获得这个月的开始日期和结束日期,用LocalDate的with方法即可,with就是调整的意思,想啥调整就咋调整非常灵活,随便取一个日期(我这里取的是但当前日期)
  • 接下来我们来构造stream,用Stream.iterate(start, localDate -> localDate.plusDays(1l))构造一个无限流,它代表,以start作为起始值,按照第二个参数localDate -> localDate.plusDays(1l)也就是加一天的方式构造一个无限流,当然我要的不是无限,而是要到这个月末,所以limit(ChronoUnit.DAYS.between(start, end) + 1),这样就把这个无限流截断了
  • 这样第一步就完成了,第二步,按周分类,这里有一个知识点,给一个LocalDate对象,怎么判断它是该月的第几周,这里肯定要用LocalDate的get方法,因为这个方法就是表示从当前日期中获取某个属性值,参数是接口TemporalField,你需要传入一个实现类即可,这个实现类就是定义了这个属性,当然JDK默认有一个实现类枚举ChronoField,里面有很多好用的实现类可以用,所以很容易就会选到一个枚举
  • ChronoField.ALIGNED_WEEK_OF_MONTH,看起来好像是对的,ALIGNED不认识,WEEK_OF_MONTH感觉意思很明白,貌似能用,其实不然,这个实现类定义的一周跟我们想象中的不一样,它的一周是按照完整7天来算的,拿8月6号来看,我们感觉是第二周,但是实际结果是第一周,因为要满打满算的7天才算一周,8月6号还是算第一周的第六天而已

这篇关于学习log-Calendar and LocalDate类的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/389019

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例

《PyTorch中的词嵌入层(nn.Embedding)详解与实战应用示例》词嵌入解决NLP维度灾难,捕捉语义关系,PyTorch的nn.Embedding模块提供灵活实现,支持参数配置、预训练及变长... 目录一、词嵌入(Word Embedding)简介为什么需要词嵌入?二、PyTorch中的nn.Em

Spring Boot3.0新特性全面解析与应用实战

《SpringBoot3.0新特性全面解析与应用实战》SpringBoot3.0作为Spring生态系统的一个重要里程碑,带来了众多令人兴奋的新特性和改进,本文将深入解析SpringBoot3.0的... 目录核心变化概览Java版本要求提升迁移至Jakarta EE重要新特性详解1. Native Ima