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?
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():
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:
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:
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:
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
}
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
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.
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.