学习log

编程入门 行业动态 更新时间:2024-10-19 11:48:43

学习<a href=https://www.elefans.com/category/jswz/34/1771098.html style=log"/>

学习log

文章目录

    • 引言
    • 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

本文发布于:2024-03-23 23:43:06,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1744228.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:log

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!