Chcę zaimplementować ten kod, aby sprawdzić, czy użytkownik jest subskrybowany do usługi:

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

W bazie przechowuję 2 pola:

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

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

Muszę sprawdzić, czy zmienna now jest dopasowana między przedziałem czasu startAt a endAt. Jak mogę zaimplementować to sprawdzenie w instrukcji if?

EDIT:

@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);
    }
}
1
Peter Penzov 27 czerwiec 2021, 16:52

4 odpowiedzi

Najlepsza odpowiedź

Dwa punkty:

  1. Nie używaj LocalDateTime przez pewien czas. Każdy, kto go przeczyta, będzie mógł zinterpretować go w dowolnej strefie czasowej, o której może pomyśleć, w przypadku interpretacji trwającej od 24 do 26 godzin. Instant to klasa do użycia przez określony czas. Ma metody isBefore i isAfter, podobnie jak LocalDateTime, więc kod nie będzie inny. Alternatywy, które również definiują punkt w czasie, obejmują ZonedDateTime i OffsetDateTime.
  2. Z Optional nie używaj jego metod isPresent i get (z wyjątkiem rzadkich przypadków). Są niskopoziomowe i zdecydowanie najczęściej możemy uzyskać bardziej elegancki kod metodami wyższego poziomu.

Jestem raczej w łańcuchu metod z Optional, więc mój kod będzie wyglądał tak:

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

Działa to, jeśli getStartAt() i getEndAt() zwracają Instant. Aby uzyskać spójne wyniki w przypadkach narożnych, odczytałem zegar tylko raz (nie dwa razy w ramach warunku filtra). Standardowa interpretacja przedziału czasu jest w połowie otwarta, od początku włącznie do końca wyłączna, więc mój kod używa tego. Używam „nie po” w znaczeniu „w dniu lub przed”. Możesz nie potrzebować tej precyzji w twoim przypadku.

Aby zapisać punkt w czasie w bazie danych, w przypadku większości silników baz danych potrzebujesz timestamp with time zone.

4
Ole V.V. 28 czerwiec 2021, 04:29

Musisz sprawdzić, czy now jest między startDate a endDate:

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;
}
2
catch23 27 czerwiec 2021, 14:28

To zależy od wymagań. @dariosicily ma rację, ale jeśli chronologia lub system kalendarza są ważne dla twojej aplikacji, zaleca się użycie compareTo

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

  if(now.compareTo(startAt) == 1 && now.compareTo(endAt) == -1){
    return "subscribed";
  }
2
sir 27 czerwiec 2021, 14:28

Możesz użyć LocalDateTime#isAfter i LocalDateTime#isBefore jak poniżej:

if (now.isAfter(startAt) && now.isBefore(endAt)) { .... }
3
dariosicily 27 czerwiec 2021, 14:14