- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在研究旧的 Calendar
API 看看它有多糟糕,我发现 Calendar
有一个 roll
方法。与 add
方法不同,roll
不会更改较大日历字段的值。
例如,日历实例 c
表示日期 2019-08-31。调用 c.roll(Calendar.MONTH, 13)
将 13 添加到月份字段,但不会更改年份,因此结果为 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
的任何有用应用。其次,我认为在极端情况下功能没有得到很好的指定。角落案例将是有趣的案例。如果没有 roll
方法,按 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 点向后拨到凌晨 2 点时,一天是 25 小时,您如何从早上 6 点开始滚动 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));
输出:
1999-06-01
1999-06-30
解释:您引用的文档假定星期日是一周的第一天(它以“星期日是一周的第一天”结束;它可能是在美国写的)所以在六月星期日之前有一周6. 滚动-1周应该滚动到本周之前。我的第一行代码就是这样做的。
在 ISO 周计划中,6 月 6 日星期日属于从 5 月 31 日星期一到 6 月 6 日星期日的那一周,因此 6 月没有本周之前的一周。因此,我的第二行代码滚动到 6 月的最后一周,即 6 月 28 日到 7 月 4 日。由于我们不能超出 6 月,因此选择 6 月 30 日。
我还没有测试它的行为是否与 GregorianCalendar
相同。相比之下,GregorianCalendar.roll
实现使用 52 行代码来处理 WEEK_OF_MONTH
情况,而我的是 20 行。要么我遗漏了一些东西,要么 java.time 再次显示了它的优越性。
我对现实世界的建议是:明确您的要求并直接在 java.time 之上实现它们,而忽略旧 API 的行为方式。作为一项学术练习,您的问题很有趣。
关于java - java.time 中 Calendar.roll 的等价物是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57326072/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!