Struktur data untuk mewakili jadwal kalender dengan rincian waktu yang ditentukan?

Saya telah mencoba memikirkan cara murni Java untuk mewakili jadwal selama satu tahun kalender penuh. Setiap jadwal memiliki slot 30 menit (perincian setengah jam).

Ini akan diabstraksi melalui metode repositori seperti findByDateTime()

Pada dasarnya saya perlu memodelkan slot waktu pada granularitas 30 menit untuk setiap hari.

Cara saya meretasnya bersama-sama adalah seperti itu

public Map<Integer, Map<Integer, Programme>> enumerateMapOfMapSchedules() {

    int numberOfSlots = 48; //48 half hours in a day

    Map<Integer, Map<Integer, Programme>> dayToTimeScheduleMap = new HashMap<>();

    //create a key value map for each day of the year
    for (int i = 1; i < 366; i++) {

        Map<Integer, Programme> dayProgrammeScheduleMap = new HashMap<>();

        for (int y = 1; y < numberOfSlots; y++) {
            dayProgrammeScheduleMap.put(y, null);
        }

        dayToTimeScheduleMap.put(i, dayProgrammeScheduleMap);
    }
    //creates a map with 365 days and each day having a map of 48 schedule slots
    return dayToTimeScheduleMap;
}

Saya menghargai solusi ini tidak menangani atau memiliki konsep tahun, namun karena ini untuk tiruan/tes maka saya setuju dengan ini.

Juga tidak menangani jadwal yang tumpang tindih, jika program mencakup dua slot setengah jam.

Metode kueri saya cukup sederhana untuk menemukan apa yang ada di slot jadwal tertentu.

public Programme findByDateTime(LocalDateTime dateTime) {

    int scheduleSlot = dateTime.getHour() * 2;

    //if its the after 30 minute schedule slot
    if (dateTime.getMinute() > 30) {
        scheduleSlot++;
    }

    return scheduleMap.get(dateTime.getDayOfYear()).get(scheduleSlot);
}

Namun untuk mengulangi seluruh struktur data untuk melihat berapa banyak kemunculan program tertentu yang ada.

Pertanyaan saya, apakah ada cara yang lebih mudah untuk melakukan ini?

Saya mencoba melakukannya dengan DB relasional tetapi sulit untuk merepresentasikan periode waktu dengan mudah tanpa banyak SQL.

Setiap saran atau saran implementasi disambut baik!


person tomaytotomato    schedule 15.06.2020    source sumber


Jawaban (1)


Panjang hari bervariasi

Jadwal kalender hanya masuk akal dalam konteks zona waktu dan tahun. Politisi sering kali mengubah offset yang digunakan berdasarkan zona waktu yurisdiksi mereka. Artinya, hari tidak selalu 24 jam. Anomali seperti Waktu Musim Panas (DST) berarti satu hari mungkin berdurasi 23 jam, 25 jam panjang, atau sesuatu yang lain seperti 23,5 jam.

Mulailah dari awal, hitung dengan kelipatan 30 menit

Jadi, jika Anda ingin membagi satu tahun penuh menjadi segmen 30 menit, Anda harus mulai dari momen pertama hari pertama tahun tertentu dalam zona waktu tertentu, dan menambahkan 30 menit setiap kalinya hingga mencapai zona waktu baru. tahun.

ZoneId z = ZoneId.of( "America/Montreal" );
Year year = Year.of( 2021 );
LocalDate firstOfYear = year.atDay( 1 );
ZonedDateTime start = firstOfYear.atStartOfDay( z );
List < ZonedDateTime > zdts = new ArrayList <>();

Duration duration = Duration.ofMinutes( 30 );
ZonedDateTime zdt = start;
while ( zdt.getYear() == year.getValue() )
{
    zdts.add( zdt );
    // Setup the next loop.
    zdt = zdt.plus( duration );
}

Kembalikan salinan daftar itu yang tidak dapat dimodifikasi.

List < ZonedDateTime > slots = List.copyOf( zdts );

Saat dijalankan. Pemberitahuan apa yang terjadi pada pukul 01.00 atau 02.00 tanggal 14 Maret 2021 dan 7 November 2021.

slot = [01-01-2021T00:00-05:00[Amerika/Montreal], 01-01-2021T00:30-05:00[Amerika/Montreal], 01-01-2021T01:00-05:00[Amerika /Montreal], 01-01-2021T01:30-05:00[Amerika/Montreal], 01-01-2021T02:00-05:00[Amerika/Montreal],

14-03-2021T01:00-05:00[Amerika/Montreal], 14-03-2021T01:30-05:00[Amerika/Montreal], 14-03-2021T03:00-04:00[Amerika/Montreal] ,

07-11-2021T00:30-04:00[Amerika/Montreal], 07-11-2021T01:00-04:00[Amerika/Montreal], 07-11-2021T01:30-04:00[Amerika/Montreal] , 07-11-2021T01:00-05:00[Amerika/Montreal], 07-11-2021T01:30-05:00[Amerika/Montreal], 07-11-2021T02:00-05:00[Amerika/Montreal ],

31-12-2021T22:00-05:00[Amerika/Montreal], 31-12-2021T22:30-05:00[Amerika/Montreal], 31-12-2021T23:00-05:00[Amerika/Montreal] , 31-12-2021T23:30-05:00[Amerika/Montreal]]

Proyeksi masa depan tidak dapat diandalkan!

Namun berhati-hatilah: politisi sering kali mengubah offset yang digunakan dalam suatu zona! Hal ini terjadi lebih sering daripada yang mungkin Anda sadari. Para politisi bahkan menjadi lebih buruk lagi dengan mengurangi peringatan dini mereka dari bertahun-tahun menjadi beberapa bulan, atau bahkan beberapa minggu seperti yang terlihat baru-baru ini di Turki dan Maroko, dan bahkan tidak ada peringatan sama sekali seperti yang terlihat di Korea Utara.

Jadi Anda tidak dapat memproyeksikan masa depan dengan andal menggunakan pendekatan yang terlihat di atas.

Matematika slot

Saya kira Anda bisa mendekati masalah slot tahun ini dengan cara lain. Hitung jumlah seluruh slot sepanjang tahun dengan cara ini.

ZoneId z = ZoneId.of( "America/Montreal" );
Year year = Year.of( 2021 );
LocalDate firstOfYear = year.atDay( 1 );
ZonedDateTime start = firstOfYear.atStartOfDay( z );
ZonedDateTime end = start.plusYears( 1 );

Duration slotLength = Duration.ofMinutes( 30 );
long wholeSlotsInYear = Duration.between( start , end ).dividedBy( slotLength );

Kemudian Anda dapat melompat ke suatu titik dalam tahun tersebut dengan mengalikan durasi, dan menambahkan hasilnya ke awal tahun.

int slotNumber = 22;
Duration jump = slotLength.multipliedBy( slotNumber - 1 );  // Subtract one to change an ordinal number into a zero-based index. 
ZonedDateTime slot22 = start.plus( jump );

Pelacakan buku janji temu

Jika Anda membuat janji temu seperti di salon rambut atau klinik gigi, pendekatan yang biasa dilakukan adalah melacak tahun-bulan-hari dengan waktu tertentu. Tapi lacak zona waktu secara terpisah. Jadi gunakan LocalDateTime dengan ZoneId terpisah di model Java Anda. Dalam tabel database Anda, gunakan sepasang kolom, salah satu tipenya mirip dengan tipe standar SQL TIMESTAMP WITHOUT TIME ZONE dan kolom lainnya bertipe teks yang memuat nama zona waktu seperti America/Montreal atau Africa/Tunis.

Saat membuat jadwal, terapkan zona untuk menentukan momen. Di Java, itu berarti menerapkan ZoneId ke LocalDateTime untuk mendapatkan ZonedDateTime.

Anda harus memahami gagasan mendasar bahwa objek LocalDateTime tidak mewakili momen. Dalam contoh kita di sini, pukul 15.00 pada tanggal 23 tahun depan bisa berarti pukul 15.00 di Tokyo Jepang atau pukul 15.00 di Toledo Ohio AS, dua momen yang sangat berbeda dengan jarak beberapa jam. A LocalDateTime pada dasarnya bersifat ambigu. Maka dari itu perlunya menyimpan zona waktu juga, namun tetap terpisah.

LocalDateTime ldt = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;  // Determine a moment.

Lihat momen yang sama di UTC dengan mengekstrak Instant.

Instant instant = zdt.toInstant() ;
person Basil Bourque    schedule 16.06.2020