Abrufen des Datums des ersten Wochentags basierend auf LocalDate.now() in Java 8

Lesezeit: 9 Minuten

Ich möchte das Datum des ersten Wochentags basierend auf LocalDate.now() erhalten. Folgendes war mit JodaTime möglich, scheint aber aus der neuen Date-API in Java 8 entfernt worden zu sein.

LocalDate now = LocalDate.now();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY));

Ich kann ‘withDayOfWeek()’ nicht aufrufen, weil es nicht existiert.

Also meine Frage ist: Wie erhält man das Datum des ersten Wochentags basierend auf LocalDate?

Benutzer-Avatar
Meno Hochschild

Beachten Sie, dass der Ausdruck System.out.println(now.with(DayOfWeek.MONDAY)) ist vom Gebietsschema unabhängig, da es ISO-8601 verwendet, daher springt es immer zurück zum letzten Montag (oder bleibt am Montag, falls das Datum bereits auf Montag zeigt).

Daher funktioniert es in den USA oder einigen anderen Ländern – wo die Woche am Sonntag beginnt – möglicherweise nicht so, wie Sie es erwarten würden – now.with(DayOfWeek.MONDAY) wird nicht nach vorne springen bis Montag, falls das Datum auf Sonntag zeigt.

Falls Sie diese Bedenken ansprechen müssen, ist es besser, das lokalisierte Feld zu verwenden WeekFields.dayOfWeek():

LocalDate now = LocalDate.now();
TemporalField fieldISO = WeekFields.of(Locale.FRANCE).dayOfWeek();
System.out.println(now.with(fieldISO, 1)); // 2015-02-09 (Monday)

TemporalField fieldUS = WeekFields.of(Locale.US).dayOfWeek();
System.out.println(now.with(fieldUS, 1)); // 2015-02-08 (Sunday)

Ein weiteres Beispiel aufgrund der folgenden Kommentare:

LocalDate ld = LocalDate.of(2017, 8, 18); // Friday as original date

System.out.println(
    ld.with(DayOfWeek.SUNDAY)); // 2017-08-20 (2 days later according to ISO)

// Now let's again set the date to Sunday, but this time in a localized way...
// the method dayOfWeek() uses localized numbering (Sunday = 1 in US and = 7 in France)

System.out.println(ld.with(WeekFields.of(Locale.US).dayOfWeek(), 1L)); // 2017-08-13
System.out.println(ld.with(WeekFields.of(Locale.FRANCE).dayOfWeek(), 7L)); // 2017-08-20

Das US-Beispiel macht ziemlich deutlich, dass jemand mit Wohnsitz in den USA erwarten würde, zum letzten und nicht zum nächsten Sonntag zu gehen, da der Sonntag in den USA als erster Wochentag gilt. Der einfache ISO-basierte Ausdruck with(DayOfWeek.SUNDAY) ignoriert dieses Lokalisierungsproblem.

  • Nur zur Info WeekFields.of(Locale.getDefault()).getFirstDayOfWeek() gibt den konfigurierten ersten Wochentag für das aktuelle Gebietsschema zurück (z SUNDAY, MONDAY, etc). Nicht das Datum.

    – Brice

    4. Januar 2016 um 14:31 Uhr

  • @MenoHochschild Warum sollte die Aufzählung DayOfWeek funktioniert nicht in einigen Regionen wie den USA? Was ist das Problem?

    – Basilikum Bourque

    15. Januar 2016 um 22:15 Uhr


  • @BasilBourque Wenn heute Sonntag ist und wir uns in den USA befinden (Sonntag als erster Wochentag), dann today.with(MONDAY) geht zum nächsten Tag (+1), aber wenn wir in Europa sind, gehen wir 6 Tage zurück (-6). Der Ausdruck with(day-of-week) bezeichnet das Gehen zum Wochentag innerhalb der GLEICHEN Kalenderwoche, und das hängt vom Beginn der Woche ab.

    – Meno Hochschild

    16. Januar 2016 um 3:48 Uhr

  • @BasilBourque Zur Klarstellung bezieht sich mein vorheriger Kommentar auf die Verwendung von WeekFields (wollte sagen with(day-of-week, 1)). Wenn Sie Ihren bevorzugten Ansatz verwenden (basierend auf enum – with(MONDAY)), dann basiert die Manipulation nur auf dem ISO-Stil, wobei immer der Montag als erster Wochentag angenommen wird. Leider, WeekFields funktioniert nicht direkt mit Aufzählungen, sondern mit langen Zahlen (schlechtes Design), daher ist es weniger bequem und kryptischer als es sollte (today.with(WeekFields.of(Locale.US).dayOfWeek(), MONDAY) kompiliert nicht).

    – Meno Hochschild

    16. Januar 2016 um 4:01 Uhr


  • @barthand Danke für den Hinweis. Ich habe jetzt die erste Aussage/den ersten Satz aktualisiert und hoffe, dass es jetzt klarer ist.

    – Meno Hochschild

    18. August 2017 um 13:43 Uhr

Versuchen

System.out.println(now.with(DayOfWeek.MONDAY));

  • Ich möchte nur hinzufügen, dass nicht alle Orte auf der Erde den gleichen Anfangstag der Woche haben. Wenn es benötigt wird, kann es durch erhalten werden Kalender#getFirstDayOfWeek

    – ioreskovic

    11. Februar 2015 um 9:53 Uhr


  • Können wir die Woche irgendwie so ändern, dass sie am Sonntag beginnt, und denselben Befehl verwenden, um den ersten Wochentag zu erhalten?

    – Durga Swaroop

    1. Januar 2016 um 23:16 Uhr

  • Behandelt das Gebietsschema nicht richtig, nicht alle Gebietsschemas beginnen mit Montag als erstem Wochentag.

    – Brice

    4. Januar 2016 um 14:29 Uhr

  • Prägnanteste Antwort IMO. Wenn das OP andere Orte in Betracht ziehen wollte, hätte er es auch in Joda Time tun müssen.

    – Jerry

    3. Juni 2021 um 10:07 Uhr

Trotz all der vorherigen Antworten musste ich immer noch herumgraben, um herauszufinden, was Java8 tat, also fand ich hier den intuitivsten Weg, dies zu tun:

LocalDate implementiert Zeitlich

with(TemporalField field, long newValue)

Gibt ein Objekt desselben Typs wie dieses Objekt zurück, wobei das angegebene Feld geändert wurde.

Also müssen wir ihm sagen, zu welchem ​​​​Datumsteil er gehört LocalDate wir wollen uns ändern (DAY_OF_WEEK) und auf welchen Wert ändern.

Falls Sie Zweifel hatten, dass die Wochentage von 0 bis 6 oder von 1 bis 7 gezählt werden können:

    System.out.printf("first day of week (0 or 1) == %d \n",
            ChronoField.DAY_OF_WEEK.range().getMinimum());
first day of week (0 or 1) == 1 

Ich musste festnageln, was mein JDK für Standardwerte bereitstellte – YMMV:

    System.out.printf("default zone offset==[%s]\n",
            ZoneId.systemDefault());
    System.out.printf("1st day of week==%s\n",
            WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
default zone offset==[Europe/London]
1st day of week==MONDAY

Wenn ich also Code basierend auf diesen Standardwerten ausführe, etwa so:

    LocalDate localDate = LocalDate.now();
    System.out.printf("localDate == %s \n", localDate);
    System.out.printf("localdate first day of week == %s (%s) \n",
            localDate.with(ChronoField.DAY_OF_WEEK, 1),
            localDate.with(ChronoField.DAY_OF_WEEK, 1).getDayOfWeek());
localDate == 2017-10-24 
localdate first day of week == 2017-10-23 (MONDAY) 

dann geht Java mit ChronoField.DAY_OF_WEEK die nicht nur definiert, welchen Teil des Datums wir ändern möchten, sondern auch, wie es geändert werden soll.

Wenn wir also wollen, dass unser Code mit dem umgeht, was der Benutzer als ersten Tag der Woche angibt, erstellen wir unsere eigene Definition, wie wochenbasierte Berechnungen durchgeführt werden sollen, indem wir die verwenden WeekFields.of() Fabrikmethode.

Damit können wir unsere eigenen übergeben dayOfWeek Parameter zu with() um die Datumsberechnung so durchzuführen, wie wir es wollen:

    TemporalField myWeek = WeekFields.of(DayOfWeek.SUNDAY, 1).dayOfWeek();
    System.out.printf("configured localdate first day of week == %s (%s) \n",
            localDate.with(myWeek, 1),
            localDate.with(myWeek, 1).getDayOfWeek());
configured localdate first day of week == 2017-10-22 (SUNDAY) 

Werfen Sie für weitere Einblicke einen Blick auf den Code in LocalDate.with()es ist ziemlich interessant.

Es funktioniert für mich, falls ich es bekommen möchte Montag als erster Tag der aktuellen Woche:

LocalDate mondayDate = LocalDate.now().with(WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());

Benutzer-Avatar
Semih Eker

Vielen Dank für diese Frage.

Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !
        cal.clear(Calendar.MINUTE);
        cal.clear(Calendar.SECOND);
        cal.clear(Calendar.MILLISECOND);

        // get start of this week in milliseconds
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
        System.out.println("Start of this week:       " + cal.getTime());
        System.out.println("... in milliseconds:      " + cal.getTimeInMillis());

  • Danke, dass du das bemerkt hast! Ich habe jedoch mit LocalDate nach dem Java 8-Weg gesucht.

    – bashoogzaad

    11. Februar 2015 um 9:41 Uhr

Das LocalDate scheint dies nicht zu haben, aber WeekFields (das von der Java-8-API stammt) (hier). Sie können also Folgendes tun:

WeekFields.of(Locale.getDefault()).firstDayOfWeek.value

Dies gibt den Wert des ersten Wochentags zurück, beginnend mit 1 als Montag und endend mit 7 als Sonntag.

Beispiel für die Verwendung (in Kotlin), um ein neues LocalDate zu erhalten, für das der Wochentag festgelegt ist, wobei die Zeit rückwärts statt vorwärts geht:

/**@param targetDayOfWeek day of week to go to, starting from 1 as Monday (and 7 is Sunday) */
fun LocalDate.minusDaysToDayOfWeek(targetDayOfWeek: Int = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value): LocalDate {
    //conversion so that Sunday is 0, Monday is 1, etc:
    val diffDays = (dayOfWeek.value % 7) - (targetDayOfWeek % 7)
    val result = when {
        diffDays == 0 -> this
        diffDays < 0 -> minusDays((7 + diffDays).toLong())
        else -> minusDays(diffDays.toLong())
    }
    return result
}

Beispiel Inputs-Outputs:

2017-12-31 -> 2017-12-31
2018-01-01 -> 2017-12-31
2018-01-02 -> 2017-12-31
2018-01-03 -> 2017-12-31
2018-01-04 -> 2017-12-31
2018-01-05 -> 2017-12-31
2018-01-06 -> 2017-12-31
2018-01-07 -> 2018-01-07
2018-01-08 -> 2018-01-07
2018-01-09 -> 2018-01-07
2018-01-10 -> 2018-01-07
2018-01-11 -> 2018-01-07
2018-01-12 -> 2018-01-07
2018-01-13 -> 2018-01-07
2018-01-14 -> 2018-01-14
2018-01-15 -> 2018-01-14

Und hier ist eine Beispielfunktion, um zeitlich zum Zielwochentag vorzurücken:

fun LocalDate.plusDaysToDayOfWeek(targetDayOfWeek: Int = getLastDayOfWeek()): LocalDate {
    val diffDays = (targetDayOfWeek % 7) - (dayOfWeek.value % 7)
    val result = when {
        diffDays == 0 -> this
        diffDays < 0 -> plusDays((7 + diffDays).toLong())
        else -> plusDays(diffDays.toLong())
    }
    return result
}

/**@return the  last day of week, when 1 is Monday ... 7 is Sunday) */
@JvmStatic
fun getLastDayOfWeek(firstDayOfWeek: DayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek): Int {
    return when (firstDayOfWeek) {
        DayOfWeek.MONDAY -> DayOfWeek.SUNDAY.value
        else -> firstDayOfWeek.value - 1
    }
}

Übrigens, seltsam ist, dass ich denke, dass der Code hinter den Kulissen der neuen API sowieso die Kalenderklasse verwendet …

Falls Sie es hassen, den DayOfWeek zu verwenden, wie er für LocalDate verwendet wird (wie ich es tue), und Sie den mit Calendar verwendeten bevorzugen, können Sie diese einfachen Konverter verwenden:

fun DayOfWeek.toCalendarDayOfWeek(): Int {
    return when (this) {
        DayOfWeek.SATURDAY -> Calendar.SATURDAY
        else -> (this.value + 1) % 7
    }
}

@JvmStatic
fun convertLocalDateDayOfWeekToCalendarDayOfWeek(localDateDayOfWeek: Int): Int {
    return when (localDateDayOfWeek) {
        DayOfWeek.SATURDAY.value -> Calendar.SATURDAY
        else -> (localDateDayOfWeek + 1) % 7
    }
}

@JvmStatic
fun convertFromCalendarDayOfWeekToLocalDateDayOfWeek(calendarDayOfWeek: Int): Int {
    return when (calendarDayOfWeek) {
        Calendar.SUNDAY -> DayOfWeek.SUNDAY.value
        else -> calendarDayOfWeek - 1
    }
}

  • Danke, dass du das bemerkt hast! Ich habe jedoch mit LocalDate nach dem Java 8-Weg gesucht.

    – bashoogzaad

    11. Februar 2015 um 9:41 Uhr

Benutzer-Avatar
Gemeinschaft

Wie die richtige Antwort von Ray sagt, kannst du anrufen with und passieren die DayOfWeek Aufzählung.

Zeitzone

Beachten Sie, dass die Zeitzone für die Bestimmung des Datums “heute” entscheidend ist. Zu jedem Zeitpunkt variiert das Datum je nachdem, wo Sie auf dem Globus stehen.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY );

Wenn Sie keine Zeitzone angeben, wird automatisch die aktuelle Standardzeitzone der JVM angewendet. Achtung: Diese Voreinstellung kann sich jederzeit ändern während der Laufzeit! Besser angeben Ihre gewünschte/erwartete Zeitzone.

ZonedDateTime

Sie können eine Zeitzone (a ZoneId) zu dir LocalDate ein bekommen ZonedDateTime repräsentiert den ersten Moment der Woche.

ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );

1217180cookie-checkAbrufen des Datums des ersten Wochentags basierend auf LocalDate.now() in Java 8

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy