jumps4fun
jumps4fun

Reputation: 4132

Why does my GregorianCalendar object return the wrong day of week?

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.

Upvotes: 5

Views: 12519

Answers (5)

Anonymous
Anonymous

Reputation: 86203

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

Upvotes: 3

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79005

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.

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499860

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.

Upvotes: 11

CS Pei
CS Pei

Reputation: 11047

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.

Upvotes: 1

ppeterka
ppeterka

Reputation: 20726

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...

Upvotes: 14

Related Questions