4

My issue is seemingly extremely simple. I make a calendar graphic user interface, from a GregorianCalendar object, and uses it's methods to calculate the correct number of days in the different months, and the different date's corresponding weekdays.

But the weekdays are consistentyl one day off. The Calendar claims that the 1st of July 2013 is a '2', which in my part of the world means tuesday. It should have been a '1' for Monday. "Easy!" i think, and put in the line: c.setFirstDayOfWeek(Calendar.MONDAY); But no reaction is given.

So I search stackoverflow for an answer, but everyone with my problem seem to have forgotten that January is 0, and not 1. I haven't. So now I am stuck.

As a simplifyed code, I have made a very short code piece, with it's corresponding output:

    GregorianCalendar c = new GregorianCalendar();
    c.setFirstDayOfWeek(Calendar.MONDAY);
    c.set(Calendar.MONTH, 6);
    c.set(Calendar.DAY_OF_MONTH, 1);
    c.set(Calendar.YEAR, 2013);

    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(sdf.format(c.getTime()));
    System.out.println(c.get(Calendar.DAY_OF_WEEK));

and the output is:

01-07-2013

2

I refuse to put in a "-1" in my code, to wrongly correct the symptoms of what is obviously a mistake. Help is appreciated.

jumps4fun
  • 3,994
  • 10
  • 50
  • 96
  • 4
    2 is Monday... 1 is Sunday... Also, setFirstDayOfWeek, according to the doc: `The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year`. There is no `obvious mistake` in there. Just localization issue... – ppeterka Oct 02 '13 at 11:52
  • Thanks. As of now, I've stopped trying to set Monday as the first day of the week. It just seemed simpler to edit my other code to expect that sunday is number 1, no matter how illogical it appears to me. Thanks for telling me that my mistake was my interpretation of the setFirstDayOfWeek()-method. That could have been hard to find on my own. I wish I could accept it as an answer, but it seems like it is only posted as a comment. – jumps4fun Oct 02 '13 at 12:10
  • For any new readers to this question I recommend you don’t use `GregorianCalendar`, `Calendar` and `SimpleDateFormat`. Those classes are poorly designed and long outdated (the last in particular notoriously troublesome). Instead use `LocalDate`, `WeekFields` and `DateTimeFormatter`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Aug 14 '21 at 18:35
  • *I refuse to put in a "-1"*. Also subtracting 1 won’t help for 1 = Sunday because you’ll get 0 where you want 7. – Ole V.V. Aug 18 '21 at 20:39

5 Answers5

13

Yes, date handling in Java is problematic...

  • Months start from 0 (JANUARY)
  • days of week start from SUNDAY being 1, SATURDAY being seven (Ideone fiddle)
  • c.setFirstDayOfWeek(Calendar.MONDAY); is a bit different than what the name suggests

    The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year

You can get out of troubles by always using the constants defined in the Calendar class, and not even trying to deduce any meaning from the numerical representations of those constants, or the results returned by the Calendar.get(int) method...

ppeterka
  • 20,583
  • 6
  • 63
  • 78
  • This is also a really good answer +1. I have been working with Calendar objects for the better part of six months now, and I have learned a lot, thanks to guys like you. I love the wording of the final paragraph in your answer. – jumps4fun Apr 01 '14 at 12:39
11

I refuse to put in a "-1" in my code, to wrongly correct the symptoms of what is obviously a mistake.

The mistake is your assumption that Calendar.get(Calendar.DAY_OF_WEEK) is localized. It isn't. The mapping between day-of-week and number is fixed; use Calendar.getFirstDayOfWeek() to determine the human understanding of "first day of the week" if you need to; I'd be surprised if you really wanted to show a user "2" anyway... surely you'd want to show them the name of the day of the week.

Any calculations involving the start of the week should use getFirstDayOfWeek though.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That is exactly what I managed to get out of an earlier comment. Awesome answer! Thanks. And as an extra comment; I parsed the integer value to another WeekDay enum value, so that I could get the name of the weekday in my mother tongue. Thanks again. – jumps4fun Oct 02 '13 at 12:14
  • @KjetilNordin: Ideally, use `DateFormatSymbols.getInstance(locale).getWeekdays()` for that. – Jon Skeet Oct 02 '13 at 12:41
  • I also believe that the users don’t want to see `1` for Monday. But they may want a month calendar where each day is offset an amount proportional to the number of the day of the week, for example. `getFirstDayOfWeek()` helps partially at best. java.time, the modern Java date and time API, gives clearly better support for it than `Calendar` does. – Ole V.V. Aug 14 '21 at 20:14
2

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

The first day of the week is Locale dependent

Demo:

import java.time.format.TextStyle;
import java.time.temporal.WeekFields;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // ############## First day of week ##############
        System.out.println(WeekFields.of(Locale.UK).getFirstDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
        System.out.println(WeekFields.of(Locale.US).getFirstDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
    }
}

Output:

Monday
Sunday

ONLINE DEMO

How to get the day-of-week?

import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2013, Month.JULY, 1);
        System.out.println(date);

        // ############ Day of week ############
        System.out.println(date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
        // Alternatively,
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEEE", Locale.ENGLISH);
        System.out.println(date.format(dtf));
    }
}

Output on my system in Europe/London timezone:

2013-07-01
Monday
Monday

ONLINE DEMO

Learn more about the modern Date-Time API* from Trail: Date Time.

What went wrong with your code and expectation?

  • The thing that went wrong with your expectation is that you assumed c.get(Calendar.DAY_OF_WEEK) would give you the first day of the week whereas it returns the value representing MONDAY because it was Monday on the 1st Jul 2013.

  • The thing that is wrong with your code is the use of Y (Week year) instead of y (Year). Check this discussion to learn more about this difference.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
2

java.time

I recommend that you use java.time, the modern Java date and time API, for your date work. Arvind Kumar Avinash has already in an answer shown a nice application of it (+1).

The way I understand your question you want Monday to be the first day of the week, and you want to know which number day of the week a certain date is (e.g., July 1, 2013). Monday = 1, Tuesday = 2 and so forth up to Sunday = 7.

    LocalDate ld = LocalDate.of(2013, Month.JULY, 1);
    
    // Monday is first day of week; which number day of the week is ld then?
    int numberDayOfTheWeek = ld.get(WeekFields.ISO.dayOfWeek()); // 1 through 7
    System.out.println(numberDayOfTheWeek);

Output is:

1

Having Monday be the first day of the week agrees with ISO 8601, the international standard for dates and times. So the built-in WeekFields.ISO uses this numbering. WeekFields.ISO.dayOfWeek() gives us a TemporalField that we then use for querying the LocalDate object about its day of the week.

Instead of WeekFields.ISO we may use WeekFields.of(DayOfWeek.MONDAY, 1) to specify that Monday is the first day of the week. The second argument to of() is the minimal number of days in the first week (of the year or month) form 1 through 7, which we don’t use here, so it doesn’t matter which number we use.

Link

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
1

This is one of the caveats in Java,

DAY_OF_WEEK,

This field takes values SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, and SATURDAY.

When your program prints 2, it's telling you that the day of week is MONDAY. This constant value has nothing to do with the beginning of the week. It does coincidentally happen to be the same as the day of the week if the first day of the week is SUNDAY - but it doesn't change if the first day of the week is redefined.

CS Pei
  • 10,869
  • 1
  • 27
  • 46