Apakah ada cara untuk menemukan waktu standar yang berada di bawah wilayah zona waktu, misalnya

America/New_York and America/NewJersey -> EST

Saya sedang mengembangkan layanan REST di mana permintaan akan memiliki zona waktu berbasis wilayah (Amerika/NewJersey) sebagai parameter dan saya perlu menemukan waktu standar yang berlaku dan meneruskannya ke API lama, yang hanya menerima zona waktu 3 digit (EST/ MST/CST/AET).

Saya menggunakan Java 8 dan saya memeriksa Time API, tetapi tidak memiliki fitur/fungsi seperti itu. Sebagai solusinya, saya dapat memiliki pemetaan dalam file atau DB, tetapi hanya ingin tahu apakah ada orang lain yang menghadapi ini dan apakah ada solusi bersih untuk itu.

0
java_dev 10 Juli 2020, 20:23

1 menjawab

Jawaban Terbaik

Jika saya mengerti dengan benar, persyaratan utamanya adalah memiliki beberapa singkatan tiga huruf tertentu yang diperlukan oleh API di luar kendali Anda. Jadi misalnya:

  • EST untuk Waktu Standar Timur (mungkin Waktu Standar Timur Amerika Utara?), bukan ET untuk Waktu Timur.
  • Di sisi lain AET untuk Waktu Bagian Timur Australia, bukan AEST untuk Waktu Standar Timur Australia (dan juga bukan EST untuk Waktu Standar Timur meskipun saya telah membaca bahwa EST juga digunakan sebagai singkatan di Australia).

Bagi saya tampaknya tidak ada korespondensi sistematis antara singkatan zona waktu yang diketahui Java (dari CLDR atau penyedia data lokal apa yang Anda gunakan) dan singkatan yang diperlukan oleh API itu. Sebagai masalah lebih lanjut, singkatan zona waktu tiga huruf sering ambigu, jadi saya menduga ada banyak zona waktu yang tidak dapat dikenali oleh API lama Anda (atau yang memerlukan beberapa singkatan sederhana yang tidak dapat kami tebak).

Pendekatan ada dua:

  1. Cara yang aman tetapi juga tidak langsung dan melelahkan adalah cara yang telah lama disarankan oleh Deadpool dalam komentar: Bangun dan simpan pemetaan singkatan yang diperlukan.
  2. Lihat seberapa jauh Anda bisa melakukannya dengan singkatan yang diketahui Java. Bersiaplah bahwa Anda tidak akan dapat menangani semua kasus dan bahwa Anda kadang-kadang membuat tebakan yang salah.

Saya akan meninggalkan opsi 1. untuk diri Anda sendiri dengan rekomendasi saya.

Jika Anda ingin mencoba keberuntungan Anda dengan opsi 2., upaya saya berikut.

private static final DateTimeFormatter ZONE_FORMATTER
        = DateTimeFormatter.ofPattern("zzz", Locale.ENGLISH);

private static String getThreeLetterAbbreviation(ZoneId zone) {
    // Try the display name first
    String displayName = zone.getDisplayName(TextStyle.SHORT_STANDALONE, Locale.ENGLISH);
    if (displayName.length() == 3) {
        return displayName;
    }
    
    // Try formatting a date in standard time; try southern hemisphere first
    ZonedDateTime timeInStandardTime = LocalDate.of(2021, Month.JULY, 1)
            .atStartOfDay(zone);
    if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
        // Then northern hemisphere
        timeInStandardTime = LocalDate.of(2021, Month.JANUARY, 1)
                .atStartOfDay(zone);
        if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
            throw new IllegalArgumentException("Unable to find a date in standard time");
        }
    }
    return timeInStandardTime.format(ZONE_FORMATTER);
}

Metode tambahan ini mencobanya:

private static void printAbbreviation(String zid) {
    System.out.format("%19s -> %s%n", zid,
            getThreeLetterAbbreviation(ZoneId.of(zid)));
}

Jadi menggunakannya kita pergi:

    printAbbreviation("America/Los_Angeles");
    printAbbreviation("America/Denver");
    printAbbreviation("America/Chicago");
    printAbbreviation("America/New_York");
    printAbbreviation("Australia/Sydney");

Keluaran:

America/Los_Angeles -> PST
     America/Denver -> MST
    America/Chicago -> CST
   America/New_York -> EST
   Australia/Sydney -> AET

Saya tidak akan menyebutnya solusi bersih. Yang paling saya takutkan adalah bahwa metode ini akan menghasilkan hasil yang salah yang ditafsirkan oleh API Anda secara berbeda dari yang dimaksudkan, dan tidak ada yang akan menyadari bahwa metode tersebut pada gilirannya menghasilkan hasil yang salah, atau tidak sampai terlambat. Sebagai contoh:

    printAbbreviation("Asia/Shanghai");
      Asia/Shanghai -> CST

Di sini CST adalah untuk Waktu Standar China, tetapi dugaan saya adalah bahwa API Anda akan memahaminya sebagai Waktu Standar Tengah Amerika Utara. Kita benar-benar harus tidak pernah mengandalkan singkatan zona waktu tiga huruf. Mereka ambigu, mungkin lebih sering daripada tidak. Dan seperti yang ditunjukkan pertanyaan ini, mereka tidak distandarisasi.

2
Ole V.V. 11 Juli 2020, 13:59