web-dev-qa-db-fra.com

Obtenir la date du premier jour de la semaine en fonction de LocalDate.now () dans Java 8

Je voudrais obtenir la date du premier jour de la semaine sur la base de LocalDate.now (). Ce qui suit était possible avec JodaTime, mais semble avoir été supprimé de la nouvelle API Date de Java 8.

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

Je ne peux pas appeler 'withDayOfWeek ()', car il n'existe pas.

Ma question est donc la suivante: Comment obtenir la date du premier jour de la semaine en fonction d’une date locale? 

32
bashoogzaad

Notez que l'expression System.out.println(now.with(DayOfWeek.MONDAY)) dépend des paramètres régionaux, car elle utilise ISO-8601. Par conséquent, elle revient toujours en arrière jusqu'au lundi dernier (ou reste lundi si la date est déjà fixée à lundi). 

Ainsi, aux États-Unis ou dans certains autres pays - où la semaine commence le dimanche - cela ne fonctionnera peut-être pas comme prévu - now.with(DayOfWeek.MONDAY)ne fera pas un bond en avant jusqu'à lundi, si la date indique dimanche.

Si vous avez besoin de résoudre ces problèmes, 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 dû aux 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 américain montre assez clairement que quelqu'un résidant aux États-Unis s'attendrait à rester le dernier et non au dimanche prochain, car dimanche est considéré comme le premier jour de la semaine aux États-Unis. La simple expression basée sur ISO with(DayOfWeek.SUNDAY) ignore ce problème de localisation.

58
Meno Hochschild

Essayer

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

Merci à viens de à 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());
1
Semih Eker

Comme le correct Answer de 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 votre position 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 de la machine virtuelle Java 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 (a ZoneId ) à votre LocalDate pour obtenir un ZonedDateTime représentant le premier moment de la semaine.

ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );
1
Basil Bourque

LocalDate ne semble pas avoir cela, mais WeekFields (qui provient de l'API Java-8) en a ( here ). Donc, vous pouvez faire ceci:

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

Ceci retourne la valeur du premier jour de la semaine, commençant de 1 à lundi et se terminant à 7 à dimanche.

Exemple d'utilisation (en Kotlin), pour obtenir une nouvelle date locale qui a la valeur dayOfWeek, en remontant dans le temps au lieu d'avancer:

/**@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 d'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 avancer dans le temps jusqu'au jour de la semaine cible:

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, c'est que je pense que le code dans les coulisses de la nouvelle API utilise en fait la classe Calendar de toute façon ...

Si vous détestez utiliser dayOfWeek comme 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
    }
}
1
android developer

Avec Joda Time, que pensez-vous de

now.toString("EEEE", locale)
0
Labe

Cela fonctionne pour moi au cas où je voudrais recevoir lundi comme premier jour de la semaine en cours:

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