4

I have the following java code to get the date of a specific week day:

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.set(Calendar.YEAR, 2010);
cal.set(Calendar.WEEK_OF_YEAR, 37); //week 37 of year 2010
cal.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
System.out.println("date="+sdf.format(cal.getTime()));

When I put this code in a main(String[] args)method, like the following:

import java.util.*;
import java.lang.*;
import java.text.SimpleDateFormat;

public class test{
    public static void main(String[] args){

    /** get dates from a known week ID **/
    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    cal.set(Calendar.YEAR, 2010);
    cal.set(Calendar.WEEK_OF_YEAR, 37);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
    System.out.println("date="+sdf.format(cal.getTime()));
    }
}

and run it, I get the correct result which is date=09/09/2010. There is no problem.

HOWEVER...

When I put this code in a function of a Class, like the following:

Public Class MyService{

  MyService(){}
  ...
  ...
  public String getDateOfWeekDay(int weekId, int year, int weekDay){
      //weekId = 37; year=2010; weekDay = Calendar.THURSDAY

      SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
      Calendar cal = Calendar.getInstance();
      cal.setTime(new Date());
      cal.set(Calendar.YEAR, year);
      cal.set(Calendar.WEEK_OF_YEAR, weekId);
      cal.set(Calendar.DAY_OF_WEEK, weekDay);

      //I am developing android app. so I use Log to printout
      logPrinter.println("date="+sdf.format(cal.getTime())); 

      return  sdf.format(cal.getTime());    
  }

}

in another class MainClass, MainClass will invoke this service function like following:

Public Class MainClass{

MyService myService = new MyService();
myService.getDateOfWeekDay(37,2010,Calendar.THURSDAY);

}

But the result returned is always the date of the current week's thursday (date=14/10/2010), not the Thursday of the week which I specified (week 37, year 2010, Thursday). WHY???? I use exactly the same java code to get the date of the specific week day, only used it in different ways, why the result is different???? I can not understand this...Anybody can explain to me??

andersoj
  • 22,406
  • 7
  • 62
  • 73
Mellon
  • 37,586
  • 78
  • 186
  • 264
  • 1
    Is it possible that the code in the question isn't the same as the code you're actually using? My suspicion would be that the order of the arguments to the function is different than the arguments you're supplying -- for example, your function expects year/week/day and you're supplying week/year/day. Obviously that's not the case in the question, so I'm left wondering if you used cut/paste or retyped and got it right here, but not in your actual code. – tvanfosson Oct 16 '10 at 14:27
  • Well, I have even tried to use constant variable inside my service function getDateOfWeekDay(int weekId, int year, int weekDay) with year=2010, weekId=37, weekDay=5 (thursday), but the result is still the date of current week's thursday. – Mellon Oct 16 '10 at 14:37
  • putting your code in another class shouldn't really change anything, but I tested it anyway. I don't think anyone else can reproduce your error. Can you repaste ALL of your code above, from both classes? – robert_x44 Oct 16 '10 at 14:52

4 Answers4

4

Yes, JodaTime is wonderful, but I'll bet you'd rather know what's wrong with your stuff.

Adding another JAR dependency might be a problem for a mobile device.

That method isn't good, IMO. The name is a misnomer, and it's doing too many things. You're creating a String, not a Date, and you're printing to a log. I'd recommend returning a Date and let clients worry about whether they want to turn it into a String. Logging is a cross-cutting concern.

Here's a class (and a JUnit test) that works. See what's different:

package util;

import java.util.Calendar;
import java.util.Date;

public class DateUtils
{
    public static Date getDateOfWeekDay(int weekId, int year, int weekDay)
    {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }

}

JUnit test:

package util;

import org.junit.Assert;
import org.junit.Test;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * DateUtilsTest
 * User: Michael
 * Date: 10/16/10
 * Time: 10:40 AM
 */
public class DateUtilsTest
{
    public static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("dd/MM/yyyy");

    @Test
    public void testNewYearsDayLastYear() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("1/1/2009");
        Date actual = DateUtils.getDateOfWeekDay(1, 2009, Calendar.THURSDAY);

        Assert.assertEquals(expected, actual);
    }

    @Test
    public void testTaxDay() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("15/4/2010");
        Date actual = DateUtils.getDateOfWeekDay(16, 2010, Calendar.THURSDAY);

        Assert.assertEquals(expected, actual);
    }

    @Test
    public void testGetDateOfWeekDay() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("16/10/2010");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(expected);
        int week = calendar.get(Calendar.WEEK_OF_YEAR);
        int year = calendar.get(Calendar.YEAR);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);

        Date actual = DateUtils.getDateOfWeekDay(week, year, dayOfWeek);

        Assert.assertEquals(expected, actual);
    }
}
duffymo
  • 305,152
  • 44
  • 369
  • 561
  • Heh, picking at my JodaTime suggestion, eh? I did (after knee-jerking to dis java.util.Calendar) provide a real answer. +1 for providing a JUnit test case. I'm moved to tears... ;-) – andersoj Oct 16 '10 at 14:51
  • 1
    I see you pulled out the `DateFormat` as a static field. That's my reaction too, but given the expected use cases, you should note that this makes the method non-threadsafe. Why a `DateFormat` can't be threadsafe (and why they don't retrofit it to be such) is beyond me. – andersoj Oct 16 '10 at 14:57
  • we know, we know, you like JodaTime :)P (so do I) – robert_x44 Oct 16 '10 at 15:01
  • You beat me with the real answer, andersoj (not initializing Calendar), but it's because I was writing that JUnit test and "loading new answers". Nice work. Good point about thread safety as well. I'd remove the DateFormat now. If the class isn't responsible for formatting anymore there's no need for it. – duffymo Oct 16 '10 at 15:15
3

It's becoming a rote answer around here, but: Use JodaTime or one of the alternatives. Investing precious cycles into understanding the JDK calendar API is throwing good money after bad.

Related on SO: Should I use native date/time; I see (now) you're doing Android development, which I can't speak to, but on SO: JodaTime on Android?

If you're insisting on JDK, I did try your code, with a slight modification. First, I'd eliminate the cal.setTime(new Date()) -- it's not doing anything, and it's confusing since it might (seem to) correlate to always getting a date around "now," since new Date() gives you now. However, in your code, it still should be overridden by the following setX calls.

class DateTest
{
    DateTest(){}

    public String getDateOfWeekDay(int weekId, int year, int weekDay){

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);

        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        System.out.println("date="+sdf.format(cal.getTime())); 

        return  sdf.format(cal.getTime());    
    }

    public static void main(String args[])
    {
      DateTest dt = new DateTest();
      for (int weekCount = 1; weekCount <= 53; weekCount++) {
        dt.getDateOfWeekDay(weekCount,2010,Calendar.THURSDAY);
      }
    }

}

And I get exactly what I expect:

date=31/12/2009 
date=07/01/2010 
...
date=23/12/2010 
date=30/12/2010

Do you see different?

Community
  • 1
  • 1
andersoj
  • 22,406
  • 7
  • 62
  • 73
  • Also related: http://stackoverflow.com/questions/3709870/how-do-libraries-in-different-programming-languages-handle-date-time-timestamp – andersoj Oct 16 '10 at 15:52
1
public class CalendarTest {

    public static String getDateOfWeekDay(int weekId, int year, int weekDay) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        return sdf.format(cal.getTime());
    }

    public static void main(String[] args) {
        String someDay = getDateOfWeekDay(37,2010,Calendar.THURSDAY);
        System.out.println(someDay);
    }

}

Outputs 16/09/2010 As does

public class CalendarTest {
    public static void main(String[] args) {
        MyService s = new MyService();
        String someDay = s.getDateOfWeekDay(37, 2010, Calendar.THURSDAY);
        System.out.println(someDay);
    }
}

class MyService {
    public String getDateOfWeekDay(int weekId, int year, int weekDay) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        return sdf.format(cal.getTime());
    }
}
RedGrittyBrick
  • 3,827
  • 1
  • 30
  • 51
  • As I said, by using the code in this way, there is no problem, the problem comes when I put the code in a function of one class, and another class invoke this function from the instance of the first class. – Mellon Oct 16 '10 at 14:47
  • Ok, now I am getting more confused. I made the two classes (MyService.java and CalendarTest.java), and compiled them, after I run CalendarTest, the result is correct. But why in my android project, it always give the date of current week's thursday?? – Mellon Oct 16 '10 at 14:57
  • The Javadocs for Calendar will probably throw som light on this, there are traps for the unwary (see Javadoc quote in edit above) – RedGrittyBrick Oct 16 '10 at 15:04
0

Well, because these answers are less about answering your actual question than recommending to use JodaTime, I'll throw in my recommendation against JodaTime.

Date/Calendar as well as JodaTime have significant design flaws (quoting the authors) and if you plan to do work with time and date, use JSR-310.

JSR-310 is the replacement for both Date/Calendar and JodaTime which is more consistent and works better than both. There are considerations to include JSR-310 in Java 7.

Regardless if that works out or not, it is possible to use it today. It is just a jar file like JodaTime.

The benefits are:

  • Fixes the remaining problems of JodaTime
  • Consistent library design
  • Better naming conventions
  • Easier to read API
  • Everything immutable
  • Better usability from other programming languages

If you are interested in this topic:

Community
  • 1
  • 1
soc
  • 27,983
  • 20
  • 111
  • 215