1

我想实现此代码来检查用户是否订阅了服务:

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";
  }

在数据库中,我存储 2 个字段:

@Column(name = "start_at")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime startAt;

@Column(name = "end_at")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime endAt;

我需要检查now变量是否在时间间隔startAtendAt.

这个检查如何在 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);
    }
}
4

4 回答 4

5

两点:

  1. 不要LocalDateTime在某个时间点使用。任何阅读它的人都可以在他们能想到的任何时区自由地解释它,24 到 26 小时的不同解释。Instant是用于某个时间点的类。它有isBeforeisAfter方法一样LocalDateTime的,所以代码不会有什么不同。也确实定义了时间点的替代方案包括ZonedDateTimeOffsetDateTime
  2. WithOptional不要使用它的isPresentandget方法(在极少数情况下除外)。它们是低级的,到目前为止,我们通常可以使用高级方法获得更优雅的代码。

我更喜欢使用 的方法链接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");
}

这适用于 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可能弊大于利。无论如何,没有链条比其最薄弱的环节更强大。所以在这种情况下,坚持使用LocalDateTimeJava。然后以这种方式读取时钟:

    ZoneId timeZoneThatTheDatabaseAssumes = ZoneId.of("Europe/Gibraltar");
    LocalDateTime now = LocalDateTime.now(timeZoneThatTheDatabaseAssumes);

当然,为您的数据库使用的时区指定时区 ID。

于 2021-06-28T04:22:10.873 回答
3

您可以使用LocalDateTime#isAfterLocalDateTime#isBefore如下所示:

if (now.isAfter(startAt) && now.isBefore(endAt)) { .... }
于 2021-06-27T14:14:42.360 回答
2

这取决于要求。@dariosicily 有一点,但如果年表或日历系统对您的应用程序很重要,那么建议使用compareTo

  LocalDateTime startAt = subscription.getStartAt();
  LocalDateTime endAt = subscription.getEndAt();
  LocalDateTime now = LocalDateTime.now();

  if(now.compareTo(startAt) == 1 && now.compareTo(endAt) == -1){
    return "subscribed";
  }
于 2021-06-27T14:28:14.860 回答
2

你必须检查它now是 beetweenstartDateendDate

public String calculateSubscription(String email) { 
    Optional<Subscription> subscriptionsByUserEmail = subscriptionService.findSubscriptionsByUserEmail(email);

    String result = "unsubscribed";
    if(subscriptionsByUserEmail.isPresent()){
        Subscription subscription = subscriptionsByUserEmail.get();

        LocalDateTime startAt = subscription.getStartAt();
        LocalDateTime endAt = subscription.getEndAt();
        LocalDateTime now = LocalDateTime.now();

        if (startAt.isBefore(now) && endAt.isAfter(now)) {
            result = "subscribed";
        }
    }
    return result;
}
于 2021-06-27T14:28:37.993 回答