根据 LocalDateTime 对象列表和带流的已占用时隙列表创建可用时隙列表
Creating a list of avalible Timeslots based on a list LocalDateTime objects and a List of taken Timeslots with Streams
我有一个 List<Timeslot>
,其中包含具有以下字段的实体 Timeslot
:
timeslot_id
;
day
;
start_time
;
end_time
.
例如,这个列表包含两条记录:
第一条记录的start_time
等于9:00
,end_time
等于10:00
.
第二个对象的 start_time
等于 10:00
并且 end_time
等于 11:00
.
第二个列表包含时间戳List<LocalDateTime>
:
[2022-04-16T08:00, 2022-04-16T09:00, 2022-04-16T10:00, 2022-04-16T11:00,
2022-04-16T12:00, 2022-04-16T13:00, 2022-04-16T14:00, 2022-04-16T15:00]
我需要创建第三个 List<Timeslot>
,它将包含 Timeslot
,除了第一个列表中的这两个。
在这种情况下,因此,第三个列表应该包含 Timeslot
class.
的六个对象
start_time
第一个应该等于 2022-04-16T08:00
和 end_time 2022-04-16T09:00
。 IE。 start_time
和 end_time
之间每隔 时间段 的差异是 一个小时 .
因此,根据上面提供的 timestamps 列表构造的 result 应该包含六个对象:
start_time
是 8:00
,end_time
是 9:00
。
start_time
是 11:00
,end_time
是 12:00
。
start_time
是12:00
,end_time
是13:00
...等等。
我 start_time
9:00
和 10:00
的对象不会出现在第三个列表中,因为它们已经被预订了(出现在第一个列表中).
我尝试使用 Java 流创建 第三个列表 ,它应该将字段 start_time
和 end_time
与来自 第二个列表.
我试过了,但结果列表总是空的:
List<Timeslot> availableSlots = query.stream()
.filter(timeslot -> timestamps.contains(timeslot.getStartTime()))
.toList();
时间段 class:
@Entity(name = "timeslot")
public class Timeslot {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "timeslot_id")
private Integer id;
@Column(name = "day", columnDefinition = "DATE")
private LocalDateTime day;
@Column(name = "start_time")
private LocalDateTime startTime;
@Column(name = "end_time")
private LocalDateTime endTime;
@Column(name = "user_id")
private Integer userId;
@Column(name = "is_recorded")
private Boolean isRecorded;
}
我已针对此问题简化了您的 Timeslot
class(用于演示目的),因为对于此任务,您主要关注 每个时间段的开始时间和结束时间。
我的方法是通过从已经存在的每个 timeslot 中提取 start time 来创建一组 LocalDateTime
对象采取(由您的第一个列表表示)。
然后在 query
列表上创建一个流并过滤集合中不存在的 date-time 对象。然后使用每个 date-time 对象创建一个 timeslot 作为 start time (end time = 开始时间 + 1 小时)。并将所有流元素收集到一个 list.
注意:终端操作toList()
创建一个不可变列表,您可以通过应用collect(Collectors.toList())
代替获得可变列表。
public static void main(String[] args) {
List<LocalDateTime> query =
List.of(LocalDateTime.of(2022, 04, 16, 8, 00),
LocalDateTime.of(2022, 04, 16, 9, 00),
LocalDateTime.of(2022, 04, 16, 10, 00),
LocalDateTime.of(2022, 04, 16, 11, 00),
LocalDateTime.of(2022, 04, 16, 12, 00),
LocalDateTime.of(2022, 04, 16, 13, 00),
LocalDateTime.of(2022, 04, 16, 14, 00),
LocalDateTime.of(2022, 04, 16, 15, 00));
List<Timeslot> timeslots = // timeslots that already taken
List.of(new Timeslot(LocalDateTime.of(2022, 04, 16, 9, 00),
LocalDateTime.of(2022, 04, 16, 10, 00)),
new Timeslot(LocalDateTime.of(2022, 04, 16, 10, 00),
LocalDateTime.of(2022, 04, 16, 11, 00)));
Set<LocalDateTime> takenStartTime = timeslots.stream()
.map(Timeslot::getStartTime)
.collect(Collectors.toSet());
List<Timeslot> availableSlots = query.stream()
.filter(dateTime -> !takenStartTime.contains(dateTime))
.map(dateTime -> new Timeslot(dateTime, dateTime.plusHours(1)))
.toList();
availableSlots.forEach(System.out::println);
}
简化虚拟Timeslot
class
public class Timeslot {
private LocalDateTime startTime;
private LocalDateTime endTime;
// constructor, getters, toString()
}
输出
Timeslot{start_time=2022-04-16T08:00, end_time=2022-04-16T09:00}
Timeslot{start_time=2022-04-16T11:00, end_time=2022-04-16T12:00}
Timeslot{start_time=2022-04-16T12:00, end_time=2022-04-16T13:00}
Timeslot{start_time=2022-04-16T13:00, end_time=2022-04-16T14:00}
Timeslot{start_time=2022-04-16T14:00, end_time=2022-04-16T15:00}
Timeslot{start_time=2022-04-16T15:00, end_time=2022-04-16T16:00}
非常好。这里有一个替代方案,作为思考的食物。
顺便说一下,您的 day
字段是多余的。您从 LocalDateTime
开始就知道日期和 date-time。我建议从您的模型中删除它。
添加TimeSlot#contains
方法
让我们将您的 TimeSlot
class 更简单地定义为 record。我将使用 UUID
作为标识符,而不是 fiddle 计数整数。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end ) {}
诀窍是添加一个 contains
方法,告诉调用者特定的 LocalDateTime
是否恰好位于我们的时间段范围内。我们使用 Half-Open 方法,其中时间跨度定义为开始 inclusive 而结束 exclusive.
请注意,“不早于”是“等于或晚于”的缩写。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end )
{
boolean contains ( LocalDateTime localDateTime )
{
return ( ( ! localDateTime.isBefore( this.start ) ) && localDateTime.isBefore( this.end ) );
}
}
示例数据。
List < TimeSlot > timeslots =
List.of(
new TimeSlot(
UUID.fromString( "0500ce28-ad96-43d0-9b3d-b907cadd27f9" ) ,
LocalDateTime.of( 2022 , 04 , 16 , 9 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 )
) ,
new TimeSlot(
UUID.fromString( "887d72df-4787-4974-ab6d-f2a46cb7d7af" ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 11 , 00 )
)
);
和一些示例输入。
List < LocalDateTime > inputs =
List.of(
LocalDateTime.of( 2022 , 04 , 16 , 8 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 9 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 11 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 12 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 13 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 14 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 15 , 00 )
);
创建一个包含 TimeSlot
个对象的新列表,跳过我们现有的 TimeSlot
个对象所花费的时间跨度。
List < TimeSlot > resultingTimeSlots = new ArrayList <>( inputs.size() );
循环输入 LocalDateTime
个对象。对于每个,询问每个原始时隙是否恰好包含该 date-time 值。如果是这样,请将找到的时间段添加到我们的列表中。如果不是,则使用输入 LocalDateTime
作为开始创建一个新的 TimeSlot
对象,并假设结束应该在一个小时后。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
resultingTimeSlots.add( hit.orElse( new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ) );
}
该代码可以优化。使用 Optional#orElse
实际上是在 for
的每个循环上执行 new TimeSlot
,无论是否需要。
我们可以通过向我们的记录添加一个紧凑的构造函数来验证此行为。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end )
{
TimeSlot
{
System.out.println( "running constructor for " + id );
}
boolean contains ( LocalDateTime localDateTime )
{
return ( ( ! localDateTime.isBefore( start ) ) && localDateTime.isBefore( end ) );
}
}
让我们用 Optional#orElseGet
替换它,同时将我们的 new TimeSlot
转换为实现所需 Supplier
接口的 lambda。这个变化意味着一个新的 TimeSlot
对象只有在我们真正需要它时才会被实例化。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
resultingTimeSlots.add( hit.orElseGet( ( ) -> new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ) );
}
转储到控制台。
System.out.println( "resultingTimeSlots.size(): " + resultingTimeSlots.size() );
System.out.println( "resultingTimeSlots.containsAll( timeslots ): " + resultingTimeSlots.containsAll( timeslots ) );
System.out.println( resultingTimeSlots );
当运行.
running constructor for 0500ce28-ad96-43d0-9b3d-b907cadd27f9
running constructor for 887d72df-4787-4974-ab6d-f2a46cb7d7af
running constructor for ce2b9c66-ef69-4ecd-a451-7a51ebbb259e
running constructor for c77cf83f-5ea8-4da3-9a44-104a56f4de03
running constructor for 139280b6-20c4-4428-b2cb-80717a00756b
running constructor for 1d219e16-0513-466e-9b84-091312e4ff5e
running constructor for 4b0b6c11-c6ae-4e04-a8fe-6c1245f7e80b
running constructor for 1ccdbd7f-ff4c-4d7d-b900-54d14898a50f
resultingTimeSlots.size(): 8
resultingTimeSlots.containsAll( timeslots ): true
[TimeSlot[id=ce2b9c66-ef69-4ecd-a451-7a51ebbb259e, start=2022-04-16T08:00, end=2022-04-16T09:00], TimeSlot[id=0500ce28-ad96-43d0-9b3d-b907cadd27f9, start=2022-04-16T09:00, end=2022-04-16T10:00], TimeSlot[id=887d72df-4787-4974-ab6d-f2a46cb7d7af, start=2022-04-16T10:00, end=2022-04-16T11:00], TimeSlot[id=c77cf83f-5ea8-4da3-9a44-104a56f4de03, start=2022-04-16T11:00, end=2022-04-16T12:00], TimeSlot[id=139280b6-20c4-4428-b2cb-80717a00756b, start=2022-04-16T12:00, end=2022-04-16T13:00], TimeSlot[id=1d219e16-0513-466e-9b84-091312e4ff5e, start=2022-04-16T13:00, end=2022-04-16T14:00], TimeSlot[id=4b0b6c11-c6ae-4e04-a8fe-6c1245f7e80b, start=2022-04-16T14:00, end=2022-04-16T15:00], TimeSlot[id=1ccdbd7f-ff4c-4d7d-b900-54d14898a50f, start=2022-04-16T15:00, end=2022-04-16T16:00]]
如果您想跳过原始项目,请将 for
循环更改为此。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
if ( hit.isEmpty() ) { resultingTimeSlots.add( new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ); }
}
跟踪约会
如果你想做一个未来的约会跟踪应用程序,你的方法是错误的。
您应该只跟踪 LocalDateTime
的开始,而不是结束。不是结束,而是将约会的长度跟踪为 Duration
对象。至关重要的是,为时区 (ZoneId
) 添加一个字段作为此日期和时间的预期上下文。
要理解的概念是政治时间与自然时间不同。天不一定是 24 小时。它们可能是 23、23.5、25 或其他小时数。因此,1 小时的约会可能从 2 点开始,但在 4 点结束。
当您需要构建时刻表、时间轴上的特定点时,将时区应用到开始。并在结尾添加持续时间。
ZonedDateTime start = startLocalDateTime.atZone( storedZoneId ) ;
ZonedDateTime end = start.plus( storedDuration ) ;
但是从不存储这些ZonedDateTime
对象。如果政治家改变其管辖范围内的时区规则,它们将变得无效。世界各地的政治家以惊人的频率这样做。
我和其他人在 Stack Overflow 上多次写过这个主题。所以搜索以了解更多信息。
我有一个 List<Timeslot>
,其中包含具有以下字段的实体 Timeslot
:
timeslot_id
;day
;start_time
;end_time
.
例如,这个列表包含两条记录:
-
第一条记录的
start_time
等于9:00
,end_time
等于10:00
.
第二个对象的 start_time
等于10:00
并且end_time
等于11:00
.
第二个列表包含时间戳List<LocalDateTime>
:
[2022-04-16T08:00, 2022-04-16T09:00, 2022-04-16T10:00, 2022-04-16T11:00,
2022-04-16T12:00, 2022-04-16T13:00, 2022-04-16T14:00, 2022-04-16T15:00]
我需要创建第三个 List<Timeslot>
,它将包含 Timeslot
,除了第一个列表中的这两个。
在这种情况下,因此,第三个列表应该包含 Timeslot
class.
start_time
第一个应该等于 2022-04-16T08:00
和 end_time 2022-04-16T09:00
。 IE。 start_time
和 end_time
之间每隔 时间段 的差异是 一个小时 .
因此,根据上面提供的 timestamps 列表构造的 result 应该包含六个对象:
start_time
是8:00
,end_time
是9:00
。start_time
是11:00
,end_time
是12:00
。start_time
是12:00
,end_time
是13:00
...等等。
我 start_time
9:00
和 10:00
的对象不会出现在第三个列表中,因为它们已经被预订了(出现在第一个列表中).
我尝试使用 Java 流创建 第三个列表 ,它应该将字段 start_time
和 end_time
与来自 第二个列表.
我试过了,但结果列表总是空的:
List<Timeslot> availableSlots = query.stream()
.filter(timeslot -> timestamps.contains(timeslot.getStartTime()))
.toList();
时间段 class:
@Entity(name = "timeslot")
public class Timeslot {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "timeslot_id")
private Integer id;
@Column(name = "day", columnDefinition = "DATE")
private LocalDateTime day;
@Column(name = "start_time")
private LocalDateTime startTime;
@Column(name = "end_time")
private LocalDateTime endTime;
@Column(name = "user_id")
private Integer userId;
@Column(name = "is_recorded")
private Boolean isRecorded;
}
我已针对此问题简化了您的 Timeslot
class(用于演示目的),因为对于此任务,您主要关注 每个时间段的开始时间和结束时间。
我的方法是通过从已经存在的每个 timeslot 中提取 start time 来创建一组 LocalDateTime
对象采取(由您的第一个列表表示)。
然后在 query
列表上创建一个流并过滤集合中不存在的 date-time 对象。然后使用每个 date-time 对象创建一个 timeslot 作为 start time (end time = 开始时间 + 1 小时)。并将所有流元素收集到一个 list.
注意:终端操作toList()
创建一个不可变列表,您可以通过应用collect(Collectors.toList())
代替获得可变列表。
public static void main(String[] args) {
List<LocalDateTime> query =
List.of(LocalDateTime.of(2022, 04, 16, 8, 00),
LocalDateTime.of(2022, 04, 16, 9, 00),
LocalDateTime.of(2022, 04, 16, 10, 00),
LocalDateTime.of(2022, 04, 16, 11, 00),
LocalDateTime.of(2022, 04, 16, 12, 00),
LocalDateTime.of(2022, 04, 16, 13, 00),
LocalDateTime.of(2022, 04, 16, 14, 00),
LocalDateTime.of(2022, 04, 16, 15, 00));
List<Timeslot> timeslots = // timeslots that already taken
List.of(new Timeslot(LocalDateTime.of(2022, 04, 16, 9, 00),
LocalDateTime.of(2022, 04, 16, 10, 00)),
new Timeslot(LocalDateTime.of(2022, 04, 16, 10, 00),
LocalDateTime.of(2022, 04, 16, 11, 00)));
Set<LocalDateTime> takenStartTime = timeslots.stream()
.map(Timeslot::getStartTime)
.collect(Collectors.toSet());
List<Timeslot> availableSlots = query.stream()
.filter(dateTime -> !takenStartTime.contains(dateTime))
.map(dateTime -> new Timeslot(dateTime, dateTime.plusHours(1)))
.toList();
availableSlots.forEach(System.out::println);
}
简化虚拟Timeslot
class
public class Timeslot {
private LocalDateTime startTime;
private LocalDateTime endTime;
// constructor, getters, toString()
}
输出
Timeslot{start_time=2022-04-16T08:00, end_time=2022-04-16T09:00}
Timeslot{start_time=2022-04-16T11:00, end_time=2022-04-16T12:00}
Timeslot{start_time=2022-04-16T12:00, end_time=2022-04-16T13:00}
Timeslot{start_time=2022-04-16T13:00, end_time=2022-04-16T14:00}
Timeslot{start_time=2022-04-16T14:00, end_time=2022-04-16T15:00}
Timeslot{start_time=2022-04-16T15:00, end_time=2022-04-16T16:00}
顺便说一下,您的 day
字段是多余的。您从 LocalDateTime
开始就知道日期和 date-time。我建议从您的模型中删除它。
添加TimeSlot#contains
方法
让我们将您的 TimeSlot
class 更简单地定义为 record。我将使用 UUID
作为标识符,而不是 fiddle 计数整数。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end ) {}
诀窍是添加一个 contains
方法,告诉调用者特定的 LocalDateTime
是否恰好位于我们的时间段范围内。我们使用 Half-Open 方法,其中时间跨度定义为开始 inclusive 而结束 exclusive.
请注意,“不早于”是“等于或晚于”的缩写。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end )
{
boolean contains ( LocalDateTime localDateTime )
{
return ( ( ! localDateTime.isBefore( this.start ) ) && localDateTime.isBefore( this.end ) );
}
}
示例数据。
List < TimeSlot > timeslots =
List.of(
new TimeSlot(
UUID.fromString( "0500ce28-ad96-43d0-9b3d-b907cadd27f9" ) ,
LocalDateTime.of( 2022 , 04 , 16 , 9 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 )
) ,
new TimeSlot(
UUID.fromString( "887d72df-4787-4974-ab6d-f2a46cb7d7af" ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 11 , 00 )
)
);
和一些示例输入。
List < LocalDateTime > inputs =
List.of(
LocalDateTime.of( 2022 , 04 , 16 , 8 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 9 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 10 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 11 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 12 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 13 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 14 , 00 ) ,
LocalDateTime.of( 2022 , 04 , 16 , 15 , 00 )
);
创建一个包含 TimeSlot
个对象的新列表,跳过我们现有的 TimeSlot
个对象所花费的时间跨度。
List < TimeSlot > resultingTimeSlots = new ArrayList <>( inputs.size() );
循环输入 LocalDateTime
个对象。对于每个,询问每个原始时隙是否恰好包含该 date-time 值。如果是这样,请将找到的时间段添加到我们的列表中。如果不是,则使用输入 LocalDateTime
作为开始创建一个新的 TimeSlot
对象,并假设结束应该在一个小时后。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
resultingTimeSlots.add( hit.orElse( new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ) );
}
该代码可以优化。使用 Optional#orElse
实际上是在 for
的每个循环上执行 new TimeSlot
,无论是否需要。
我们可以通过向我们的记录添加一个紧凑的构造函数来验证此行为。
record TimeSlot( UUID id , LocalDateTime start , LocalDateTime end )
{
TimeSlot
{
System.out.println( "running constructor for " + id );
}
boolean contains ( LocalDateTime localDateTime )
{
return ( ( ! localDateTime.isBefore( start ) ) && localDateTime.isBefore( end ) );
}
}
让我们用 Optional#orElseGet
替换它,同时将我们的 new TimeSlot
转换为实现所需 Supplier
接口的 lambda。这个变化意味着一个新的 TimeSlot
对象只有在我们真正需要它时才会被实例化。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
resultingTimeSlots.add( hit.orElseGet( ( ) -> new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ) );
}
转储到控制台。
System.out.println( "resultingTimeSlots.size(): " + resultingTimeSlots.size() );
System.out.println( "resultingTimeSlots.containsAll( timeslots ): " + resultingTimeSlots.containsAll( timeslots ) );
System.out.println( resultingTimeSlots );
当运行.
running constructor for 0500ce28-ad96-43d0-9b3d-b907cadd27f9
running constructor for 887d72df-4787-4974-ab6d-f2a46cb7d7af
running constructor for ce2b9c66-ef69-4ecd-a451-7a51ebbb259e
running constructor for c77cf83f-5ea8-4da3-9a44-104a56f4de03
running constructor for 139280b6-20c4-4428-b2cb-80717a00756b
running constructor for 1d219e16-0513-466e-9b84-091312e4ff5e
running constructor for 4b0b6c11-c6ae-4e04-a8fe-6c1245f7e80b
running constructor for 1ccdbd7f-ff4c-4d7d-b900-54d14898a50f
resultingTimeSlots.size(): 8
resultingTimeSlots.containsAll( timeslots ): true
[TimeSlot[id=ce2b9c66-ef69-4ecd-a451-7a51ebbb259e, start=2022-04-16T08:00, end=2022-04-16T09:00], TimeSlot[id=0500ce28-ad96-43d0-9b3d-b907cadd27f9, start=2022-04-16T09:00, end=2022-04-16T10:00], TimeSlot[id=887d72df-4787-4974-ab6d-f2a46cb7d7af, start=2022-04-16T10:00, end=2022-04-16T11:00], TimeSlot[id=c77cf83f-5ea8-4da3-9a44-104a56f4de03, start=2022-04-16T11:00, end=2022-04-16T12:00], TimeSlot[id=139280b6-20c4-4428-b2cb-80717a00756b, start=2022-04-16T12:00, end=2022-04-16T13:00], TimeSlot[id=1d219e16-0513-466e-9b84-091312e4ff5e, start=2022-04-16T13:00, end=2022-04-16T14:00], TimeSlot[id=4b0b6c11-c6ae-4e04-a8fe-6c1245f7e80b, start=2022-04-16T14:00, end=2022-04-16T15:00], TimeSlot[id=1ccdbd7f-ff4c-4d7d-b900-54d14898a50f, start=2022-04-16T15:00, end=2022-04-16T16:00]]
如果您想跳过原始项目,请将 for
循环更改为此。
for ( LocalDateTime input : inputs )
{
Optional < TimeSlot > hit = timeslots.stream().filter( timeSlot -> timeSlot.contains( input ) ).findAny();
if ( hit.isEmpty() ) { resultingTimeSlots.add( new TimeSlot( UUID.randomUUID() , input , input.plusHours( 1 ) ) ); }
}
跟踪约会
如果你想做一个未来的约会跟踪应用程序,你的方法是错误的。
您应该只跟踪 LocalDateTime
的开始,而不是结束。不是结束,而是将约会的长度跟踪为 Duration
对象。至关重要的是,为时区 (ZoneId
) 添加一个字段作为此日期和时间的预期上下文。
要理解的概念是政治时间与自然时间不同。天不一定是 24 小时。它们可能是 23、23.5、25 或其他小时数。因此,1 小时的约会可能从 2 点开始,但在 4 点结束。
当您需要构建时刻表、时间轴上的特定点时,将时区应用到开始。并在结尾添加持续时间。
ZonedDateTime start = startLocalDateTime.atZone( storedZoneId ) ;
ZonedDateTime end = start.plus( storedDuration ) ;
但是从不存储这些ZonedDateTime
对象。如果政治家改变其管辖范围内的时区规则,它们将变得无效。世界各地的政治家以惊人的频率这样做。
我和其他人在 Stack Overflow 上多次写过这个主题。所以搜索以了解更多信息。