Search code examples
javadatesimpledateformat

Getting a correct date by adding substracting a number of milliseconds


Today is 18/12/2013.

I was testing this program where I wanted get another date by adding/substracting a number of milliseconds from System.currentMillis(). It works well when I shift the date in decembre but it doesn't work correctly for some similar values. For example the following code gives me 2013 12 20 as the result! I wonder, no I still wonder how it could be possible! or I'm making a mistake?

public class CreateDirFiles {


    public static final String PLOG_DIR = "ProductLog";

    private SimpleDateFormat dateFormatter  = new SimpleDateFormat();

    public CreateDirFiles() {
    }

    public void createDayDir(Date date){
        dateFormatter.applyPattern("YYYY");
        String year = dateFormatter.format(date);
        dateFormatter.applyPattern("MM");
        String month = dateFormatter.format(date);
        dateFormatter.applyPattern("dd");
        String day = dateFormatter.format(date);
        System.out.printf("%s %s %s\n", year, month, day);
    }

    public static void main(String... args){
        CreateDirFiles dfc = new CreateDirFiles();
        dfc.createDayDir(new Date(System.currentTimeMillis() -
                ((long)( 48 * 24 * 3600 * 1000)) ));
    }
}

Solution

  • This is the problem:

    ((long)( 48 * 24 * 3600 * 1000))
    

    That's doing all the arithmetic in 32 bits, and then converting the (now truncated, as the result is too large for an int) result to a long. You want:

    48L * 24 * 3600 * 1000
    

    where the L suffix means that it'll use a long for the value 48.

    However, you really don't want to do this at all - you want to use Joda Time which is a much nicer API for date/time work. You really don't want to have to mess around with the low level stuff at all.

    LocalDate date = ...;
    LocalDate twoDaysLater = date.minusDays(48);
    

    If you really want to stick with the built-in API, then use Calendar. At the very least use the TimeUnit enum, which will allow:

    long millisFor48Days = TimeUnit.DAYS.toMillis(48);
    

    You also need to consider the time zone - while "today" may be the 18th of December for you, it isn't elsewhere in the world.