Johnny
Johnny

Reputation: 1569

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)) ));
    }
}

Upvotes: 2

Views: 140

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 340320

java.time

The Answer by Jon Skeet was correct in its time. Let's update for Java 8 and later, using the modern java.time classes defined in JSR 310.

Represent a date-only, without time-of-day and without time zone, with the LocalDate class.

LocalDate localDate = LocalDate.of( 2013 , Month.DECEMBER , 18 ) ;

Determine today's date. This requires a time zone (ZoneId) as the date varies around the globe by time zone.

ZoneId zoneId = ZoneId.of( "America/Edmonton" ) ;  // Or `ZoneId.systemDefault()`. 
LocalDate today = LocalDate.now( zoneId ) ;

Subtract two days.

LocalDate twoDaysBeforeToday = today.minusDays( 2 ) ;

Generate text in standard ISO 8601 format, YYYY-MM-DD.

String output = twoDaysBeforeToday.toString() ;

To generate text in localized format, use DateTimeFormatter.ofLocalizedDate.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1504122

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.

Upvotes: 7

Related Questions