0

I am getting inputDate as "2020-09-08T20:06:19-0400" ;I am following below approach to add 90 days to it and final format should be in "yyyy-MM-dd"?

     SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZ");
                     Date newInputDate= addDays(inputFormat.parse(inputDate), 90);
        
              System.out.println("newInputDate:"+newInputDate);
//getting newInputDate as Tue Dec 08 05:36:19 IST 2020 so I have to change it to required format i.e."yyyy-MM-dd"
                            
  String    endDate= dateFormater(newInputDate.toString() , "yyyy-MM-dd" , "E MMM dd HH:mm:ss Z yyyy");

System.out.println("endDate:"+endDate);

private static Date addDays(Date date, int days) {
            GregorianCalendar cal = new GregorianCalendar();
            cal.setTime(date);
            cal.add(Calendar.DATE, days);
                    
            return cal.getTime();
        }
        
        private static String dateFormater(String dateFromJSON, String expectedFormat, String oldFormat) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(oldFormat);
            Date date = null;
            String convertedDate = null;
            try {
                date = dateFormat.parse(dateFromJSON);
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(expectedFormat);
                convertedDate = simpleDateFormat.format(date);
            } catch (Exception e) {
                e.printStackTrace();
                writeToLog("dateFormater Exception :" + e.getMessage());
            }
    
            return convertedDate;
        }
user739115
  • 1,117
  • 5
  • 20
  • 41

4 Answers4

4

I recommend you do it using the modern date-time API.

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String dateTimeStr = "2020-09-08T20:06:19-0400";
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH);
        OffsetDateTime odt = OffsetDateTime.parse(dateTimeStr, inputFormatter);
        System.out.println("Given date time: " + odt);

        // 90 days later
        OffsetDateTime odt90DaysLater = odt.plusDays(90);
        System.out.println("90 days later (default format): " + odt90DaysLater);
        // In ISO_LOCAL_DATE format
        System.out.println("90 days later (yyyy-MM-dd): " + odt90DaysLater.toLocalDate());
        // Or this
        System.out.println("90 days later (yyyy-MM-dd): " + odt90DaysLater.format(DateTimeFormatter.ISO_LOCAL_DATE));
    }
}

Output:

Given date time: 2020-09-08T20:06:19-04:00
90 days later (default format): 2020-12-07T20:06:19-04:00
90 days later (yyyy-MM-dd): 2020-12-07
90 days later (yyyy-MM-dd): 2020-12-07

Learn more about the modern date-time API at Trail: Date Time.

If you are doing it for your Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Using legacy API:

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

public class Main {
    public static void main(String[] args) throws ParseException {
        String dateTimeStr = "2020-09-08T20:06:19-0400";
        DateFormat sdfInput = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZ", Locale.ENGLISH);
        sdfInput.setTimeZone(TimeZone.getTimeZone("GMT-4"));
        Date date = sdfInput.parse(dateTimeStr);
        System.out.println("Given date time: " + sdfInput.format(date));

        // 90 days later
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, 90);
        DateFormat sdfOutput = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
        sdfOutput.setTimeZone(TimeZone.getTimeZone("GMT-4"));
        System.out.println("90 days later: " + sdfOutput.format(calendar.getTime()));
    }
}

Output:

Given date time: 2020-09-08T20:06:19-0400
90 days later: 2020-12-07

Recommendation: The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • I didnt get.Cant I use modern date-time API? – user739115 Oct 28 '20 at 08:02
  • 1
    @user739115 - You should strive to use the modern date-time API. As mentioned in the answer, the legacy date-time API is error-prone and therefore you should try avoiding the legacy date-time API. – Arvind Kumar Avinash Oct 28 '20 at 08:03
  • I was Confused with this statement by Ole "Also you get December 8 when adding 90 days, whereas both answers seem to get December 7. Which is correct? Or more precisely: which do you want and why?" – user739115 Oct 28 '20 at 08:06
  • The results that you see in this answer are correct but Ole has mentioned about the comment that you have put in your question. You have mentioned, `//getting newInputDate as Tue Dec 08 05:36:19 IST 2020 so I have to change it to required format i.e."yyyy-MM-dd"` in your question and his comment is pointing to it. In short, he wants to know whether you want to get the result in IST or at the zone-offset of -0400`. – Arvind Kumar Avinash Oct 28 '20 at 08:15
  • My question was a disguised time zone question (sorry that it was unclear). At 90 days after the point in time denoted by your string it was December 8 in India (IST) and December 7 at offset -04:00, the offset in your string. Which time zone or offset do you want for the result? @user739115 – Ole V.V. Oct 28 '20 at 16:49
  • EST/EDT Timezone. – user739115 Oct 29 '20 at 03:12
  • Since you want North American Eastern Time, 2020-12-07 is correct. That is, if the input string is always in North American Eastern Time (-0400 in summer, -0500 during standard time), then the answers will give you the correct output. – Ole V.V. Oct 29 '20 at 05:59
3

Use java.time package can make it easier.

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

The code below is self-explaining:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
OffsetDateTime offsetDateTime = OffsetDateTime.parse("2020-09-08T20:06:19-0400", formatter);
OffsetDateTime later = offsetDateTime.plusDays(90);
LocalDate localDate = later.toLocalDate();
String output = localDate.format(DateTimeFormatter.ISO_DATE);
System.out.println(output);
xingbin
  • 27,410
  • 9
  • 53
  • 103
  • 1
    You do not need to use `DateTimeFormatter.ISO_DATE` if you are using `later.toLocalDate()`. The `LocalDate#toString` gives you result in `yyyy-MM-dd` by default. – Arvind Kumar Avinash Oct 28 '20 at 04:07
  • 2
    @ArvindKumarAvinash is correct. Or the other way around: you don’t need to convert to `LocalDate` first. Just do `later.format(DateTimeFormatter.ISO_LOCAL_DATE)` to get the desired `2020-12-07`. – Ole V.V. Oct 28 '20 at 05:58
1

Some other alternatives with Zoned Java Time, plusing days

Alternative ZonedDateTime:

ZonedDateTime.parse("2020-09-08T20:06:19-0400", dtfInput).plusDays(90).format(DateTimeFormatter.ISO_LOCAL_DATE);

Alternative OffsetDateTime:

OffsetDateTime.parse("2020-09-08T20:06:19-0400", dtfInput).plusDays(90).format(DateTimeFormatter.ISO_LOCAL_DATE);

Where variable 'dtfInput' is:

DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH);

Alternatives in testbench:

public static void main(String[] args) {
    String input = "2020-09-08T20:06:19-0400";
    DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH);;
    String dateStampFromZoned = ZonedDateTime.parse(input, dtfInput).plusDays(90).format(DateTimeFormatter.ISO_LOCAL_DATE);
    String dateStampFromOffset = OffsetDateTime.parse(input, dtfInput).plusDays(90).format(DateTimeFormatter.ISO_LOCAL_DATE);
    System.out.printf("90 days later starting from date time '%s', %nprinted as only date in format 'yyyy-MM-dd':%n%n", input);
    System.out.println("Date stamp from ZonedDateTime: " + dateStampFromZoned);
    System.out.println("Date stamp from OffsetDateTime: " + dateStampFromOffset);
}

Output:

90 days later starting from date time '2020-09-08T20:06:19-0400',
printed as only date in format 'yyyy-MM-dd':

Date stamp from ZonedDateTime: 2020-12-07
Date stamp from OffsetDateTime: 2020-12-07

Note: java.time was introduced in Java 8

More information about DateTimeFormatter.ISO_LOCAL_DATE and other 'Predefined Formatters' can be found at:

DocsApiJavaTimeDateTimeFormatter

Note also: If the inputDateTime '2020-09-08T20:06:19-0400' was written as ISO_OFFSET_DATE_TIME, a predefined formatter, then we do not need to specify the format for inputDateTime, see example below:

ZonedDateTime.parse("2020-09-08T20:06:19-04:00").plusDays(90).format(DateTimeFormatter.ISO_LOCAL_DATE);

Only a semicolon in the zone-offset format differs, where inputDateTime is written as "2020-09-08T20:06:19-0400" and ISO_OFFSET_DATE_TIME is written as "2020-09-08T20:06:19-04:00".

DigitShifter
  • 801
  • 5
  • 12
0

You’ve got to specify desired time zone

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .appendOffset("+HHMM", "Z")
            .toFormatter();
    ZoneId zone = ZoneId.of("America/Toronto");
    
    String inputDateTimeString = "2020-09-08T20:06:19-0400";
    
    OffsetDateTime dateTime = OffsetDateTime.parse(inputDateTimeString, formatter);
    ZonedDateTime easternTime = dateTime.atZoneSameInstant(zone);
    ZonedDateTime ninetyDaysLater = easternTime.plusDays(90);
    String endDateString = ninetyDaysLater.format(DateTimeFormatter.ISO_LOCAL_DATE);
    
    System.out.println(endDateString);

Output is the same as you get from the other answers and is correct for North American Eatern Time:

2020-12-07

Don’t mind my formatter. It’s longer than the formatters in the other answers because I prefer to reuse the built-in formatters. A potential advantage is I can accept fraction of second too, otherwise my formatter works the same as the others.

Corner case: summer time transistions

While the other answers do give correct output, they get there through a path that isn’t quite correct. Assume your string was in the first hour of the day:

    String inputDateTimeString = "2020-09-08T00:06:19-0400";

Now 90 days later summer time (DST) in Eastern Time has ended. We’ve gone from EDT to EST. So the date and time are 2020-12-07T00:06:19-05:00. If you ignore the time zone, you will instead get 2020-12-07T00:06:19-04:00, which in America/Toronto time zone is 2020-12-06T23:06:19-05:00, that is, on the day before. So the other answers through a combination of incorrect time zone and incorrect time get to print the correct date.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161