添加日历日未按预期工作
Calendar day adding not working as expected
我正在尝试编写一个算法,该算法基于 1 到 31(一个月中的一天)之间的数字,它将 return 之前那一刻的毫秒数 day/number。
该算法将始终使用今天日期。
例子:
输入:5
输出:1601845199000,即 2020 年 10 月 4 日 23:59:59
================
输入:31
输出:1601499599000,即 2020 年 9 月 30 日 23:59:59
因为月份没有 31 天,即使给定 31 天,算法也会采用最接近的可能日期。
二月 29/30 也是如此
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 23)
calendar.set(Calendar.MINUTE, 59)
calendar.set(Calendar.SECOND, 59)
calendar.clear(Calendar.MILLISECOND)
val lastDayNumber = 31
var found = false
while (!found) {
if (calendar.get(Calendar.DAY_OF_MONTH) <= lastDayNumber) {
found = true
}
if (calendar.get(Calendar.DAY_OF_MONTH) < lastDayNumber) {
calendar.add(Calendar.DATE, 1)
}
}
问题是 calendar.add(Calendar.DATE, 1)
根本不工作。
此方法应查找未来给定数字的前一天。我错过了什么吗?我已经阅读了文档和其他 Whosebug 答案,但我仍然无法理解。
Edit1:我也尝试过 calendar.add(Calendar.DAY_OF_MONTH, 1)
和 +1,但是,-1 工作得很好。
编辑2:
查看 GregorianCalendar.java
我看到以下内容:
// Handle week, day and AM_PM fields which involves
// time zone offset change adjustment. Convert the
// given amount to the number of days.
case WEEK_OF_YEAR:
case WEEK_OF_MONTH:
case DAY_OF_WEEK_IN_MONTH:
delta *= 7;
break;
case DAY_OF_MONTH: // synonym of DATE
case DAY_OF_YEAR:
case DAY_OF_WEEK:
break;
如果我以 WEEL_OF_YEAR
为例,相同的代码将 运行 也用于 week_of_month 和 day_of_week_in_month,因为没有中断所有 3 个字段 运行 通过相同的代码。
但是,我在 DAY_OF_MONTH
、DAY_OF_YEAR
和 DAY_OF_WEEK
.
上完全没有看到 运行 的代码
P.S。我找不到 DATE
字段
============================================= =====
使用LocalDateTime
fun getLastDayOfMonth(date: LocalDateTime): Long {
val lastDayNumber = lastDay?.filter { it.isDigit() }!!.toInt()
var found = false
while (!found) {
if (date.dayOfMonth <= lastDayNumber) {
found = true
} else {
date.plusDays(1)
}
}
return date.toEpochSecond(ZoneOffset.UTC)
}
date.plusDays(1) is not changing the date variable to be next day ...
您可以使用 java.time
,它为此提供了非常方便的方法。
看这个例子:
import java.time.LocalDate
fun main() {
val fourDaysAgo = findDate(4)
println(fourDaysAgo)
}
fun findDate(daysAgo: Long): LocalDate {
return LocalDate.now().minusDays(daysAgo)
}
输出4天前的日期(今天执行/2020-09-07)
2020-09-03
LocalDate.now()
计算今天的日期(注意:只是日期部分,不涉及一天中的时间、偏移量或时区)和 returns 具有方法的 LocalDate
minusDays(long days)
通过在必要时调整月份和年份来正确计算 日期前 。
如果您执行以下操作:
println(LocalDate.of(2020, 1, 1).minusDays(1))
输出将是
2019-12-31
如果您还需要时间部分,甚至可能需要偏移量或时区才能真正正确地减去天、小时、分钟或任何时间单位,请查看 类 java.time
...
在您的问题下发表以下评论后进行编辑:
如果您输入 7 而今天是 9 月 7 日,您应该得到 10 月 6 日。如果您输入 8,您应该得到 9 月 7 日(今天)
fun findDate(dayOfMonth: Int): LocalDate {
val now = LocalDate.now()
val currentDayOfMonth = now.getDayOfMonth()
if (currentDayOfMonth <= dayOfMonth) {
// use the current month with the given day of month
return now.withDayOfMonth(dayOfMonth)
// subtract a day (will change the month when dayOfMonth == 1)
.minusDays(1)
// and add a month
.plusMonths(1)
} else {
// otherwise just take the current month with the given day of month
return now.withDayOfMonth(dayOfMonth)
// and subtract a day
.minusDays(1)
}
}
注意:我猜的是输入的第几天小于今天的情况,因为你没有为它指定任何行为。这种情况的处理方式与每月的相等天数(参数和今天)相同。
我来了。与 deHaar 一样,我强烈建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。您尝试使用的 Calendar
class 设计不佳且已过时。
因为你想要午夜前 1 秒的时间,让我们先用这个值声明一个常量:
private static final Duration timeBeforeStartOfDay = Duration.ofSeconds(1);
如果您更喜欢某一天,很容易将其更改为 1 分钟、1 毫秒或 1 纳秒。
我们需要考虑一些特殊情况。我认为这段代码可以做到:
ZoneId zone = ZoneId.systemDefault();
int dayNumber = 31;
LocalDate today = LocalDate.now(zone);
YearMonth ym = YearMonth.from(today);
if (dayNumber <= today.getDayOfMonth()) {
// Next month
ym = ym.plusMonths(1);
}
ZonedDateTime targetDateTime;
if (dayNumber > ym.lengthOfMonth()) {
// Use end of month
targetDateTime = ym.plusMonths(1)
.atDay(1)
.atStartOfDay(zone)
.minus(timeBeforeStartOfDay);
} else {
// Use day number
targetDateTime = ym.atDay(dayNumber)
.atStartOfDay(zone)
.minus(timeBeforeStartOfDay);
}
long milliseconds = targetDateTime.toInstant().toEpochMilli();
System.out.println("Target date and time: " + targetDateTime);
System.out.println("Target milliseconds: " + milliseconds);
我们 运行 在哪个时区会有所不同。我 运行 它在 Europe/Bucharest 时区,因为我想它可能是你的。今天(9 月 7 日)的输出是:
Target date and time: 2020-09-30T23:59:59+03:00[Europe/Bucharest]
Target milliseconds: 1601499599000
Link: Oracle tutorial: Date Time 解释如何使用 java.time.
我正在尝试编写一个算法,该算法基于 1 到 31(一个月中的一天)之间的数字,它将 return 之前那一刻的毫秒数 day/number。 该算法将始终使用今天日期。
例子: 输入:5 输出:1601845199000,即 2020 年 10 月 4 日 23:59:59
================
输入:31 输出:1601499599000,即 2020 年 9 月 30 日 23:59:59
因为月份没有 31 天,即使给定 31 天,算法也会采用最接近的可能日期。
二月 29/30 也是如此
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 23)
calendar.set(Calendar.MINUTE, 59)
calendar.set(Calendar.SECOND, 59)
calendar.clear(Calendar.MILLISECOND)
val lastDayNumber = 31
var found = false
while (!found) {
if (calendar.get(Calendar.DAY_OF_MONTH) <= lastDayNumber) {
found = true
}
if (calendar.get(Calendar.DAY_OF_MONTH) < lastDayNumber) {
calendar.add(Calendar.DATE, 1)
}
}
问题是 calendar.add(Calendar.DATE, 1)
根本不工作。
此方法应查找未来给定数字的前一天。我错过了什么吗?我已经阅读了文档和其他 Whosebug 答案,但我仍然无法理解。
Edit1:我也尝试过 calendar.add(Calendar.DAY_OF_MONTH, 1)
和 +1,但是,-1 工作得很好。
编辑2:
查看 GregorianCalendar.java
我看到以下内容:
// Handle week, day and AM_PM fields which involves
// time zone offset change adjustment. Convert the
// given amount to the number of days.
case WEEK_OF_YEAR:
case WEEK_OF_MONTH:
case DAY_OF_WEEK_IN_MONTH:
delta *= 7;
break;
case DAY_OF_MONTH: // synonym of DATE
case DAY_OF_YEAR:
case DAY_OF_WEEK:
break;
如果我以 WEEL_OF_YEAR
为例,相同的代码将 运行 也用于 week_of_month 和 day_of_week_in_month,因为没有中断所有 3 个字段 运行 通过相同的代码。
但是,我在 DAY_OF_MONTH
、DAY_OF_YEAR
和 DAY_OF_WEEK
.
P.S。我找不到 DATE
字段
============================================= =====
使用LocalDateTime
fun getLastDayOfMonth(date: LocalDateTime): Long {
val lastDayNumber = lastDay?.filter { it.isDigit() }!!.toInt()
var found = false
while (!found) {
if (date.dayOfMonth <= lastDayNumber) {
found = true
} else {
date.plusDays(1)
}
}
return date.toEpochSecond(ZoneOffset.UTC)
}
date.plusDays(1) is not changing the date variable to be next day ...
您可以使用 java.time
,它为此提供了非常方便的方法。
看这个例子:
import java.time.LocalDate
fun main() {
val fourDaysAgo = findDate(4)
println(fourDaysAgo)
}
fun findDate(daysAgo: Long): LocalDate {
return LocalDate.now().minusDays(daysAgo)
}
输出4天前的日期(今天执行/2020-09-07)
2020-09-03
LocalDate.now()
计算今天的日期(注意:只是日期部分,不涉及一天中的时间、偏移量或时区)和 returns 具有方法的 LocalDate
minusDays(long days)
通过在必要时调整月份和年份来正确计算 日期前 。
如果您执行以下操作:
println(LocalDate.of(2020, 1, 1).minusDays(1))
输出将是
2019-12-31
如果您还需要时间部分,甚至可能需要偏移量或时区才能真正正确地减去天、小时、分钟或任何时间单位,请查看 类 java.time
...
在您的问题下发表以下评论后进行编辑:
如果您输入 7 而今天是 9 月 7 日,您应该得到 10 月 6 日。如果您输入 8,您应该得到 9 月 7 日(今天)
fun findDate(dayOfMonth: Int): LocalDate {
val now = LocalDate.now()
val currentDayOfMonth = now.getDayOfMonth()
if (currentDayOfMonth <= dayOfMonth) {
// use the current month with the given day of month
return now.withDayOfMonth(dayOfMonth)
// subtract a day (will change the month when dayOfMonth == 1)
.minusDays(1)
// and add a month
.plusMonths(1)
} else {
// otherwise just take the current month with the given day of month
return now.withDayOfMonth(dayOfMonth)
// and subtract a day
.minusDays(1)
}
}
注意:我猜的是输入的第几天小于今天的情况,因为你没有为它指定任何行为。这种情况的处理方式与每月的相等天数(参数和今天)相同。
我来了。与 deHaar 一样,我强烈建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。您尝试使用的 Calendar
class 设计不佳且已过时。
因为你想要午夜前 1 秒的时间,让我们先用这个值声明一个常量:
private static final Duration timeBeforeStartOfDay = Duration.ofSeconds(1);
如果您更喜欢某一天,很容易将其更改为 1 分钟、1 毫秒或 1 纳秒。
我们需要考虑一些特殊情况。我认为这段代码可以做到:
ZoneId zone = ZoneId.systemDefault();
int dayNumber = 31;
LocalDate today = LocalDate.now(zone);
YearMonth ym = YearMonth.from(today);
if (dayNumber <= today.getDayOfMonth()) {
// Next month
ym = ym.plusMonths(1);
}
ZonedDateTime targetDateTime;
if (dayNumber > ym.lengthOfMonth()) {
// Use end of month
targetDateTime = ym.plusMonths(1)
.atDay(1)
.atStartOfDay(zone)
.minus(timeBeforeStartOfDay);
} else {
// Use day number
targetDateTime = ym.atDay(dayNumber)
.atStartOfDay(zone)
.minus(timeBeforeStartOfDay);
}
long milliseconds = targetDateTime.toInstant().toEpochMilli();
System.out.println("Target date and time: " + targetDateTime);
System.out.println("Target milliseconds: " + milliseconds);
我们 运行 在哪个时区会有所不同。我 运行 它在 Europe/Bucharest 时区,因为我想它可能是你的。今天(9 月 7 日)的输出是:
Target date and time: 2020-09-30T23:59:59+03:00[Europe/Bucharest] Target milliseconds: 1601499599000
Link: Oracle tutorial: Date Time 解释如何使用 java.time.