Java 8'de ZoneId'yi ZoneOffset'e dönüştürmenin bir yolu var mı?


89

Yöntem1 ile bir epoch saniye ve zoneId var. Sistem varsayılan zoneId ile LocalDateTime'a dönüştürülebilir, ancak epoch saniyesini method2'ye göre LocalDateTime'a dönüştürmenin bir yolunu bulamıyorum, çünkü ZoneOffset.systemDefaultbunun belirsiz olduğunu düşünüyorum.

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

Toplu içe aktarmanın import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}çalışması için hangi dili / lehçeyi kullanıyorsunuz ? Bu bir var unexpected tokenJava 11. benim için
anddero

1
Scala olabilir, ancak bu burada gerçekten önemli değil
donatas M

1
Arkasındaki teoriyi java.timeburada ayrıntılı olarak tartıştım : stackoverflow.com/a/56508200/145989
Ondra Žižka

Yanıtlar:


113

Burada böyle ulaşır ZoneOffsetdan ZoneId:

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

Not: ZoneIdzamandaki noktaya ve belirli yerin geçmişine bağlı olarak farklı sapmalara sahip olabilir. Bu nedenle, farklı Anların seçilmesi farklı ofsetlere neden olur.

NB2: ZoneId.of()bir dönebilir ZoneOffsetyerine ZoneIdeğer UTC+3/ GMT+2gibi bir zaman dilimine karşılık / etc geçirilir Africa/Cairo. Dolayısıyla, UTC / GMT farkları geçilirse, geçmiş / coğrafi / gün ışığından yararlanma bilgileri Instantdikkate alınmayacaktır - yalnızca belirtilen ofset ile çalışacaksınız.


Mevcut an DST'de ise bu yanlış değer verir, ancak hesaplama anında DST'sizdir
DST'de DST'sizdir msangel

@msangel, bunu iki kez kontrol edebilir misin? Belki ZoneId.systemDefault()kodunuzda kullanıyorsunuz ve farklı makinelerde farklı saat dilimleri döndürüyor?
Stanislav Bashkyrtsev

Bunu kontrol ettim ve başka bir duruma bağlı olarak çalışıyor. Bununla güncellenmiş cevap.
msangel

43

Bire bir eşleştirme yoktur. ZoneId, zaman içinde bir dizi farklı ZoneOffsets'in kullanıldığı bir coğrafi kapsamı tanımlar. Saat dilimi yaz saati uygulamasını kullanıyorsa ZoneOffset yaz ve kış arasında farklı olacaktır.

Ayrıca, gün ışığından yararlanma saati kuralları zaman içinde değişmiş olabilir, bu nedenle ZoneOffset, 13/10/1980 ile karşılaştırıldığında 13/10/2015 için farklı olabilir.

Böylece, ZoneId için ZoneOffset'i yalnızca belirli bir Anında bulabilirsiniz.

Ayrıca bakınız Https://en.wikipedia.org/wiki/Tz_database


10
Bunu biliyorum ama nasıl yapılır? LocaDate'i biliyorsam ve ZoneId'e sahipsem, onu ZoneOffset'e nasıl dönüştürebilirim. Kullanım durumum, zaman ve bölge içeren bir dizedir. Bölge bilgisini düşürmeden dizeyi bir OffsetTime olarak ayrıştırmak istiyorum.
Kai Moritz

35

tl; dr

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

… Mevcut varsayılan saat diliminden…

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Detaylar

Stanislav Bshkyrtsev tarafından cevap doğru ve doğrudan Soru cevaplar.

Ancak, Jon Skeet'in Yanıtında önerildiği gibi, daha büyük sorunlar var .

LocalDateTime

Epoch second'ı LocalDateTime'a dönüştürmenin bir yolunu bulamıyorum

LocalDateTimekasıtlı olarak saat dilimi veya UTC'den sapma kavramı yoktur. Muhtemelen istediğin şey değil. Bu Local…, herhangi bir yerellik anlamına gelir , belirli bir yer değil. Bu sınıf bir anı değil , yalnızca yaklaşık 26-27 saatlik bir aralıktaki potansiyel anları temsil eder (dünyadaki zaman dilimleri aralığı).

Instant

Geçerli saati almaya çalışıyorsanız, epoch saniye ile başlamanıza gerek yoktur. Akımı alın Instant. InstantSınıfı zaman çizelgesinde bir anı temsil UTC çözünürlüğe sahip nanosaniye (ondalık kesir dokuz (9) haneye kadar).

Instant instant = Instant.now();

Bunun içinde, çağdan Instantitibaren nanosaniye sayısı var . Ama gerçekten umursamıyoruz.

ZonedDateTime

Belirli bir bölgenin duvar saatlik süre merceğinden o anı görmek istiyorsan, bir geçerli ZoneIdbir olsun ZonedDateTime.

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

Bir kısayol olarak, doğrudan ZonedDateTime.

ZonedDateTime zdt = ZonedDateTime.now( z );  

A'nın ZonedDateTimeiçinde bir Instantvardır. UTC'dezdt.toInstant() temel bir değer olarak aynı anda aynı anı almak için arayın . Dönemden beri aynı sayıda nanosaniye, her şekilde, bir .ZonedDateTimeInstant

Dönemden bu yana geçen saniye sayısı

Size çağdan beri bir saniye sayısı verilmişse ve dönem, UTC ( 1970-01-01T00:00:00Z) ' de 1970'in ilk anıysa, o sayıyı Instant.

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

Hem modern hem de eski Java'daki tarih-saat türleri tablosu.


Hakkında java.time

Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date, Calendar& SimpleDateFormat.

Daha fazla bilgi edinmek için Oracle Eğitimine bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .

Şu anda bakım modunda olan Joda-Time projesi, java.time sınıflarına geçişi tavsiye ediyor .

Sen değiştirebilir java.time sizin veritabanı ile doğrudan nesneleri. JDBC 4.2 veya üstü ile uyumlu bir JDBC sürücüsü kullanın . Dizelere gerek yok, derslere gerek yok .java.sql.*

Java.time derslerini nereden edinebilirim?

ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time uygulamasına gelecekteki olası eklemeler için kanıtlayıcı bir zemindir. Burada bazı yararlı sınıfları gibi bulabilir Interval, YearWeek, YearQuarter, ve daha .


10

Gibi belgeler der ki, "Bu öncelikle düşük seviyeli yerine dönüşümler genel uygulama kullanımı için tasarlanmıştır."

Üzerinden gitmek Instantbenim için çok mantıklı geliyor - ikinci çağınız etkili bir şekilde bir farklı bir temsil Instant, bu yüzden an'a dönüştürün Instantve sonra bunu belirli bir zaman dilimine dönüştürün.


9

Umarım aşağıdaki çözümümün ilk iki satırı yardımcı olur. Benim sorunum vardı LocalDateTimeve bir zaman diliminin ismi, ve bir ihtiyaç instantBen inşa edebileceğini, böylece java.util.Dateo en neyi MongoDB istediği için. Kodum Scala, ancak burada Java'ya çok yakın, onu anlamakta bir sorun olmamalı:

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)

1
Bu cevabı buraya gönderdim çünkü sonunda anladığım şeyi yapmanın bir yolunu ararken ortaya çıkan sayfa buydu.
gknauth

2

Aşağıdakiler, bu saat diliminde standart saati almak için UTC'ye eklenecek süreyi milisaniye cinsinden döndürür:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()

0

Bir epoch second ve zoneId var. Java 8'de ZoneId'yi ZoneOffset'e dönüştürmenin bir yolu var mı?

  1. ZonedDateTimeEpoch second ve Zone Id'den alın
  2. alın ZoneOffsetdanZonedDateTime

Demo:

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

Çıktı:

+01:00
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.