学习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类的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/m0_49093968/article/details/125436025
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/389019

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Python Flask 库及应用场景

《PythonFlask库及应用场景》Flask是Python生态中​轻量级且高度灵活的Web开发框架,基于WerkzeugWSGI工具库和Jinja2模板引擎构建,下面给大家介绍PythonFl... 目录一、Flask 库简介二、核心组件与架构三、常用函数与核心操作 ​1. 基础应用搭建​2. 路由与参

Spring Boot中的YML配置列表及应用小结

《SpringBoot中的YML配置列表及应用小结》在SpringBoot中使用YAML进行列表的配置不仅简洁明了,还能提高代码的可读性和可维护性,:本文主要介绍SpringBoot中的YML配... 目录YAML列表的基础语法在Spring Boot中的应用从YAML读取列表列表中的复杂对象其他注意事项总

电脑系统Hosts文件原理和应用分享

《电脑系统Hosts文件原理和应用分享》Hosts是一个没有扩展名的系统文件,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应... Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应

CSS 样式表的四种应用方式及css注释的应用小结

《CSS样式表的四种应用方式及css注释的应用小结》:本文主要介绍了CSS样式表的四种应用方式及css注释的应用小结,本文通过实例代码给大家介绍的非常详细,详细内容请阅读本文,希望能对你有所帮助... 一、外部 css(推荐方式)定义:将 CSS 代码保存为独立的 .css 文件,通过 <link> 标签

Python使用Reflex构建现代Web应用的完全指南

《Python使用Reflex构建现代Web应用的完全指南》这篇文章为大家深入介绍了Reflex框架的设计理念,技术特性,项目结构,核心API,实际开发流程以及与其他框架的对比和部署建议,感兴趣的小伙... 目录什么是 ReFlex?为什么选择 Reflex?安装与环境配置构建你的第一个应用核心概念解析组件