I have following method that I would like to make shorter or faster if nothing else. Please all comments are welcome:
Bellow method takes a date object, formates i
this for today,yesterday,tomorrow
String formatDate(String fecha){
String Rfecha=new String();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
//SimpleDateFormat formatter2 = new SimpleDateFormat("EEEE d MMM");
SimpleDateFormat formatter2 = new SimpleDateFormat("E, d MMM ");
try {
Date hoy=new Date();
Date date = formatter.parse(fecha);
String pref="";
Log.d("hoy long", ""+(hoy.getTime()/ (1000*60*60*24)));
Log.d("date long", ""+ (date.getTime()/ (1000*60*60*24)));
int ihoy=(int) (hoy.getTime()/ (1000*60*60*24));
int idate=(int) (date.getTime()/ (1000*60*60*24));
int dif=idate-ihoy;
if(dif==0)
pref="Today";
if(dif==1)
pref="Tomorrow";
if(dif==-1)
pref="Yesterday";
Rfecha=pref+" "+formatter2.format(date);
} catch (Exception e) {
e.printStackTrace();
}
return Rfecha;
}
Here's how you could improve it with the standard API:
public static String formatToYesterdayOrToday(String date) throws ParseException {
Date dateTime = new SimpleDateFormat("EEE hh:mma MMM d, yyyy").parse(date);
Calendar calendar = Calendar.getInstance();
calendar.setTime(dateTime);
Calendar today = Calendar.getInstance();
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DATE, -1);
DateFormat timeFormatter = new SimpleDateFormat("hh:mma");
if (calendar.get(Calendar.YEAR) == today.get(Calendar.YEAR) && calendar.get(Calendar.DAY_OF_YEAR) == today.get(Calendar.DAY_OF_YEAR)) {
return "Today " + timeFormatter.format(dateTime);
} else if (calendar.get(Calendar.YEAR) == yesterday.get(Calendar.YEAR) && calendar.get(Calendar.DAY_OF_YEAR) == yesterday.get(Calendar.DAY_OF_YEAR)) {
return "Yesterday " + timeFormatter.format(dateTime);
} else {
return date;
}
}
Here's how you could do it with Jodatime:
public static String formatToYesterdayOrToday(String date) {
DateTime dateTime = DateTimeFormat.forPattern("EEE hh:mma MMM d, yyyy").parseDateTime(date);
DateTime today = new DateTime();
DateTime yesterday = today.minusDays(1);
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("hh:mma");
if (dateTime.toLocalDate().equals(today.toLocalDate())) {
return "Today " + timeFormatter.print(dateTime);
} else if (dateTime.toLocalDate().equals(yesterday.toLocalDate())) {
return "Yesterday " + timeFormatter.print(dateTime);
} else {
return date;
}
}
The Question and the other Answers ignore the crucial issue of time zone. That input string lacks any time zone or offset-from-UTC. So that string will be parsed while assuming it represents a date-time in your JVM’s current default time zone. Risky business as (a) that assumption may be false, and (b) that default can change at any moment, even during runtime.
The Question and other Answers ignore another crucial issue: Locale. The Locale determines the human language used to translate the name of day and name of month from the input string during parsing (and generating).
If not specified the JVM’s current default Locale will be used for translation. Just as with time zone, your JVM’s default Locale can change at any moment, even during runtime.
Better to specify your desired/expected Locale.
The Question and the other Answers use the old date-time classes that have proven to be poorly designed and troublesome. Java 8 and later has the java.time framework built-in whose classes supplant the old ones.
You method to parse a string while generating a new string should be broken up into two methods. One method should parse to obtain date-time objects. The second should take date-time objects and generate the desired string output. Then each can be used separately. And this approach leads us away from thinking of strings as date-time values. Strings are textual representations of date-time values. Your business logic should focus on manipulating those date-time values as objects, not focus on strings.
private ZonedDateTime parseLengthyString ( String input , ZoneId zoneId , Locale locale ) {
// FIXME: Check for nulls.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" );
formatter = formatter.withZone ( zoneId );
formatter = formatter.withLocale ( locale );
ZonedDateTime zdt = null;
try {
zdt = ZonedDateTime.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
// FIXME: handle exeption.
System.out.println ( "ERROR - e: " + e );
}
return zdt; // FIXME: Check for null.
}
Given a ZonedDateTime
in hand from the method above, we can generate a textual representation of its date-time value using a specified Locale for translation of name-of-day and name-of-month.
To determine if the date-time is for today or yesterday, we only care about the date portion without time of day. For that we can use the LocalDate class in java.time.
private String generateLengthyString ( ZonedDateTime zdt , Locale locale ) {
// FIXME: Check for nulls.
// Compare the date-only value of incoming date-time to date-only of today and yesterday.
LocalDate localDateIncoming = zdt.toLocalDate ();
Instant instant = Instant.now ();
ZonedDateTime now = ZonedDateTime.now ( zdt.getZone () ); // Get current date-time in same zone as incoming ZonedDateTime.
LocalDate localDateToday = now.toLocalDate ();
LocalDate localDateYesterday = localDateToday.minusDays ( 1 );
DateTimeFormatter formatter = null;
if ( localDateIncoming.isEqual ( localDateToday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Today' hh:mma" , locale ); // FIXME: Localize "Today".
} else if ( localDateIncoming.isEqual ( localDateYesterday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Yesterday' hh:mma" , locale ); // FIXME: Localize "Yesterday".
} else {
formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" , locale );
}
String output = zdt.format ( formatter );
return output; // FIXME: Check for null.
}
Exercise those two methods.
Arbitrarily choosing a time zone of America/New_York as the Question does not specify.
String input = "Sat 11:23AM Feb 6, 2016";
ZoneId zoneId = ZoneId.of ( "America/New_York" );
Locale locale = Locale.US;
ZonedDateTime zdt = this.parseLengthyString ( input , zoneId , locale );
String output = this.generateLengthyString ( zdt , locale );
By the way, you can ask java.time to automatically format the output string according to the cultural norms of the Locale instead of hard-coding a format.
String outputPerLocale = zdt.format ( DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ) );
Dump to console.
System.out.println ( "input: " + input + " | zdt: " + zdt + " | Instant: " + zdt.toInstant () + " | output: " | output + " + outputPerLocale: " + outputPerLocale );
input: Sat 11:23AM Feb 6, 2016 | zdt: 2016-02-06T11:23-05:00[America/New_York] | Instant: 2016-02-06T16:23:00Z | output: Today 11:23AM | outputPerLocale: Feb 6, 2016 11:23:00 AM
By the way, I suggest putting a SPACE before the AM
or PM
for easier reading.