PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przechowywanie spotkań w bazie danych SQL, takiej jak Postgres do użytku z frameworkiem java.time

To zależy od rodzaju spotkania.

Istnieją dwa rodzaje spotkań:

  • Chwila, konkretny punkt na osi czasu, ignorujący wszelkie zmiany zasad strefy czasowej.
    Przykład:start rakiety.
  • Data i pora dnia, które powinny zostać dostosowane do zmian w zasadach strefy czasowej.
    Przykład:wizyta medyczna/dentystyczna.

Moment

Jeśli rezerwujemy np. start rakiety, nie obchodzi nas data i pora dnia. Dbamy tylko o moment, w którym (a) niebiosa wyrównają się i (b) spodziewamy się sprzyjającej pogody.

Jeśli w międzyczasie politycy zmienią zasady strefy czasowej używanej na naszej stronie startowej lub w naszych biurach, nie ma to wpływu na nasz termin rozpoczęcia. Jeśli politycy zarządzający naszą witryną startową przyjmą Czas letni (DST) , moment naszej premiery pozostaje ten sam. Jeśli politycy rządzący naszymi biurami zdecydują się zmień zegar pół godziny wcześniej ze względu na stosunki dyplomatyczne z sąsiednim krajem, moment naszej premiery pozostaje taki sam.

W przypadku takiego spotkania tak, twoje podejście byłoby poprawne. Zarejestrowałbyś spotkanie w UTC używając kolumny typu TIMESTAMP WITH TIME ZONE . Po pobraniu dostosuj się do dowolnej preferowanej przez użytkownika strefy czasowej.

Bazy danych, takie jak Postgres użyj dowolnych informacji o strefie czasowej towarzyszących wejściu, aby dostosować się do czasu UTC, a następnie usuń te informacje o strefie czasowej. Gdy pobierzesz wartość z Postgres, zawsze będzie ona reprezentować datę z porą dnia, jak widać w UTC. Uwaga, niektóre narzędzia lub oprogramowanie pośredniczące mogą mieć funkcję antywirusową polegającą na zastosowaniu domyślnej strefy czasowej między pobraniem z bazy danych a dostarczeniem programiście. Ale pamiętaj:Postgres zawsze zapisuje i pobiera wartości typu TIMESTAMP WITH TIME ZONE w UTC, zawsze UTC i przesunięcie od UTC zero godzin-minut-sekund.

Oto przykładowy kod Java.

LocalDate launchDateAsSeenInRome = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime launchTimeAsSeenInRome = LocalTime.of( 21 , 0 ) ;
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
// Assemble those three parts to determine a moment.
ZonedDateTime launchMomentAsSeenInRome = ZonedDateTime.of( launchDateAsSeenInRome , launchTimeAsSeenInRome , zoneEuropeRome ) ;

Aby zobaczyć ten sam moment w UTC, przekonwertuj na Instant . Instant obiekt zawsze reprezentuje moment widziany w UTC.

Instant launchInstant = launchMomentAsSeenInRome.toInstant() ;  // Adjust from Rome time zone to UTC.

WITH na końcu powyższego przykładu ciągu znajduje się standardowa notacja dla UTC i jest wymawiana „Zulu”.

Niestety zespół JDBC 4.2 nie wymagał wsparcia dla Instant lub ZonedDateTime typy. Twój sterownik JDBC może, ale nie musi, być w stanie odczytywać/zapisywać takie obiekty w Twojej bazie danych. Jeśli nie, po prostu przekonwertuj na OffsetDateTime . Wszystkie trzy typy reprezentują moment, konkretny punkt na osi czasu. Ale OffsetDateTime ma wsparcie wymagane przez JDBC 4.2 z powodów, które mi umykają.

OffsetDateTime odtLaunchAsSeenInRome = launchMomentAsSeenInRome.toOffsetDateTime() ;

Zapis do bazy danych.

myPreparedStatement.setObject( … , odtLaunchAsSeenInRome ) ;

Pobieranie z bazy danych.

OffsetDateTime launchMoment = myResultSet.getObject( … , OffsetDateTime.class ) ;

Dostosuj strefę czasową Nowego Jorku żądaną przez użytkownika.

ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime launchAsSeenInNewYork = launchMoment.atZoneSameInstant( zoneAmericaNewYork ) ;

Możesz zobaczyć wszystkie powyższe kod uruchamiany na żywo na IdeOne.com .

Nawiasem mówiąc, śledzenie przeszłych wydarzeń również traktowane jest jako chwila. Kiedy pacjent rzeczywiście przybył na wizytę, kiedy klient zapłacił fakturę, kiedy nowy pracownik podpisał swoje dokumenty, kiedy nastąpiła awaria serwera… wszystko to jest śledzone jako moment w UTC. Jak omówiono powyżej, zwykle będzie to Instant , chociaż ZonedDateTime &OffsetDateTime również reprezentują chwilę. Dla bazy danych użyj TIMESTAMP WITH TIME ZONE (nie WITHOUT ).

Pora dnia

Spodziewam się, że większość aplikacji biznesowych koncentruje się na spotkaniach innego typu, w których celujemy w randkę z porą dnia, a nie konkretnym momentem.

Jeśli użytkownik umówi się na wizytę u swojego lekarza, aby przejrzeć wyniki testu, robi to na konkretną porę dnia w tym dniu. Jeśli w międzyczasie politycy zmienią zasady swojej strefy czasowej, przesuwając zegar do przodu lub do tyłu o godzinę, pół godziny lub o jakąkolwiek inną ilość czasu, data i godzina wizyty lekarskiej pozostają takie same. W rzeczywistości punkt na osi czasu pierwotnego spotkania zostanie zmieniony po tym, jak politycy zmienią strefę czasową, przesuwając się do wcześniejszego/późniejszego punktu na osi czasu.

W przypadku takich spotkań nie przechowywać datę i godzinę w formacie UTC. nie użyj bazy danych typu kolumny TIMESTAMP WITH TIME ZONE .

W przypadku takich spotkań przechowujemy datę z porą dnia bez względu na strefę czasową. Używamy kolumny bazy danych typu TIMESTAMP WITHOUT TIME ZONE (zwróć uwagę WITHOUT zamiast WITH ). Dopasowany typ w Javie to LocalDateTime .

LocalDate medicalApptDate = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime medicalApptTime = LocalTime.of( 21 , 0 ) ;
LocalDateTime medicalApptDateTime = LocalDateTime.of( medicalApptDate , medicalApptTime ) ;

Zapisz to do bazy danych.

myPreparedStatement.setObject( … , medicalApptDateTime ) ;

Wyjaśnij to:LocalDateTime obiekt nie reprezentować chwilę, to nie określony punkt na osi czasu. LocalDateTime obiekt reprezentuje zakres możliwych momenty wzdłuż około 26-27 godzin osi czasu (zakres stref czasowych na całym świecie). Aby nadać prawdziwe znaczenie LocalDateTime , musimy powiązać zamierzoną strefę czasową.

Dla tej zamierzonej strefy czasowej użyj drugiej kolumny do przechowywania identyfikatora strefy. Na przykład ciągi Europe/Rome lub America/New_York . Zobacz listę nazw stref .

ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;

Zapisz to w bazie danych jako tekst.

myPreparedStatement.setString( … , zoneEuropeRome ) ;

Wyszukiwanie. Pobierz nazwę strefy jako tekst i stwórz instancję ZoneId obiekt.

LocalDateTime medicalApptDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;
ZoneId medicalApptZone = ZoneId.of( myResultSet.getString( … ) ) ;

Połącz te dwa kawałki, aby określić moment reprezentowany jako ZonedDateTime obiekt. Rób to dynamicznie, gdy musisz zaplanować kalendarz. Ale nie zapisz tę chwilę. Jeśli politycy przedefiniują strefy czasowe w przyszłości, wówczas należy obliczyć inny moment.

ZonedDateTime medicalApptAsSeenInCareProviderZone = ZonedDateTime.of( medicalApptDateTime , medicalApptZone ) ;

Użytkownik podróżuje do Nowego Jorku w Stanach Zjednoczonych. Muszą wiedzieć, kiedy zadzwonić do lekarza w Mediolanie we Włoszech, zgodnie z zegarami ściennymi w ich tymczasowej lokalizacji w Nowym Jorku. Dostosuj się więc z jednej strefy czasowej do drugiej. Ten sam moment, inny czas zegara ściennego.

ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime medicalApptAsSeenInNewYork = medicalApptAsSeenInCareProviderZone.withZoneSameInstant( zoneAmericaNewYork ) ;

tzdata

Pamiętaj, że jeśli reguły żądanych stref czasowych mogą ulec zmianie, musisz zaktualizować kopię definicji stref czasowych na swoich komputerach.

Java zawiera własną kopię tzdata , podobnie jak silnik bazy danych Postgres. A także system operacyjny hosta. Ten konkretny kod pokazany tutaj wymaga tylko aktualności Java. Jeśli używasz Postgresa do dostosowywania stref czasowych, jego tzdata muszą być również aktualne. W przypadku logowania itp. system operacyjny hosta powinien być aktualizowany. Aby użytkownik mógł prawidłowo obserwować zegar, system operacyjny komputera klienckiego również musi być aktualny.

Uwaga:politycy na całym świecie wykazali się zamiłowaniem do zmiany swoich stref czasowych z zaskakującą częstotliwością i często bez ostrzeżenia.

O java.time

java.time Framework jest wbudowany w Javę 8 i nowsze. Te klasy zastępują kłopotliwe stare dziedzictwo klasy data-godzina, takie jak java.util.Date , Calendar , &SimpleDateFormat .

Aby dowiedzieć się więcej, zapoznaj się z Samouczkiem Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Joda-Time projekt, teraz w trybie konserwacji , zaleca migrację do java.time zajęcia.

Możesz wymienić java.time obiekty bezpośrednio z bazą danych. Użyj sterownika JDBC zgodny z JDBC 4.2 lub później. Nie potrzeba ciągów, nie potrzeba java.sql.* zajęcia. Obsługa Hibernate 5 i JPA 2.2 java.time .

Skąd wziąć klasy java.time?



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy porządek jest zachowany po UNION w PostgreSQL?

  2. Nie można usunąć roli PostgreSQL. Błąd:`nie można usunąć, ponieważ niektóre obiekty od niego zależą`

  3. Jakiś powód, dla którego nie korzystasz z wbudowanego wyszukiwania pełnotekstowego PostgreSQL w Heroku?

  4. PostgreSQL 9.6:równoległe skanowanie sekwencyjne

  5. Jak w naturalny sposób połączyć dwa zapytania z klauzulą?