Aaron的回答很好,但它忽略了输入中可能存在的秒数或分数秒。此外,我可以更详细地展开,并应用时区。
截断
您可以截断LocalDateTime
对象,以在增加小时数时消除任何整个或分数秒。
LocalDateTime ldtTruncated = ldt.truncatedTo( ChronoUnit.MINUTES ); // Lop off seconds and nanoseconds.
…或者…
LocalDateTime ldtTruncated = ldt.truncatedTo( ChronoUnit.HOURS ); // Lop off minutes, seconds, and nanoseconds.
时区
一个关键问题是时区。这些值缺乏任何与UTC偏移量或时区的指示器。因此,正如Aaron所正确展示的那样,我们应该最初将它们解析为LocalDateTime
。
LocalDateTime ldtStart = LocalDateTime.parse ( "2017-03-07 06:30:00".replace ( " " , "T" ) );
LocalDateTime ldtStop = LocalDateTime.parse ( "2017-03-07 11:35:00".replace ( " " , "T" ) );
但从问题的措辞中可以看出,我们希望处理特定的时刻。根据定义,
LocalDateTime
并不是一个具体的时刻,而只是潜在时刻的模糊想法。您必须添加时区(或偏移量)的上下文来确定实际时刻。因此,如果您知道这些值所代表的时区,请应用它。
ZonedDateTime
类会针对由于异常情况(如
夏令时 (DST))而无效的输入值进行调整。
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdtStart = ldtStart.atZone ( z );
ZonedDateTime zdtStop = ldtStop.atZone ( z );
确保输入内容合理。
if ( zdtStop.isBefore ( zdtStart ) ) {
System.out.println ( "ERROR - stop is befor start." );
return;
}
日期时间范围作为一对ZonedDateTime
对象
现在我们可以逐小时增加以生成所需的范围。我们可以使用来自ThreeTen-Extra项目的Interval
类(见下文),该类跟踪始终处于UTC的一对Instant
对象。但是,这对我们可能没有用处,因为我们真正想要处理时区小时(或者我这样认为)。因此,让我们将每个日期时间范围作为一对ZonedDateTime
类进行跟踪。我们可以为这对创建自己的类,但是相反,我们重新利用AbstractMap.SimpleImmutableEntry类。该类将一对对象作为键和值进行跟踪。
不要让那个配对类的名称让你困惑。该类最初的意图是与一个
Map
一起使用,但它本身不是一个地图。该类的目的是引用来自
Map
的键和值,但我们将以其“键”作为起始时刻,“值”作为停止时刻的方式使用它。我们将每个计算出的时间范围收集到一个
List
类型的
AbstractMap.SimpleImmutableEntry
中。
int initialCapacity = ( ( int ) ChronoUnit.HOURS.between ( zdtStart , zdtStop ) ) + 2;
List<AbstractMap.SimpleImmutableEntry<ZonedDateTime , ZonedDateTime>> ranges = new ArrayList<> ( initialCapacity );
设置循环的起始值并进行循环。在每次循环中,我们希望将值截断为整点(以去除秒和小数秒)。在截断后,我们再加上一个小时以到达下一个小时。我们只需要在第一次循环时进行截断,因此您可以重新编写此代码以更高效地避免在连续循环中不必要的截断。除非您正在处理非常大量的小时,否则我不会费心。
ZonedDateTime zdt = zdtStart;
while ( zdt.isBefore ( zdtStop ) ) {
ZonedDateTime zdt2 = zdt.truncatedTo ( ChronoUnit.HOURS ).plusHours ( 1 );
if ( zdt2.isAfter ( zdtStop ) ) {
zdt2 = zdtStop;
}
AbstractMap.SimpleImmutableEntry<ZonedDateTime , ZonedDateTime> range = new AbstractMap.SimpleImmutableEntry<> ( zdt , zdt2 );
ranges.add ( range );
zdt = zdt2;
}
将内容输出到控制台。
System.out.println ( "ldtStart/ldtStop: " + ldtStart + "/" + ldtStop );
System.out.println ( "zdtStart/zdtStop: " + zdtStart + "/" + zdtStart );
System.out.println ( "ranges: " + ranges );
当运行时。
ldtStart/ldtStop: 2017年3月7日06:30至2017年3月7日11:35
zdtStart/zdtStop: 2017年3月7日06:30-05:00[美国蒙特利尔]/2017年3月7日06:30-05:00[美国蒙特利尔]
ranges: [2017年3月7日06:30-05:00[美国蒙特利尔]=2017年3月7日07:00-05:00[美国蒙特利尔],2017年3月7日07:00-05:00[美国蒙特利尔]=2017年3月7日08:00-05:00[美国蒙特利尔],2017年3月7日08:00-05:00[美国蒙特利尔]=2017年3月7日09:00-05:00[美国蒙特利尔],2017年3月7日09:00-05:00[美国蒙特利尔]=2017年3月7日10:00-05:00[美国蒙特利尔],2017年3月7日10:00-05:00[美国蒙特利尔]=2017年3月7日11:00-05:00[美国蒙特利尔],2017年3月7日11:00-05:00[美国蒙特利尔]=2017年3月7日11:35-05:00[美国蒙特利尔]]
关于 java.time
java.time 框架是内置于 Java 8 及更高版本中的。这些类取代了令人头痛的旧的传统日期时间类,例如java.util.Date
、Calendar
和SimpleDateFormat
。
Joda-Time 项目现在处于维护模式,建议迁移到java.time 类。
要了解更多,请参见
Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是
JSR 310。
从哪里获取java.time类?
ThreeTen-Extra 项目扩展了 java.time 的额外类。该项目是 java.time 可能未来添加的试验场。您可能会在这里找到一些有用的类,例如 Interval
, YearWeek
, YearQuarter
和 更多。