0

I have a string in data format, apr 17,2016.

For instance, I would like to go back 1 day, so I would like to get apr 16,2016.

How can I do that?

Please note, it could be mar 1,2016 as well so the replacement at index cannot work.

catch23
  • 17,519
  • 42
  • 144
  • 217
brobee
  • 231
  • 1
  • 5
  • 25
  • 6
    You parse the value as a date/time (e.g. using `java.time`) and then you use the appropriate date manipulation methods. You *don't* try to do it all with string operations. – Jon Skeet Apr 06 '17 at 18:14
  • I got this as a String, so I HAVE to use it. (Test automation purpose, not development. It was not clear, but doesn't matter, my question was accurate) – brobee Apr 06 '17 at 18:29
  • 2
    You have to *use* it, sure. That's what the "You parse the value" part was about. That doesn't mean you have to do everything with string operations. (That's what both of the current answers do, and it's a really bad idea. Why reinvent the wheel when there are multiple ways of parsing dates in Java already?) – Jon Skeet Apr 06 '17 at 18:31
  • I need to check this out, I'm not familiar with java.time. Thanks. You think it was easier than String operations? I always will get string and I need to parse the value and vica versa to get a string at the end as well. It is not to expensive? – brobee Apr 06 '17 at 18:36
  • 1
    Well do you have well-defined performance constraints? You haven't mentioned those yet. I would definitely start with the simple, clear code that tries to do work in the appropriate domain - and "get the previous day" is definitely work in the date/time domain rather than the string domain. – Jon Skeet Apr 06 '17 at 18:37
  • No, there is no any performance constraints, just I guessed that it would be too expensive. I would like to use it for selenium framework and I want to avoid any unnecessary complication within my test. Anyway, I got your point and according to the examples, it would be the best option. – brobee Apr 06 '17 at 19:40
  • I'm going trough all of the answers and mark the best. – brobee Apr 06 '17 at 19:42
  • What locale or human language are you expecting? The initial lowercase letter for month name is not appropriate to US English, so I am asking. – Basil Bourque Apr 07 '17 at 04:39

7 Answers7

2

You can use Java 8 for this.

Just convert to LocalDate. It has flexible API for many reasons.

Here is code snippet:

public static void main(String[] args) throws ParseException {
    String dateStr = "apr 17,2016";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd,uuuu");

    // convert to local date
    LocalDate localDate = LocalDate.parse(dateStr, formatter.withLocale(Locale.ITALIAN));
    System.out.println("START DATE:\n" + localDate);

    // use all power of new java.time
    LocalDate oneDayBefore = localDate.minusDays(1);
    LocalDate oneMonthBefore = localDate.minusMonths(1);
    LocalDate oneWeekBefore = localDate.minusWeeks(1);
    LocalDate oneYearBefore = localDate.minusYears(1);

    System.out.println("RESULTS:");
    System.out.println(oneDayBefore);
    System.out.println(oneMonthBefore);
    System.out.println(oneWeekBefore);
    System.out.println(oneYearBefore);
}

Output:

START DATE:
2016-04-17
RESULTS:
2016-04-16
2016-03-17
2016-04-10
2015-04-17

Now you need to print local date as a string.

Here is example:

    // use Java 8 features
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd,yyyy");
    String dt = dtf.format(oneDayBefore);
    System.out.println(dt);

Output:

Apr 16,2016
catch23
  • 17,519
  • 42
  • 144
  • 217
  • 1
    If you're using LocalDate - which I agree is the right way to go - don't use `SimpleDateFormat`... use `DateTimeFormatter`... that's what it's there for. – Jon Skeet Apr 06 '17 at 22:04
  • As Jon Skeet commented, you are mixing incompatible classes. The java.time classes supplant the old legacy date-time classes. Use just the java.time classes. Also, you are overworking the problem. Use just `LocalDate` without going to a date-time (`Instant`). – Basil Bourque Apr 07 '17 at 04:42
  • @JonSkeet Thank you for a recommendation. Answer is updated. – catch23 Apr 07 '17 at 06:52
  • 1
    Hooray - much better. Finally an answer I can fully support :) (Admittedly, I'm not sure about setting the locale to Italian - but at least it's explicit. Hopefully the OP will set it to whatever they actually want.) – Jon Skeet Apr 07 '17 at 07:08
  • Thank you all for your help! Please note, I accepted one solution, but I'm sure, the others is working well. I need a simple solution and I found it helpful. Thanks again! – brobee Apr 07 '17 at 15:13
2

tl;dr

LocalDate.parse ( 
    "apr 17,2016" , 
    DateTimeFormatter.ofPattern ( "MMM dd,uuuu" ).withLocale( locale ) 
)

Using java.time

The modern way is with the java.time classes.

You do not specify the locale or human language intended for your input strings. The initial lowercase letter in the month name abbreviation is not appropriate to US English. So I tried all the locales provided with Java 8 Update 121, ignoring any parsing attempts that failed with an exception.

Note how we call DateTimeFormatter::withLocale inside the loop. Locale determines (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.

You can do date-time math to get the previous day by calling LocalDate::minusDays.

String input = "apr 17,2016";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MMM dd,uuuu" );

for ( Locale locale : Locale.getAvailableLocales ( ) ) {
    try {
        LocalDate ld = LocalDate.parse ( input, f.withLocale ( locale ) );
        System.out.println ( locale.getDisplayName ( ) + " → " + ld + " | day before: " + ld.minusDays ( 1 ) );
    } catch ( java.time.format.DateTimeParseException e ) {
        // Swallow this expected exception. No code needed here.
    }
}
System.out.println ( "Done." );

Nineteen worked.

Italian → 2016-04-17 | day before: 2016-04-16
Swedish (Sweden) → 2016-04-17 | day before: 2016-04-16
Slovak → 2016-04-17 | day before: 2016-04-16
Estonian → 2016-04-17 | day before: 2016-04-16
Swedish → 2016-04-17 | day before: 2016-04-16
Serbian (Latin,Bosnia and Herzegovina) → 2016-04-17 | day before: 2016-04-16
Serbian (Latin,Montenegro) → 2016-04-17 | day before: 2016-04-16
Norwegian (Norway,Nynorsk) → 2016-04-17 | day before: 2016-04-16
Estonian (Estonia) → 2016-04-17 | day before: 2016-04-16
Serbian (Latin) → 2016-04-17 | day before: 2016-04-16
Dutch → 2016-04-17 | day before: 2016-04-16
Norwegian (Norway) → 2016-04-17 | day before: 2016-04-16
Dutch (Netherlands) → 2016-04-17 | day before: 2016-04-16
Italian (Switzerland) → 2016-04-17 | day before: 2016-04-16
Slovak (Slovakia) → 2016-04-17 | day before: 2016-04-16
Italian (Italy) → 2016-04-17 | day before: 2016-04-16
Dutch (Belgium) → 2016-04-17 | day before: 2016-04-16
Norwegian → 2016-04-17 | day before: 2016-04-16
Serbian (Latin,Serbia) → 2016-04-17 | day before: 2016-04-16
Done.

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

**Note : you should use a date class instead of strings, but there are better classes available than the ones I used here. ** I will edit this answer to reflect this, but you should look below at solutions that are more appropriate for current Java versions and to the precision (day instead of millisecond) requested here.

The most robust way is to convert your string into a date class, manipulate the date, then reformat it back. The conversion in each direction can be done with the SimpleDateFormat class (Api docs) and the changing of the date is easily done with the Calendar class (API docs)

This runs and takes the date from the argument and outputs the format with one day subtracted, as you asked.

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

public class DateSubtractExample{
    public static String backOneDay(String inDate){
      SimpleDateFormat formatter = new SimpleDateFormat("MMM dd,yyyy");
      try{
          // turn your string into a date (if formatting is right)
          Date date1 = formatter.parse(inDate);
          // make a calendar, set it to the date, and subtract one day.
          Calendar cal = Calendar.getInstance();
          cal.setTime(date1);
          cal.add(Calendar.DATE,-1);
          // convert date back to input format. 
          return formatter.format(cal.getTime());
        }
        catch (ParseException bad){
                bad.printStackTrace();
                return "UNREADABLE DATE "+inDate+":"+bad;

        }
    }

    public static void main(String[] args) throws ParseException{
       System.out.println(DateSubtractExample.backOneDay(args[0]));
    }
}
  • 1
    This is definitely better than raw string manipulation, but I'd recommend using `java.time` where possible these days. – Jon Skeet Apr 06 '17 at 19:06
  • In support of @JonSkeet’s comment, a `Date` is a point in time with millisecond precision, this is basically not what you need. `LocalDate` in `java.time` much better reflects (models) what you’re after (there are a couple of other answers using it). – Ole V.V. Apr 07 '17 at 19:33
0
public String getPreviousDate(String oldDate) {
    String[] parts1 = oldDate.split(" "); // split the oldDate around " "
    String[] parts2 = parts1[1].split(","); // split the second part of oldDate around ","

    String month = parts1[0];
    int day = Integer.parseInt(parts2[0]);
    int year = Integer.parseInt(parts2[1]);
    ...
    return newDate;
}
bcr666
  • 2,157
  • 1
  • 12
  • 23
  • You appear to be omitting rather a lot in the "..." here... like working out what month it is, and what month should be in the result. I'd also strongly advise *against* writing your own date parser, which is effectively what you're doing. – Jon Skeet Apr 06 '17 at 18:33
0

This will work as per your requirement please try this, tested program so no need to worry

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

public class DateExample{
    public static void main(String args[]) throws Exception {

        String date = "apr 16,2016";
    SimpleDateFormat formatter=new SimpleDateFormat("MMM dd,yyyy");  

    Date dateFormated =formatter.parse(date);  
    System.out.println(dateFormated);

    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(dateFormated);
    cal.add(Calendar.DATE, -1);

        Date newDate = cal.getTime();
    String stringDate = formatter.format(newDate);
        System.out.println(stringDate);
    }

}
Sunil Prajapati
  • 330
  • 2
  • 6
  • Note that this will use the system default locale, which may well not be a good idea - if the values are known to be in a particular locale, that's what should be used. – Jon Skeet Apr 07 '17 at 07:10
0

I feel I am not clear in the question you are asking. I saw two questions, one related to replace part of string and another about date. I assume you question is about the date. So I tried to reply your question thinking you want to decrease the current date by one day.

For this you can use Calendar interface.

Calendar cal = Calendar.getInstance();
cal.setTime(myDate);
cal.add(Calendar.DAY_OF_YEAR,-1);
Date oneDayBefore= cal.getTime();
Kabiraj Kharel
  • 203
  • 2
  • 11
-1

So, Id use string.split(","). Example Code :

String date="apr 1,2016";
String[] parts=date.split(",");
String month_and_day=parts[0];
String year=parts[1];
String[] parts_of_month_and_day=month_and_day.split(" ");
String month=parts_of_month_and_day[0];
String day=parts_of_month_and_day[1];
int m;
int d;
int y;
y=Integer.parseInt(year);
d=Integer.parseInt(day);
String[] months=new String[] {"jan","feb","mar","apr","may","jun","jul","aug","sep","okt","nov","dez"};
for (int i=0; i < 12 /*length of months*/; i++) {
     if (months[i].equals(month)) {
         m=i;
     }
}
Luatic
  • 8,513
  • 2
  • 13
  • 34
  • Why would you use `String.split` instead of using any of the various ways of parsing a date? You seem happy enough to use `Integer.parseInt` - so why not the date parsing facilities as well? – Jon Skeet Apr 06 '17 at 18:33
  • 2
    Note that you have only done half the work, too. You've written some parsing code, but nothing around subtracting a day and reformatting. – Jon Skeet Apr 06 '17 at 18:38