7 Replies Latest reply: Sep 9, 2007 10:36 PM by 807592 RSS

    Calendar woes

    807587
      I am running into a situation that I am having trouble reproducing.

      If I set a calendar field like this:

      calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));

      ...and then print out the results like this:

      System.out.println(Calendar.getTime());

      ...The output shows no change. However, asking the calendar for the value of that field, like this:

      calendar.get(Calendar.DAY_OF_MONTH);

      ...correctly returns 1.

      I cannot reproduce this in isolation; a JUnit test case that performs these steps seems to do OK. Has anyone ever seen this?

      Expecting the answer no,
      Laird
        • 1. Re: Calendar woes
          807587
          Reproduced it. Here is a JUnit test that reproduces the bug:
          import java.util.Calendar;
          import java.util.Date;
          import java.util.TimeZone;
          
          import junit.framework.TestCase;
          
          public class TestCaseCalendarBug extends TestCase {
          
            public TestCaseCalendarBug(final String name) {
              super(name);
            }
          
            public void testRoundDown() throws Exception {
              final TimeZone utc = TimeZone.getTimeZone("UTC");
              assertNotNull(utc);
              assertTrue(!utc.useDaylightTime());
          
              Calendar calendar = Calendar.getInstance(utc);
              assertNotNull(calendar);
              calendar.set(2005, Calendar.JULY, 19, 12, 39, 2);
              assertEquals(2005, calendar.get(Calendar.YEAR));
              assertEquals(Calendar.JULY, calendar.get(Calendar.MONTH));
              assertEquals(19, calendar.get(Calendar.DAY_OF_MONTH));
              assertEquals(12, calendar.get(Calendar.HOUR_OF_DAY));
              assertEquals(39, calendar.get(Calendar.MINUTE));
              assertEquals(2, calendar.get(Calendar.SECOND));
          
              // Set the day to the first of the month.
              calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
              assertEquals(Calendar.JULY, calendar.get(Calendar.MONTH));
              assertEquals(1, calendar.get(Calendar.DAY_OF_MONTH));
              System.out.println("Rounded day of month to " + calendar.getActualMinimum(Calendar.DAY_OF_MONTH) + ": " + calendar.getTime());
          
              // Set the hour to 0 in 24 hour time on the current day (the first of the month).
              calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
              assertEquals(Calendar.JULY, calendar.get(Calendar.MONTH));
              assertEquals(1, calendar.get(Calendar.DAY_OF_MONTH));
              assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY));
              System.out.println("Rounded hour of day to " + calendar.getActualMinimum(Calendar.HOUR_OF_DAY) + ": " + calendar.getTime() + "; note that the month has become June, and the hour is 20!");
              System.out.println("But this is only in the string representation (and the Date that produced it), because all of our assertions have proved true up to this point.");
              System.out.println("So what the calendar says is its HOUR_OF_DAY, for example, does not jive with what comes back from Calendar.getTime().");
          
              // Here's where the fun starts.
              final Date date = calendar.getTime();
              assertNotNull(date);
              final String dateString = String.valueOf(date);
              assertNotNull(dateString);
              assertTrue(dateString.startsWith("Fri Jul 01 00:")); // XXX fails; uncomment to see that the rest is fine
          
              calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
              assertEquals(Calendar.JULY, calendar.get(Calendar.MONTH));
              assertEquals(1, calendar.get(Calendar.DAY_OF_MONTH));
              assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY));
              assertEquals(0, calendar.get(Calendar.MINUTE));
              System.out.println("Rounded minute of hour to " + calendar.getActualMinimum(Calendar.MINUTE) + ": " + calendar.getTime() + " " + calendar.get(Calendar.MINUTE));
          
              calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
              assertEquals(Calendar.JULY, calendar.get(Calendar.MONTH));
              assertEquals(1, calendar.get(Calendar.DAY_OF_MONTH));
              assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY));
              assertEquals(0, calendar.get(Calendar.MINUTE));
              assertEquals(0, calendar.get(Calendar.SECOND));
              System.out.println("Rounded second of minute to " + calendar.getActualMinimum(Calendar.SECOND) + ": " + calendar.getTime() + " " + calendar.get(Calendar.SECOND));
          
            }
          
          }
          • 2. Re: Calendar woes
            DrClap
            Don't know... you might want to have a look at the part of the API documentation for Calendar where it says

            "set(f, value) changes field f to value. In addition, it sets an internal member variable to indicate that field f has been changed. Although field f is changed immediately, the calendar's milliseconds is not recomputed until the next call to get(), getTime(), or getTimeInMillis() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations."

            (Nowadays we'd classify this as an annoying micro-optimization but maybe back in 1997 when "Java was slow" it actually noticeably speeded things up.)

            Anyway, my guess is that your question is related to that.
            • 3. Re: Calendar woes
              807587
              When you use:
              System.out.println(calendar.getTime());
              it uses local timezone to display the calendar. Therefore, it is showing June 30. From the fact that you say you get Hour = 20, I'm guessing your default timezone is Eastern timezone U.S., which is currently Eastern Daylight Time, four hours behind UTC.

              If you format your times with a SimpleDateFormat set to UTC timezone, you should get the answers you expect (everything stays in July).
              • 4. Re: Calendar woes
                DrClap
                If you format your times with a SimpleDateFormat set
                to UTC timezone, you should get the answers you
                expect (everything stays in July).
                Better guess than mine. I didn't notice the UTC gotcha.
                • 5. Re: Calendar woes
                  807587
                  When you use:
                  System.out.println(calendar.getTime());
                  it
                  uses local timezone to display the calendar.
                  Therefore, it is showing June 30. From the fact
                  t that you say you get Hour = 20, I'm guessing your
                  default timezone is Eastern timezone U.S., which is
                  currently Eastern Daylight Time, four hours behind
                  UTC.
                  Ahhhh, thank you.
                  • 6. Re: Calendar woes
                    807587
                    You are welcome. I'm on Eastern time, so I got the same output you did. :)
                    • 7. Re: Calendar woes
                      807592
                      i have here a downloaded calendar
                      now i have a separate program that have inputs on dates

                      for example:

                      input: september 15 2007

                      how can i locate using this code thanx a lot....

                      <%@page session="true" import="java.util.*" %>
                      <%
                      // Global Vars
                      int action = 0;  // incoming request for moving calendar up(1) down(0) for month
                      int currYear = 0; // if it is not retrieved from incoming URL (month=) then it is set to current year
                      int currMonth = 0; // same as year
                      String boxSize = "70";  // how big to make the box for the calendar
                      
                      //build 2 calendars
                      
                      Calendar c = Calendar.getInstance();
                      Calendar cal = Calendar.getInstance();
                      
                           if (request.getParameter("action") == null) // Check to see if we should set the year and month to the current
                           {
                                currMonth = c.get(c.MONTH);
                                currYear = c.get(c.YEAR);
                                cal.set(currYear, currMonth,1);
                           }
                      
                           else
                           {
                                if (!(request.getParameter("action") == null)) // Hove the calendar up or down in this if block
                                {
                                     currMonth = Integer.parseInt(request.getParameter("month"));
                                     currYear = Integer.parseInt(request.getParameter("year"));
                      
                                          if (Integer.parseInt( request.getParameter("action")) == 1 )
                                          {
                                               cal.set(currYear, currMonth, 1);
                                               cal.add(cal.MONTH, 1);
                                               currMonth = cal.get(cal.MONTH);
                                               currYear = cal.get(cal.YEAR);
                                          }
                                          else
                                          {
                                               cal.set(currYear, currMonth ,1);
                                               cal.add(cal.MONTH, -1);
                                               currMonth = cal.get(cal.MONTH);
                                               currYear = cal.get(cal.YEAR);
                                          }
                                }
                           } 
                      %>
                      
                      <%!
                          public boolean isDate(int m, int d, int y) // This method is used to check for a VALID date
                          {
                              m -= 1;
                              Calendar c = Calendar.getInstance();
                              c.setLenient(false);
                      
                              try
                              {
                                      c.set(y,m,d);
                                      Date dt = c.getTime();
                              }
                                catch (IllegalArgumentException e)
                              {
                                      return false;
                      
                              }
                                      return true;
                          }
                      %>
                      <%!
                         public String getDateName (int monthNumber) // This method is used to quickly return the proper name of a month
                         {
                                String strReturn = "";
                                switch (monthNumber)
                                { 
                           case 0:
                                strReturn = "January";
                                break;
                           case 1:
                                strReturn = "February";
                                break;
                           case 2:
                                strReturn = "March";
                                break;
                           case 3:
                                strReturn = "April";
                                break;
                           case 4:
                                strReturn = "May";
                                break;
                           case 5:
                                strReturn = "June";
                                break;
                           case 6:
                                strReturn = "July";
                                break;
                           case 7:
                                strReturn = "August";
                                break;
                           case 8:
                                strReturn = "September";
                                break;
                           case 9:
                                strReturn = "October";
                                break;
                           case 10:
                                strReturn = "November";
                                break;
                           case 11:
                                strReturn = "December";
                                break;
                           }
                           return strReturn;
                          }
                      %>
                      <html>
                      </body bgcolor='white'>
                      <table border='1' width='519' celpadding='0' cellspacing='0'>
                        <tr>
                           <td width='150' align='right' valign='middle'><a href="cal.jsp?month=<%=currMonth%>&year=<%=currYear%>&action=0"><font size="1">Previous Month</font></a></td>
                           <td width='260' align='center' valign='middle'><b><%=getDateName (cal.get(cal.MONTH)) + " " + cal.get(cal.YEAR)%></b></td>
                           <td width='173' align='left' valign='middle'><a href="cal.jsp?month=<%=currMonth%>&year=<%=currYear%>&action=1"><font size="1">Next Month</font></a></td>
                        </tr>
                           </table>
                      <table border="0" width="520" bordercolorlight="#C0C0C0" bordercolordark="#808080" style="border-collapse: collapse" bordercolor="#111111" cellpadding="0" cellspacing="0">
                        <td width="100%">
                          <table border="2" width="519" bordercolorlight="#C0C0C0" bordercolordark="#000000" style="border-collapse: collapse" bordercolor="#000000" cellpadding="0" cellspacing="0" bgcolor="#DFDCD8">
                             <tr>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Sun</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Mon</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Tues</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                   <font color="#FFFFFF"><b>Wed</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Thurs</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Fri</b></font></td>
                                    <td width="<%=boxSize%>" align="center" nowrap bordercolor="#666666" bgcolor="#666666">
                                    <font color="#FFFFFF"><b>Sat</b></font></td>
                             </tr>
                      <%
                      
                      //'Calendar loop
                      
                      
                           int currDay;
                           String todayColor;
                           int count = 1;
                           int dispDay = 1;
                      
                      
                           for (int w = 1; w < 7; w++)
                           {
                      %>
                             <tr>
                      <% 
                                  for (int d = 1; d < 8; d++)
                                {
                                     if (! (count >= cal.get(c.DAY_OF_WEEK)))
                                     { 
                      
                      %>
                                <td width="<%=boxSize%>" height="<%=boxSize%>" valign="top" align="left"> </td>
                      <%
                                          count += 1;
                                     } 
                                     else
                                     {
                      
                                          if (isDate ( currMonth + 1, dispDay, currYear) ) // use the isDate method
                                          { 
                      
                                               if ( dispDay == c.get(c.DAY_OF_MONTH) && c.get(c.MONTH) == cal.get(cal.MONTH) && c.get(c.YEAR) == cal.get(cal.YEAR)) // Here we check to see if the current day is today
                                                  {
                                                         todayColor = "#6C7EAA";
                                                    }
                                                    else
                                                    {
                                                         todayColor = "#ffffff";
                                                    }
                      %> 
                                <td bgcolor ="<%=todayColor%>" width="<%=boxSize%>" align="left" height="<%=boxSize%>" valign="top"><%=dispDay%><br>
                                </td>
                      <%
                                               count += 1;
                                               dispDay += 1;
                                          }
                                          else
                                          {
                      %>
                                <td width="<%=boxSize%>" align="left" height="<%=boxSize%>" valign="top"> </td>
                      <%
                                          } 
                                     }
                      
                             } 
                      %>
                             </tr> 
                      <% 
                      }
                      %>
                      </table>
                      </td>
                      <tr><td>
                      </table>
                      </body>
                      </html>