学习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

相关文章

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

PostgreSQL简介及实战应用

《PostgreSQL简介及实战应用》PostgreSQL是一种功能强大的开源关系型数据库管理系统,以其稳定性、高性能、扩展性和复杂查询能力在众多项目中得到广泛应用,本文将从基础概念讲起,逐步深入到高... 目录前言1. PostgreSQL基础1.1 PostgreSQL简介1.2 基础语法1.3 数据库

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

Python中yield的用法和实际应用示例

《Python中yield的用法和实际应用示例》在Python中,yield关键字主要用于生成器函数(generatorfunctions)中,其目的是使函数能够像迭代器一样工作,即可以被遍历,但不会... 目录python中yield的用法详解一、引言二、yield的基本用法1、yield与生成器2、yi