在 Java 中的两个 time/date 之间生成特定间隔
Generate specific intervals between two time/date in Java
我想生成两个给定 date/time 之间的间隔。
例如,对于 24 小时格式 (HH:MM)
,我有这两个端点,00:00 和 11:51,假设我想将它分成 24 块。所以我的计算是这样的:
(hour * 3600 + min * 60) / 24
如果我使用 calendar.add(Calendar.SECOND, (hour * 3600 + min * 60) / 24)
,我就错了 dates/time。我的计算是双倍的,我认为 calendar.add()
不支持双倍。就像把 28.883 当作 29 一样。
本质上我想要这样的东西:
now : 15:57
today start : 00:00 (24hh)
output : 00:00, 00:47.85, …, 15:57
您需要将开始日期保存在日历对象中,然后在生成每个分区时使用公式:
startCalendar.add(Calendar.Second, count * (hour * 3600 + min * 60) / 24))
这样,除以 24(或其他)得到的算术错误就不会累积。
您的代码的实际问题是您正在执行整数除法。我假设 hour
和 min
都被定义为整数类型。公式 (hour * 3600 + min * 60) / 24
始终生成整数类型。如果将代码更改为 (hour * 3600 + min * 60) / 24d
,表达式至少会产生一个浮点值。
下一个问题确实是 Calendar.add(int field, int amount)
只接受一个整数作为第二个参数。当然,如果您将 Calendar.SECOND
作为第一个参数传递,那么您的精度不会高于秒。您可以使用 Calendar.MILLISECOND
以获得更高的精度。
但是,我建议使用新的 Java 日期和时间 API,而不是 troublesome 旧的 API :
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
long span = Duration.between(startTime, endTime).toNanos();
final int n = 23; // Number of pieces
LongStream.rangeClosed(0, n)
.map(i -> i * span / n)
.mapToObj(i -> startTime.plusNanos(i))
.forEach(System.out::println);
这是 的变体。我想把数学留给图书馆 class。 Duration
有我们可以利用的方法 dividedBy
和 multipliedBy
。
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
final int n = 24; // Number of pieces
Duration piece = Duration.between(startTime, endTime).dividedBy(n);
LocalTime[] partitionTimes = IntStream.rangeClosed(0, n)
.mapToObj(i -> startTime.plus(piece.multipliedBy(i)))
.toArray(LocalTime[]::new);
System.out.println(Arrays.toString(partitionTimes));
输出:
[00:00, 00:29:37.500, 00:59:15, 01:28:52.500, 01:58:30, 02:28:07.500,
02:57:45, 03:27:22.500, 03:57, 04:26:37.500, 04:56:15, 05:25:52.500,
05:55:30, 06:25:07.500, 06:54:45, 07:24:22.500, 07:54, 08:23:37.500,
08:53:15, 09:22:52.500, 09:52:30, 10:22:07.500, 10:51:45,
11:21:22.500, 11:51]
是否存在四舍五入的问题?以整分钟为单位的开始时间和 24 件不会有,因为 24 平均分为一分钟内的纳秒数。使用其他数量的零件,您可以决定是否值得担心轻微的不准确。如果是,对于每个分区时间先乘后除。
我想生成两个给定 date/time 之间的间隔。
例如,对于 24 小时格式 (HH:MM)
,我有这两个端点,00:00 和 11:51,假设我想将它分成 24 块。所以我的计算是这样的:
(hour * 3600 + min * 60) / 24
如果我使用 calendar.add(Calendar.SECOND, (hour * 3600 + min * 60) / 24)
,我就错了 dates/time。我的计算是双倍的,我认为 calendar.add()
不支持双倍。就像把 28.883 当作 29 一样。
本质上我想要这样的东西:
now : 15:57
today start : 00:00 (24hh)
output : 00:00, 00:47.85, …, 15:57
您需要将开始日期保存在日历对象中,然后在生成每个分区时使用公式:
startCalendar.add(Calendar.Second, count * (hour * 3600 + min * 60) / 24))
这样,除以 24(或其他)得到的算术错误就不会累积。
您的代码的实际问题是您正在执行整数除法。我假设 hour
和 min
都被定义为整数类型。公式 (hour * 3600 + min * 60) / 24
始终生成整数类型。如果将代码更改为 (hour * 3600 + min * 60) / 24d
,表达式至少会产生一个浮点值。
下一个问题确实是 Calendar.add(int field, int amount)
只接受一个整数作为第二个参数。当然,如果您将 Calendar.SECOND
作为第一个参数传递,那么您的精度不会高于秒。您可以使用 Calendar.MILLISECOND
以获得更高的精度。
但是,我建议使用新的 Java 日期和时间 API,而不是 troublesome 旧的 API :
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
long span = Duration.between(startTime, endTime).toNanos();
final int n = 23; // Number of pieces
LongStream.rangeClosed(0, n)
.map(i -> i * span / n)
.mapToObj(i -> startTime.plusNanos(i))
.forEach(System.out::println);
这是 Duration
有我们可以利用的方法 dividedBy
和 multipliedBy
。
LocalTime startTime = LocalTime.of(0, 0);
LocalTime endTime = LocalTime.of(11, 51);
final int n = 24; // Number of pieces
Duration piece = Duration.between(startTime, endTime).dividedBy(n);
LocalTime[] partitionTimes = IntStream.rangeClosed(0, n)
.mapToObj(i -> startTime.plus(piece.multipliedBy(i)))
.toArray(LocalTime[]::new);
System.out.println(Arrays.toString(partitionTimes));
输出:
[00:00, 00:29:37.500, 00:59:15, 01:28:52.500, 01:58:30, 02:28:07.500, 02:57:45, 03:27:22.500, 03:57, 04:26:37.500, 04:56:15, 05:25:52.500, 05:55:30, 06:25:07.500, 06:54:45, 07:24:22.500, 07:54, 08:23:37.500, 08:53:15, 09:22:52.500, 09:52:30, 10:22:07.500, 10:51:45, 11:21:22.500, 11:51]
是否存在四舍五入的问题?以整分钟为单位的开始时间和 24 件不会有,因为 24 平均分为一分钟内的纳秒数。使用其他数量的零件,您可以决定是否值得担心轻微的不准确。如果是,对于每个分区时间先乘后除。