Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DAY_OF_WEEK always returns 7 in Java GregorianCalendar

So I want to do something with Java GregorianCalendar that seems to be going way harder than it should. I want to get the day of the week from the month and date. But it won't do that. I know that people often get the wrong answer to this because they don't know month is numbered from 0 while DAY_OF_WEEK is numbered from 1 (like here and here). But that's not my problem. My problem is that DAY_OF_WEEK always, always, returns 7, no matter what I set the date to. When I convert the GregorianCalendar to string, DAY_OF_WEEK appears as ?, even though I have set year, month, and dayOfMonth.

The code where this is happening:

GregorianCalendar theDate;

public ObservableDate(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second)
{
    theDate = new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
    theDate.setFirstDayOfWeek(GregorianCalendar.SUNDAY);
    System.out.println("DAY_OF_WEEK = "+theDate.DAY_OF_WEEK);
    System.out.println(theDate.toString());
}

The code that calls it:

    ObservableDate theDate = new ObservableDate(2001, 3, 24, 9, 00, 00);

Output:

DAY_OF_WEEK = 7
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2001,MONTH=3,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=24,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=9,HOUR_OF_DAY=9,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]

Any idea why this is happening?

like image 876
Displaced Hoser Avatar asked Oct 17 '14 13:10

Displaced Hoser


3 Answers

You are accessing the field constant instead of getting its' value. I believe you wanted to use something like,

System.out.println("DAY_OF_WEEK = " + theDate.get(Calendar.DAY_OF_WEEK));
like image 73
Elliott Frisch Avatar answered Oct 23 '22 11:10

Elliott Frisch


Your problem is you're accessing the constant DAY_OF_WEEK in the Calendar class (Calendar.DAY_OF_WEEK).

To properly get the day of week use the theDate variable's .get() method like so:

theDate.get(Calendar.DAY_OF_WEEK);
like image 24
sfedak Avatar answered Oct 23 '22 10:10

sfedak


tl;dr

For a smart DayOfWeek enum object.

ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , ZoneId.of( "Pacific/Auckland" ) )  // Moment as seen by people in a certain region (time zone).
             .getDayOfWeek()                                                         // Extract a `DayOfWeek` enum object to represent that day-of-week of that moment.

For a mere integer 1-7 for Monday-Sunday.

ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , ZoneId.of( "Pacific/Auckland" ) )
             .getDayOfWeek()
             .getValue()                                                             // Translate that `DayOfWeek` object into a mere integer 1-7 for Monday-Sunday.

java.time

The modern approach uses the java.time classes that supplant the troublesome old legacy date-time classes. Calendar is replaced by ZonedDateTime.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , z );

The DayOfWeek enum defines seven objects for each day of the week.

DayOfWeek dow = zdt.getDayOfWeek() ;  // Get `DayOfWeek` enum object representing this moment’s day-of-week.

You can ask the DayOfWeek to localize the name of the day.

I suggest using these DayOfWeek objects across your codebase rather than mere integer numbers. But if you insist, you can get a number. Unlike in GregorianCalendar the numbers have a fixed meaning and do not vary by locale. The meaning is 1-7 for Monday-Sunday, per the ISO 8601 standard.

int dowNumber = zdt.getDayOfWeek().getValue() ;  // 1-7 for Monday-Sunday per ISO 8601.

Immutable object

Note that java.time uses immutable objects. Rather than alter member variables on the object (“mutate”), calls to adjust the value results in a new object, leaving the original object unchanged.

ZonedDateTime zdtTomorrow = zdt.now( z ).plusDays( 1 ) ;  // Alterations result in a new object, leaving original intact. Known as *immutable objects*.

Time zone

You failed to specify a time zone in your constructor’s arguments and in the arguments passed to new GregorianCalendar. In such cases, the JVM’s current default time zone is implicitly assigned. That default can vary by machine, and can even change at any moment during runtime. Better to specify your desired/expected time zone.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

Octal number literals

Beware of your 00 literal value. A leading zero means octal base-8 number rather than decimal number in Java source code. You lucked-out as octal zero is also decimal zero.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 26
Basil Bourque Avatar answered Oct 23 '22 12:10

Basil Bourque