Pet*_*zov 1 java date-range localdatetime
我想实现此代码以检查用户是否订阅了服务:
public String calculateSubscription(String email) {
Optional<Subscription> subscriptionsByUserEmail = subscriptionService.findSubscriptionsByUserEmail(email);
if (subscriptionsByUserEmail.isPresent()) {
Subscription subscription = subscriptionsByUserEmail.get();
LocalDateTime startAt = subscription.getStartAt();
LocalDateTime endAt = subscription.getEndAt();
LocalDateTime now = LocalDateTime.now();
if(/* do here comparison */){
return "subscribed";
}
}
return "unsubscribed";
}
Run Code Online (Sandbox Code Playgroud)
到数据库中,我存储了 2 个字段:
@Column(name = "start_at")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime startAt;
@Column(name = "end_at")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime endAt;
Run Code Online (Sandbox Code Playgroud)
我需要检查now时间间隔startAt和endAt.
这个检查如何实现到 if 语句中?
编辑:
@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
@Override
public Timestamp convertToDatabaseColumn(LocalDateTime localDateTime) {
return Optional.ofNullable(localDateTime)
.map(Timestamp::valueOf)
.orElse(null);
}
@Override
public LocalDateTime convertToEntityAttribute(Timestamp timestamp) {
return Optional.ofNullable(timestamp)
.map(Timestamp::toLocalDateTime)
.orElse(null);
}
}
Run Code Online (Sandbox Code Playgroud)
两点:
LocalDateTime在某个时间点使用。任何阅读它的人都可以在他们能想到的任何时区自由地解释它,对于 24 到 26 小时的不同解释。Instant是用于某个时间点的类。它isBefore和isAfter方法一样LocalDateTime,所以代码不会有什么不同。也确实定义了时间点的替代方案包括ZonedDateTime和OffsetDateTime。Optional不使用它isPresent和get方法(除了在极少数情况下)。它们是低级的,到目前为止,我们可以通过高级方法获得更优雅的代码。我更喜欢用 方法链接Optional,所以我的代码看起来像:
public String calculateSubscription(String email) {
Instant now = Instant.now();
return subscriptionService.findSubscriptionsByUserEmail(email)
.filter(sub -> ! sub.getStartAt().isAfter(now) && sub.getEndAt().isAfter(now))
.map(sub -> "subscribed")
.orElse("unsubscribed");
}
Run Code Online (Sandbox Code Playgroud)
这适用于 ifgetStartAt()和getEndAt()return Instant。为了在极端情况下获得一致的结果,我只读取了一次时钟(在过滤条件下不是两次)。时间间隔的标准解释是半开放的,从开始包含到结束不包含,所以我的代码使用它。我使用“not after”来表示“on or before”。在您的情况下,您可能不需要这种精度。
为了将时间点存储到您的数据库中,对于大多数数据库引擎,您需要一个timestamp with time zone.
编辑:详细说明一下,aLocalDateTime给我们的日期和时间,不要建立一个时间点。例如,东京的 6 月 30 日 11:45 比洛杉矶的 6 月 30 日 11:45 早 16 小时。因此,对于某个时间点,我们还需要时区或 UTC 偏移量。
如果您的数据库可以提供一个时间点,通常是通过timestamp with time zone前面提到的,我们很高兴。究竟如何将它检索到 Java 中取决于您的 JPA 版本和实现,所以我不想在这一点上具体说明。您可能需要也可能不需要使用OffsetDateTime(或什至ZonedDateTime)而不是Instant在 Java 中,或者提供与您现在使用的不同的自定义转换器。后者可能很容易使用Timestamp::toInstant而不是Timestamp::toLocalDateTime.
如果您的数据库只给您日期和时间,例如,如果它使用其datetime数据类型并且无法更改,请不要尝试假装。在这种情况下,坚持转换为Instant可能弊大于利。无论如何,没有任何链条比其最薄弱的环节更坚固。所以在这种情况下坚持LocalDateTime在 Java 中。然后以这种方式读取时钟:
ZoneId timeZoneThatTheDatabaseAssumes = ZoneId.of("Europe/Gibraltar");
LocalDateTime now = LocalDateTime.now(timeZoneThatTheDatabaseAssumes);
Run Code Online (Sandbox Code Playgroud)
当然,请为您的数据库使用的时区指定时区 ID。