Czy istnieje sposób na przekonwertowanie ZoneId na ZoneOffset w java 8?

85

Mam epoch second i zoneId, według method1.Można go przekonwertować na LocalDateTime z domyślnym systemem zoneId, ale nie znajduję sposobu, aby przekonwertować sekundę epoki na LocalDateTime przez method2, ponieważ nie ma. ZoneOffset.systemDefaultMyślę, że jest to niejasne.

import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}

val epochSecond = System.currentTimeMillis() / 1000

LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())//method1
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)//method2
Renkai
źródło
Jakiego języka / dialektu używasz, aby import zbiorczy import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}działał? To unexpected tokendla mnie w Javie 11.
anddero,
1
Może to być Scala, ale to nie jest tutaj ważne
donatas M
1
Omówiłem szczegółowo tę teorię java.timetutaj: stackoverflow.com/a/56508200/145989
Ondra Žižka

Odpowiedzi:

109

Oto, jak możesz skorzystać ZoneOffsetz ZoneId:

Instant instant = Instant.now(); //can be LocalDateTime
ZoneId systemZone = ZoneId.systemDefault(); // my timezone
ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);

Uwaga: ZoneIdmoże mieć różne przesunięcia w zależności od czasu i historii danego miejsca. Tak więc wybranie różnych momentów spowoduje różne przesunięcia.

NB2: ZoneId.of()może zwrócić ZoneOffsetzamiast, ZoneIdjeśli przekazywany jest UTC+3/ GMT+2/ etc, w przeciwieństwie do strefy czasowej, takiej jak Africa/Cairo. Więc jeśli przesunięcia UTC / GMT zostaną przekazane, informacje historyczne / geograficzne / dotyczące czasu letniego Instantnie będą brane pod uwagę - po prostu będziesz pracować z określonym przesunięciem.

Stanislav Bashkyrtsev
źródło
Daje to niepoprawną wartość, jeśli bieżący moment jest w czasie letnim, ale w momencie obliczania był bez czasu letniego
msangel
@msangel, czy możesz to dokładnie sprawdzić? Może używasz ZoneId.systemDefault()w swoim kodzie i zwraca on różne strefy czasowe na różnych komputerach?
Stanislav Bashkyrtsev
Sprawdziłem to i działa w zależności od innego warunku. Zaktualizowana odpowiedź z tym.
msangel
43

Nie ma mapowania jeden do jednego. ZoneId definiuje zasięg geograficzny, w którym zestaw różnych ZoneOffsets jest używany w czasie. Jeśli strefa czasowa korzysta z czasu letniego, jej ustawienie ZoneOffset będzie inne w okresie letnim i zimowym.

Co więcej, zasady dotyczące czasu letniego mogły się zmieniać w czasie, więc ZoneOffset może być inna np. 13/10/2015 w porównaniu z 13/10/1980.

Więc możesz znaleźć ZoneOffset dla ZoneId w konkretnym Instant.

Zobacz także https://en.wikipedia.org/wiki/Tz_database

GreyFairer
źródło
10
Wiem o tym, ale jak to się robi? Jeśli znam LocaDate i mam ZoneId, jak przekonwertować go na ZoneOffset. Mój przypadek użycia to ciąg zawierający czas i strefę. Chcę przeanalizować ciąg w OffsetTime bez porzucania informacji o strefie.
Kai Moritz
33

tl; dr

ZonedDateTime.now( 
    ZoneId.of( "America/Montreal" ) 
)

… Bieżącej domyślnej strefy czasowej…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Detale

Odpowiedz przez Stanislav Bshkyrtsev prawidłowo i bezpośrednio odpowiada na Twoje pytanie.

Istnieją jednak większe problemy, jak sugeruje odpowiedź Jona Skeeta .

LocalDateTime

Nie znajduję sposobu, aby przekonwertować epokę sekundę na LocalDateTime

LocalDateTimecelowo nie ma pojęcia strefy czasowej ani przesunięcia względem czasu UTC. Mało prawdopodobne, czego chcesz. Local…Oznacza dowolną lokalizację, a nie któregokolwiek konkretnym obszarze. Ta klasa nie przedstawia momentu, a jedynie potencjalne momenty w zakresie około 26-27 godzin (zakres stref czasowych na całym świecie).

Instant

Nie musisz zaczynać od sekund epoki, jeśli próbujesz uzyskać aktualny czas. Pobierz aktualny Instant. InstantKlasa reprezentuje moment na osi czasu w UTC z rozdzielczością nanosekund (do dziewięciu (9) cyfr ułamka dziesiętnego).

Instant instant = Instant.now();

Wewnątrz tego Instantjest liczba nanosekund -od-epoki. Ale tak naprawdę nas to nie obchodzi.

ZonedDateTime

Jeśli chcesz zobaczyć ten moment przez pryzmat zegara ściennego określonego regionu, zastosuj a, ZoneIdaby uzyskać ZonedDateTime.

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = instant.atZone( z );

Jako skrót możesz zrobić bezpośrednio do ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

A ZonedDateTimema Instantw sobie. Zadzwoń, zdt.toInstant()aby uzyskać ten sam moment jako podstawową wartość w UTC . Taka sama liczba nanosekund od epoki w obu przypadkach, jako a ZonedDateTimelub jako Instant.

Podane sekundy od epoki

Jeśli podana jest liczba sekund od epoki, a epoka jest pierwszą chwilą roku 1970 w UTC ( 1970-01-01T00:00:00Z), podaj tę liczbę do Instant.

long secondsSinceEpoch = 1_484_063_246L ;
Instant instant = Instant.ofEpochSecond( secondsSinceEpoch ) ;

Tabela typów dat i godzin w Javie, zarówno nowoczesnych, jak i starszych.


Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

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

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas.

Skąd wziąć klasy java.time?

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
10

Jak mówi dokumentacja : „Jest to przeznaczone głównie do konwersji niskiego poziomu, a nie do ogólnego wykorzystania aplikacji”.

Przejście przez Instantma dla mnie sens - twoja sekunda epoki jest właściwie inną reprezentacją an Instant, więc przekonwertuj ją na an, Instanta następnie przekonwertuj ją na określoną strefę czasową.

Jon Skeet
źródło
9

Mam nadzieję, że pierwsze dwie linijki mojego rozwiązania poniżej są pomocne. Mój problem polegał na tym, że miałem LocalDateTimei nazwę strefy czasowej i potrzebowałem, instantaby móc zbudować java.util.Date, ponieważ tego chciał MongoDB. Mój kod to Scala, ale tutaj jest tak blisko Java, że ​​myślę, że nie powinno być problemu ze zrozumieniem go:

val zid = ZoneId.of(tzName)                                // "America/Los_Angeles"
val zo: ZoneOffset = zid.getRules.getOffset(localDateTime) // ⇒ -07:00
                                         // 2017-03-16T18:03

val odt = OffsetDateTime.of(localDateTime, zo) // ⇒ 2017-03-16T18:03:00-07:00
val instant = odt.toInstant                    // ⇒ 2017-03-17T01:03:00Z
val issued = Date.from(instant)
gknauth
źródło
1
Opublikowałem tę odpowiedź tutaj, ponieważ była to strona, która pojawiła się, gdy szukałem sposobu na zrobienie tego, co w końcu odkryłem.
gknauth
1

Poniższe zwraca ilość czasu w milisekundach, jaki należy dodać do czasu UTC, aby uzyskać standardowy czas w tej strefie czasowej:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()
Jelmer
źródło
0

Mam epokową sekundę i zoneId. Czy istnieje sposób na przekonwertowanie ZoneId na ZoneOffset w java 8?

  1. Pobierz ZonedDateTimez epoki sekund i Id strefy
  2. Get ZoneOffsetfromZonedDateTime

Próbny:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Get ZonedDateTime from epoch second and Zone Id
        ZonedDateTime zdt = Instant.ofEpochSecond(1597615462L).atZone(ZoneId.of("Europe/London"));

        // Get ZoneOffset from ZonedDateTime
        ZoneOffset offset = zdt.getOffset();

        System.out.println(offset);
    }
}

Wynik:

+01:00
Arvind Kumar Avinash
źródło