什么是java.time中的Calendar.roll等效项?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了什么是java.time中的Calendar.roll等效项?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4846字,纯文字阅读大概需要7分钟。
内容图文
![什么是java.time中的Calendar.roll等效项?](/upload/InfoBanner/zyjiaocheng/694/25e0a4ad9bd74b079d1c8e1cdcc701ba.jpg)
我正在研究旧的Calendar API,以了解它的糟糕程度,然后发现Calendar具有roll方法.与add方法不同,roll不会更改较大日历字段的值.
例如,日历实例c代表日期2019-08-31.调用c.roll(Calendar.MONTH,13)将13添加到month字段,但不更改年份,因此结果为2019-09-30.请注意,月份的日期会更改,因为它是一个较小的字段.
我试图在现代的java.time API中找到这样的方法.我以为这样的方法必须在LocalDate或LocalDateTime中,但是我什么也没找到.
因此,我尝试编写自己的roll方法:
public static LocalDateTime roll(LocalDateTime ldt, TemporalField unit, long amount) {
LocalDateTime newLdt = ldt.plus(amount, unit.getBaseUnit());
return ldt.with(unit, newLdt.get(unit));
}
但是,这仅适用于某些情况,而不适用于其他情况.例如,它不适用于documentation here中描述的情况:
Consider a GregorianCalendar originally set to Sunday June 6, 1999.
Calling roll(Calendar.WEEK_OF_MONTH, -1) sets the calendar to Tuesday
June 1, 1999, whereas calling add(Calendar.WEEK_OF_MONTH, -1) sets the
calendar to Sunday May 30, 1999. This is because the roll rule imposes
an additional constraint: The MONTH must not change when the
WEEK_OF_MONTH is rolled. Taken together with add rule 1, the resultant
date must be between Tuesday June 1 and Saturday June 5. According to
add rule 2, the DAY_OF_WEEK, an invariant when changing the
WEEK_OF_MONTH, is set to Tuesday, the closest possible value to Sunday
(where Sunday is the first day of the week).
我的代码:
System.out.println(roll(
LocalDate.of(1999, 6, 6).atStartOfDay(),
ChronoField.ALIGNED_WEEK_OF_MONTH, -1
));
输出1999-07-04T00:00,而使用Calendar:
Calendar c = new GregorianCalendar(1999, 5, 6);
c.roll(Calendar.WEEK_OF_MONTH, -1);
System.out.println(c.getTime().toInstant());
输出1999-05-31T23:00:00Z,在我的时区是1999-06-01.
java.time API中的roll等效项是什么?如果没有,我如何编写一种模仿它的方法?
解决方法:
首先,我不记得曾经看过Calendar.roll的任何有用应用程序.其次,我认为在极端情况下不能很好地指定功能.而最极端的情况将是有趣的情况.如果没有rollmethod,按月滚动13个月将不会很难.可能类似的观察结果是java.time不提供此功能的原因.
相反,我认为我们将不得不诉诸更手动的滚动方式.对于第一个示例:
LocalDate date = LocalDate.of(2019, Month.JULY, 22);
int newMonthValue = 1 + (date.getMonthValue() - 1 + 13) % 12;
date = date.with(ChronoField.MONTH_OF_YEAR, newMonthValue);
System.out.println(date);
输出:
2019-08-22
我使用的事实是,在ISO年表中,一年总是有12个月.由于%总是给出从0开始的结果,因此我在模运算之前从基于1的月份值中减去1,然后再加回去.如果投放的月份数可能为负,那么它将变得稍微复杂一些(留给读者阅读).
对于其他字段,我认为在大多数情况下也可以使用类似的方法:给定较大的字段,找到字段的最小和最大可能值,并进行模运算.
在某些情况下,这可能会成为挑战.例如,当夏令时(DST)结束并且时钟从3 AM倒退到2 AM,因此一天是25小时长,您将如何从6 AM开始滚动37小时?我确定可以做到.而且我也确信该功能未内置.
在您滚动一个月的星期的示例中,旧API和现代API之间的另一个区别就起作用了:GregorianCalendar不仅定义了日历的日期和时间,还定义了一个由一周的第一天和一个星期几组成的星期方案.第一周的最少天数.在java.time中,周方案由WeekFields对象定义.因此,在GregorianCalendar中滚动月份中的星期可能是明确的,但不知道星期方案与LocalDate或LocalDateTime无关.可以尝试假定ISO周(从星期一开始,并且第一周是新月中至少有4天的月份),但是可能并不总是用户所希望的.
由于周跨月和年边界,所以一周中的某周和一年中的某周是特殊的.这是我尝试每月执行一周的时间:
private static LocalDate rollWeekOfMonth(LocalDate date, int amount, WeekFields wf) {
LocalDate firstOfMonth = date.withDayOfMonth(1);
int firstWeekOfMonth = firstOfMonth.get(wf.weekOfMonth());
LocalDate lastOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
int lastWeekOfMonth = lastOfMonth.get(wf.weekOfMonth());
int weekCount = lastWeekOfMonth - firstWeekOfMonth + 1;
int newWeekOfMonth = firstWeekOfMonth
+ (date.get(wf.weekOfMonth()) - firstWeekOfMonth
+ amount % weekCount + weekCount)
% weekCount;
LocalDate result = date.with(wf.weekOfMonth(), newWeekOfMonth);
if (result.isBefore(firstOfMonth)) {
result = firstOfMonth;
} else if (result.isAfter(lastOfMonth)) {
result = lastOfMonth;
}
return result;
}
试试看:
System.out.println(rollWeekOfMonth(LocalDate.of(1999, Month.JUNE, 6), -1, WeekFields.SUNDAY_START));
System.out.println(rollWeekOfMonth(LocalDate.of(1999, Month.JUNE, 6), -1, WeekFields.ISO));
输出:
06003
说明:您引用的文档假设星期日是一周的第一天(以“星期日是一周的第一天结尾”;它可能是在美国写的),因此在6月6日星期日之前还有一周.滚动-1周应进入本周之前.我的第一行代码就是这样做的.
在ISO周计划中,6月6日星期日属于从5月31日星期一到6月6日星期日的星期,因此6月在这个星期之前没有星期.因此,我的第二行代码进入6月28日的6月最后一个星期到7月4日.由于我们不能选择6月30日之外.
我尚未测试它的行为是否与GregorianCalendar相同.为了进行比较,与我的20行相比,GregorianCalendar.roll实现使用52条代码行来处理WEEK_OF_MONTH情况.我要么没有考虑任何事情,要么java.time再次显示了它的优越性.
相反,我对现实世界的建议是:明确要求并直接在java.time之上实现它们,而忽略旧API的行为方式.作为一项学术练习,您的问题是一个有趣而有趣的问题.
内容总结
以上是互联网集市为您收集整理的什么是java.time中的Calendar.roll等效项?全部内容,希望文章能够帮你解决什么是java.time中的Calendar.roll等效项?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。