Search code examples
javadatesimpledateformat

Execute Date arithmetic without daylight saving adjustment


I want to parse a Date from a String in NYC timezone, add 1 day and then output string.

like:

  1. parse to date
  2. add 1 day
  3. output

The problem is, that when I parse a date during the adjustment for daylight saving, the day in step 1 already will have extra hour and when I add 1 day, the next day will have that extra hour which is wrong for the next day, due next Day is not the day when daylight saving adjustment happens.

example:

input date March 10 2am

parsed date: March 10 3am

add 1 day => March 11 3am // has to be March 11 2am

But if you parse directly March 11 2am, then it's correct:

input date March 11 2am

parsed date => March 11 2am

So, I need to parse a Date, add 1 day and only after that execute that smart adjustment:

input date March 10 2am

parsed date: March 10 2am //do not be smart here, still 2 am

add 1 day => March 11 2am // here you can be smart and adjust for daylight saving if needed

this code is incorrect and shows 7am March 11 instead of 6am

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

public class MainApp {

    public static void main(String[] args) {
        try {
            SimpleDateFormat in = new SimpleDateFormat("yyyyMMdd-HH.mm");
            in.setTimeZone(TimeZone.getTimeZone("America/New_York"));
            

            Date date = in.parse("20240310-02.00");
            
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            date = calendar.getTime();
            
            System.out.println(in.format(date)); // prints 20240311-03.00, but has to be 20240311-02.00
            
            //parse 11 march directly, works ok
            Date date2 = in.parse("20240311-02.00");
            System.out.println(in.format(date2)); // prints 20240311-02.00
            
            
        } catch (ParseException e) {e.printStackTrace();}       
    }
}

Solution

  • java.time

    I recommend you avoid using the outdated and error-prone java.util date/time API and do it using the modern date/time API, java.time.

    Your given date-time string does not have time zone information. Therefore, you should parse it to a LocalDateTime instance.

    Demo:

    public class Main {
        public static void main(String[] args) {
            String strDateTime = "20240310-02.00";
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuMMdd-HH.mm", Locale.ENGLISH);
            LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
            LocalDateTime nextDate = ldt.plusDays(1);
            System.out.println(ldt);
            System.out.println(nextDate);
    
            // In case you need to format nextDate in the input format
            System.out.println(nextDate.format(dtf));
        }
    }
    

    Output:

    2024-03-10T02:00
    2024-03-11T02:00
    20240311-02.00
    

    Online Demo

    You can convert a LocalDateTime into a ZonedDateTime by applying a ZoneId.

    ZoneId zoneId = ZoneId.of("America/New_York");
    ZonedDateTime zdt = ZonedDateTime.of(nextDate, zoneId);
    System.out.println(zdt);
    

    Output:

    2024-03-11T02:00-04:00[America/New_York]
    

    Learn about the modern date-time API from Trail: Date Time