91

I would like the get the date of the first day of the week based on LocalDate.now(). The following was possible with JodaTime, but seems to be removed from the new Date API in Java 8.

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

I can not call 'withDayOfWeek()', because it does not exist.

So my question is: How to get the date of the first day of the week based on some LocalDate?

bashoogzaad
  • 4,611
  • 8
  • 40
  • 65

10 Answers10

129

Note that the expression System.out.println(now.with(DayOfWeek.MONDAY)) is locale-independent as it uses ISO-8601, therefore it always jumps backwards to last Monday (or stays on Monday in case date points to Monday already).

As such in US or some other countries - where week starts on Sunday - it may not work as you would expect - now.with(DayOfWeek.MONDAY) will not jump forward to Monday, in case date points to Sunday.

In case you need to address these concerns, it is better to use the localized field 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)

Another example due to comments below:

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

The US-example makes pretty clear that someone residing in US would expect to go to last and not to next Sunday because Sunday is considered as first day of week in US. The simple ISO-based expression with(DayOfWeek.SUNDAY) ignores this localization issue.

barthand
  • 73
  • 3
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • 1
    Just for information `WeekFields.of(Locale.getDefault()).getFirstDayOfWeek()` returns the configured first day of week for the current locale (e.g. `SUNDAY`, `MONDAY`, etc). Not the date. – bric3 Jan 04 '16 at 14:31
  • 3
    @MenoHochschild Why would the enum [`DayOfWeek`](http://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html) not work in some locales such as US? What is the issue? – Basil Bourque Jan 15 '16 at 22:15
  • 6
    @BasilBourque If today is Sunday and we are in US (Sunday as first day of week) then `today.with(MONDAY)` will go to next day (+1), but if we are in Europe then we will go 6 days back (-6). The expression `with(day-of-week)` denotes going to day-of-week within the SAME calendar week, and that depends on the start of the week. – Meno Hochschild Jan 16 '16 at 03:48
  • 1
    @BasilBourque For clarification, my previous comment relates to use of `WeekFields` (wanted to say `with(day-of-week, 1)`). If you use your preferred approach (based on enum - `with(MONDAY)`) then the manipulation is only based on ISO-style assuming always the monday as first day of week. Unfortunately, `WeekFields` does not directly work with enums but long number (bad design) so it is less convenient and more cryptious than it should (`today.with(WeekFields.of(Locale.US).dayOfWeek(), MONDAY)` does not compile). – Meno Hochschild Jan 16 '16 at 04:01
  • @MenoHochschild I feel a little bit confused with your comments and statement that `now.with(DayOfWeek.MONDAY)` will not work in US. I'm having a test-case that uses `with(DayOfWeek.SUNDAY)` and running it today (Friday) using `en_US` locale and `PST` timezone (`-Duser.language=en -Duser.country=US -Duser.timezone=America/Los_Angeles`) or European locale & timezone brings me always the same results - in both cases I'm getting the next Sunday (20th Aug), while I think you're saying I would get last Sunday in case of US timezone (because it's part of the current week). Can you please clarify? – barthand Aug 18 '17 at 13:04
  • @barthand First, the timezone is not at all relevant here, only the locale. But, if you just apply `with(DayOfWeek.SUNDAY)` then the locale is ignored, too, and the date (if not Sunday) will always jump forward because Sunday is the last day of week in ISO-8601. – Meno Hochschild Aug 18 '17 at 13:14
  • @MenoHochschild Thanks for your answer! So since `with(DayOfWeek)` always uses ISO-8601 and ignores locale, this implies that `with(DayOfWeek.MONDAY)` will always jump backwards to last Monday (in case of any other day than Monday) or will stay on the same day (in case date points to Monday already), am I right? – barthand Aug 18 '17 at 13:20
  • @barthand Exactly. – Meno Hochschild Aug 18 '17 at 13:22
  • @MenoHochschild So maybe it would be worthwhile to explain it in your answer - _Note that the expression `System.out.println(now.with(DayOfWeek.MONDAY));` will not work in US or some other countries._ is misleading a bit, as in fact it will work in both US and any other country the same (just not-localized) way. – barthand Aug 18 '17 at 13:24
  • 1
    @barthand Thanks for the hint. I have now updated the first statement/sentence and hope it is now clearer. – Meno Hochschild Aug 18 '17 at 13:43
  • How exactly do you get the firstDayOfWeek of the current locale, instead of specifying it? – android developer Jan 08 '18 at 11:26
  • @androiddeveloper See the [javadoc](https://docs.oracle.com/javase/8/docs/api/java/time/temporal/WeekFields.html#getFirstDayOfWeek--) – Meno Hochschild Jan 08 '18 at 11:43
  • @MenoHochschild You mean this: WeekFields.of(Locale.getDefault()).firstDayOfWeek ? If so, why not post it as a real answer? Also, I think the code behind the scenes actually uses Calendar class anyway, so maybe it's better to just use it instead... – android developer Jan 08 '18 at 12:27
  • @androiddeveloper Yes, I mean `WeekFields.of(Locale.getDefault()).getFirstDayOfWeek() ` according to your comment but this is not the answer to the question of OP which asks for the full calendar date of first day of current week. – Meno Hochschild Jan 08 '18 at 13:01
  • @MenoHochschild Well it's a start, so I've actually created an answer to this, here: https://stackoverflow.com/a/48150270/878126 – android developer Jan 08 '18 at 14:16
  • Yes, this is all very true. But, getting back to the original question, my understanding is that it is consistent with the way Joda time works. So `withDayOfWeek(DateTimeConstants.MONDAY)`turns into `with(DayOfWeek.MONDAY)`, and all these considerations are valid also when you use Joda. –  Jun 03 '21 at 10:04
36

Try

System.out.println(now.with(DayOfWeek.MONDAY));
Ray
  • 3,084
  • 2
  • 19
  • 27
  • 4
    I'd just like to add that not all places on Earth have the same starting day of week. If it's needed, it can be obtained through [Calendar#getFirstDayOfWeek](http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#getFirstDayOfWeek%28%29) – ioreskovic Feb 11 '15 at 09:53
  • Can we somehow change the week to start from Sunday and use the same command to get the first day of week? – Durga Swaroop Jan 01 '16 at 23:16
  • 2
    Does not handle the locale properly, not all locale starts with Monday as the first day of week. – bric3 Jan 04 '16 at 14:29
  • Most concise answer IMO. If the OP wanted consider different locales, he would have had to do it in Joda Time, too. –  Jun 03 '21 at 10:07
9

Despite all the previous answers, I still had to dig around to work out what Java8 was doing, so here is what I found to be the most intuitive way of doing it:

LocalDate implements Temporal

with(TemporalField field, long newValue)

Returns an object of the same type as this object with the specified field altered.

So we have to tell it which date part of LocalDate we want to change (DAY_OF_WEEK) and change to what value.

In case you had doubts that the days in the week might be counted from 0 to 6 or from 1 to 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 

I had to nail down what my JDK was providing for defaults - 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

So if I execute some code based on these defaults, like 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) 

then Java goes with ChronoField.DAY_OF_WEEK which not only defines which part of the date we want to alter, but also how to alter it.

So if we want our code to deal with whatever the user specifies as the first day of the week, we create our own definition of how week-based calculations are meant to be done, using the WeekFields.of() factory method.

Using this we can pass in our own dayOfWeek parameter to with() to do the date calculation the way we want:

    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) 

For more insight, have a look at the code in LocalDate.with(), it's quite interesting.

Adam
  • 5,215
  • 5
  • 51
  • 90
5

It works for me in case if I want to get Monday as a first day of current week:

LocalDate mondayDate = LocalDate.now().with(WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
Taras Melnyk
  • 3,057
  • 3
  • 38
  • 34
4

Thanks to come from in this 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());
Community
  • 1
  • 1
Semih Eker
  • 2,389
  • 1
  • 20
  • 29
2

The LocalDate doesn't seem to have this, but WeekFields (which is from the java-8 API) does (here). So you can do this:

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

This returns the value of the first day of week, starting from 1 as Monday, ending with 7 as Sunday.

Example of usage (in Kotlin), to get a new LocalDate that has the dayOfWeek be set, going backward in time instead of 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
}

Example 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

And here's a sample function to go forward in time to the target day of week:

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, weird thing is that I think the code behind the scenes of the new API actually uses Calendar class anyway...

In case you hate using the dayOfWeek as used for LocalDate (as I do), and you prefer the one used with Calendar, you can use these simple converters:

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
    }
}
android developer
  • 114,585
  • 152
  • 739
  • 1,270
1

As the correct Answer by Ray says, you can call with and pass the DayOfWeek enum.

Time zone

Note that time zone is crucial in determining the date of "today". At any moment the date varies by where you are standing on the globe.

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

If you do not specify a time zone, the JVM’s current default time zone is silently applied. Beware: That default can change at any moment during runtime! Better to specify your desired/expected time zone.

ZonedDateTime

You can apply a time zone (a ZoneId) to your LocalDate to get a ZonedDateTime representing the first moment of the week.

ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );
Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1
LocalDate.now( ZoneId.systemDefault()).with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) );

This return the first monday of current week (considering if today is monday)

0

With Joda Time, what do you think of

now.toString("EEEE", locale)
Labe
  • 1,262
  • 2
  • 20
  • 30
0
public void getWeekFromADateOfAMonth(){
    String date = "2019-01-02T18:25:43.511Z";
    TemporalField fieldISO = WeekFields.of(Locale.US).dayOfWeek();
    ZonedDateTime dateTime = ZonedDateTime.parse(date);

    int week = dateTime.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
    int weekYear = dateTime.get ( IsoFields.WEEK_BASED_YEAR );

    System.out.println ( "now: " + dateTime + " is week: " + week + " of weekYear: " + weekYear );

    int startDate = dateTime.with(fieldISO,1).getDayOfMonth();
    int endDate = dateTime.with(fieldISO,7).getDayOfMonth();

    String startMonth = String.valueOf(dateTime.with(fieldISO,1).getMonth());
    String endMonth = String.valueOf(dateTime.with(fieldISO,7).getMonth());
}