Obtenez la date du premier jour de la semaine en fonction de LocalDate.maintenant () dans Java 8
Je voudrais obtenir la date du premier jour de la semaine basé sur LocalDate.maintenant(). Ce qui suit était possible avec JodaTime, mais semble être supprimé de la nouvelle API Date dans Java 8.
LocalDate now = LocalDate.now();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY));
Je ne peux pas appeler ' withDayOfWeek ()', car il n'existe pas.
Donc, ma question Est: Comment obtenir la date du premier jour de la semaine en fonction D'une date locale?
7 réponses
Notez que l'expression System.out.println(now.with(DayOfWeek.MONDAY))
est indépendante des paramètres régionaux car elle utilise ISO-8601, donc elle saute toujours en arrière jusqu'à lundi dernier (ou reste le lundi au cas où la date pointe déjà vers lundi).
En tant que tel aux États-Unis ou dans d'autres pays - où la semaine commence le dimanche-cela peut ne pas fonctionner comme prévu - now.with(DayOfWeek.MONDAY)
ne sautera pas en avant au lundi, au cas où la date pointe vers le dimanche.
Si vous avez besoin de répondre à ces préoccupations, il est préférable d'utiliser le champ localisé 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)
Un autre exemple en raison des commentaires ci-dessous:
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
L'exemple des États-Unis indique clairement que quelqu'un résidant aux États-Unis s'attendrait à aller au dernier et non au dimanche prochain parce que le dimanche est considéré comme le premier jour de la semaine aux États-Unis. L'expression ISO simple with(DayOfWeek.SUNDAY)
ignore ce problème de localisation.
Malgré toutes les réponses précédentes, je devais encore creuser pour comprendre ce que Java8 faisait, alors voici ce que j'ai trouvé être la façon la plus intuitive de le faire:
LocalDate implémente Temporelle
with(TemporalField field, long newValue)
Renvoie un objet du même type que cet objet avec le champ spécifié modifié.
Nous devons donc lui dire quelle partie de la date de LocalDate
nous voulons changer (DAY_OF_WEEK
) et changer à quoi valeur.
Dans le cas où vous aviez des doutes que les jours de la semaine pourraient être comptés de 0 à 6 ou de 1 à 7:
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
J'ai dû clouer ce que mon JDK fournissait pour les valeurs par défaut-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
Donc, si j'exécute du code basé sur ces valeurs par défaut, comme ceci:
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)
Ensuite, Java va avec {[11] } qui définit non seulement la partie de la date que nous voulons modifier, mais aussi comment la modifier.
Donc, si nous voulons que notre code traite de n'importe quoi l'utilisateur spécifie que le premier jour de la semaine, nous créons notre propre définition de la façon dont les calculs basés sur la semaine sont censés être effectués, en utilisant la méthode WeekFields.of()
factory.
En utilisant ceci, nous pouvons passer notre propre paramètre dayOfWeek
à with()
pour faire le calcul de la date comme nous le voulons:
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)
Pour plus d'informations, jetez un oeil au code LocalDate.with()
, c'est assez intéressant.
Grâce à venir à partir de dans cette question.
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());
Comme Réponse correcte par Ray dit, vous pouvez appeler with
et passer le DayOfWeek
enum.
Fuseau horaire
Notez que le fuseau horaire est crucial pour déterminer la date de "aujourd'hui". A tout moment, la date varie selon l'endroit où vous vous trouvez sur le globe.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY );
Si vous ne spécifiez pas de fuseau horaire, le fuseau horaire par défaut actuel de la JVM est appliqué en mode silencieux. Attention: cette valeur par défaut peut changer à tout moment pendant l'exécution! Mieux vaut spécifier votre fuseau horaire souhaité / attendu .
ZonedDateTime
, Vous pouvez appliquer un fuseau horaire (un ZoneId
) pour votre LocalDate
pour obtenir un ZonedDateTime
représentant le premier moment de la semaine.
ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );
Le LocalDate ne semble pas l'avoir, mais WeekFields (qui provient de l'API java-8) le fait (tiens). Donc, vous pouvez faire ceci:
WeekFields.of(Locale.getDefault()).firstDayOfWeek.value
Renvoie la valeur du premier jour de la semaine, à partir de 1 comme Lundi, se terminant par 7 comme dimanche.
Exemple d'utilisation (dans Kotlin), pour obtenir un nouveau LocalDate qui a le dayOfWeek défini, en remontant dans le temps au lieu de forward:
/**@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
}
Exemple entrées-sorties:
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
Et voici un exemple de fonction pour aller de l'avant dans le temps au jour cible de la semaine:
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
}
}
BTW, chose étrange est que je pense que le code dans les coulisses de la nouvelle API utilise réellement la classe Calendar de toute façon...
Si vous détestez utiliser le dayOfWeek utilisé pour LocalDate (comme je le fais), et que vous préférez celui utilisé avec Calendar, vous pouvez utiliser ces convertisseurs simples:
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
}
}