I'm trying to compare two different times to see which comes before the other, but I'm having trouble coming up with an else if statement that compares their suffixes (am and pm) and outputs the order of the first time relative to the other time.
EDIT: the date type of suffix1 and suffix2 are strings, the data type of time1 and time2 are int
So far, I have this piece of code that checks if the periods are equal:
if (suffix1.equals(suffix2))
{
if (time1 > time2)
{
System.out.print("After");
}
.....
}
is there a way to see which times' suffix comes before the other?
I would think you’re after something like the following:
String timeString1 = "2:00 PM";
String timeString2 = "9:00 AM";
DateTimeFormatter timeFormatParser
= DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH);
LocalTime time1 = LocalTime.parse(timeString1, timeFormatParser);
LocalTime time2 = LocalTime.parse(timeString2, timeFormatParser);
if (time1.isAfter(time2)) {
System.out.println("After");
}
With the strings in my example the code does print After. If your original time strings have a different format, I hope you can modify the format pattern string accordingly, otherwise follow up in a comment. Or maybe better, edit your question to specify your strings precisely. The letters you can use are documented here. Please be aware that the format pattern is case sensitive.
My DateTimeFormatter expects AM or PM in uppercase. If your strings have them in lowercase, there are a couple of options:
The simple: timeString1 = timeString1.toUpperCase(Locale.ENGLISH); and similarly for timeString2.
The more general but also more complex: Use a DateTimeFormatterBuilder to build a non-case-sensitive DateTimeFormatter.
PS Before the modern Java date and time API that I am using came out in 2014, one would often use a class called SimpleDateFormat to parse into a Date object. Nowadays stay away from that. The newer classes have shown to be considerably nicer to work with and more programmer friendly.
Use Date to represent time in application: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html
The string representation, should be used only when displaying the time.
When you use dates you can compare them like this myDate.compareTo(anotherDate).
You can print the date in whichever form you want, here is how: Change date format in a Java string
Related
I want to change the format of date from yyyyMM to yyyy-MM.
I have found out that the two ways below works equally well. But which one is the best? I would prefer methodTwo since it is simplier, but is there any advantage using methodOne?
public String date;
public void methodOne()
{
String newDate = date;
DateFormat formatter = new SimpleDateFormat("yyyyMM");
DateFormat wantedFormat = new SimpleDateFormat("yyyy-MM");
Date d = formatter.parse(newDate);
newDate = wantedFormat.format(d);
date = newDate;
}
public void methodTwo()
{
date = date.substring(0, 4) + "-" + date.substring(4, 6);
}
You should prefer method one because it can detect if the input date has an invalid format. Method two could lead to problems, when it's not guaranteed that the input date is always in the same format. Method one is also more easy to adjust, when you later want to change either the input or the output format.
It could make sense to use method two if performance really matters, because it should be slightly faster than method one.
I would say that methodOne is much more generic. If you need to change your wanted format again, you only have to change the argument "yyyy-MM" for whatever new format you want, no matter how exotic it is. I found that when you work with people all across the world, methodOne is much more useful and also easier to read than using substrings. Using substrings means that you have no way to make sure that what is coming has the format you expect. You could be splitting in the wrong order.
Get it in a Easy Way:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
String date = sdf.format(yourDate);
Using the SimpleDateFormat is the industry standard. It is easier to read and maintain in the future as it allows the format to be changed with ease.
java.time.YearMonth
There is a third way: Use the YearMonth class built into Java 8 and later as part of the java.time framework.
You don't have a date and a time, so using a date-time class such as java.util.Date or even the java.time types (Instant, OffsetDateTime, ZonedDateTime) is not a good fit. As you have only a year and a month use, well, YearMonth – a perfect fit.
Rather than pass Strings around your code, pass these YearMonth values. Then you get type-safety and valid values.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuyy");
YearMonth ym = YearMonth.parse( input );
The default format used by the YearMonth::toString method uses the standard ISO 8601 format you desire.
String output = ym.toString();
I'm working with a software that uses a lot of DateTimeFormat parsing, in order to minimize the errors, I wonder if I can present the date String in a certain way that it can be parsed by any DateTimeFormat pattern. Ideally it should work as follows:
String date = "...."
DateTimeFormatter format = DateTimeFormat.forPattern(any pattern I want);
DateTime result = format.parseDateTime(date);
Or does the date have to follow the pattern? Thanks for your help
No, you can not get one size fits all. Think if your string is not a legal date at all, something like "hello", how are you going to parse it?
java.time
Java 8 and later includes the java.time framework (Tutorial). The java.time formatter’s pattern may contain []to mark optional parts. This gives you some flexibility. Say you use format:
M[M]['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss
So in this case your string may have one or two digits specifying month, day and hour. Month, day and year may be separated by ., - or / and so forth. For example with format above the following strings will be parsed successfully:
1/10/1995 9:34:45
01-10-1995 09:34:45
01.10.1995T09:34:45
…and so forth.
I wrote a utility that has a set of patterns. Once it gets a String it tries to parse it with all the patterns in the set and sees if it succeeds with one of them. If you write such a set of patterns correctly you may ensure that your util supports any possible String that denotes a valid date.
SimpleDateFromat let you set your own date patters. for example dd/mm/yyyy, mm/dd/yyyy, yyyy-mm-dd etc..
This link can give you a better understanding about date patterns and how to use it
use SimpleDateFormat
SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
Date d=sdf.parse("07/12/2014");
System.out.printf("Time: %d-%d %02d:%02d" +
calendar.get(Calendar.DAY_OF_MONTH),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE);
That is the code a friend showed me, but how do I get the date to appear in a Format like November 1?
This is how to do it:
DateFormat dateFormat = new SimpleDateFormat( "MMMMM d" );
Calendar calendar = new GregorianCalendar(); // The date you want to format
Date dateToFormat = calendar.getTime();
String formattedDate = dateFormat.format( dateToFormat );
System.out.println( formattedDate );
Date d = new Date();
System.out.printf("%s %tB %<td", "Today", d);
// output :
// Today november 01
%tB for Locale-specific full month name, e.g. "January", "February".
%<td d for Day of month, formatted as two digits with leading zeros as necessary, < for reuse the last parameter.
The DateFormat answer is the way to do this. The printf answer is also good although does not provide locale-specific formats (it provides language-specific names but does not use e.g. the day/month/year ordering that the current locale uses).
You asked in a comment:
Can I do it with the calendar.get(Calendar.MONTH) etc method? Or do I have to use date format?
You don't have to use the other methods here, but if you want to use the Calender fields, it is up to you to convert the numeric values they provide to strings like "Tuesday" or "November". For that you can use the built in DateFormatSymbols, which provides internationalized strings from numbers for dates, in the form of String arrays, which you can use the Calendar fields to index in to. See How can I convert an Integer to localized month name in Java? for example.
Note you can use DateFormat.getDateInstance() to retrieve a pre-made format for the current locale (see the rest of those docs, there are also methods for getting pre-made time-only or date+time formats).
Basically you have the following options:
DateFormat (SimpleDateFormat for custom formats)
Locale-specific format (e.g. day/month/year ordering): Yes
Language-specific names (e.g. English "November" vs. Spanish "Noviembre"): Yes
Does the work for you: Yes. This is the best way and will provide a format that the user is used to working with, with no logic needed on your end.
printf date fields
Locale-specific format: No
Language-specific names: Yes
Does the work for you: Partly (up to you to determine field ordering)
Calendar fields with DateFormatSymbols
Locale-specific format: No
Language-specific names: Yes
Does the work for you: No
Calendar fields with your own string conversions (like a big switch statement):
Locale-specific format: No
Language-specific names: No
Does the work for you: No
Another advantage of DateFormat-based formats vs printf date fields is you can still define your own field ordering and formats with the SimpleDateFormat (just like printf) but you can stick to the DateFormat interface which makes it easier to pass around and combine with stock date formats like DateFormat.getDateInstance(DateFormat.MEDIUM).
Check out the documentation for DateFormat for info on the things you can do with it. Check out the documentation for SimpleDateFormat for info on creating custom date formats. Check out this nice example of date formats (archive) for some example output if you want instant gratification.
There's a direct way how to do it using printf, but it's a pain, too:
String.printf("Time: %1$td-%1$tm %1$tH:%1$tM", new Date());
One problem with it is that it uses 4 formatting strings with the same object, so it needs the 1$ prefix to always access the first argument. The other is that I can never remember what letter means what (but maybe that's just me).
Speed could actually be another problem, if you care.
This is documented in the underlying class Formatter.
My preffered way would be something like
myFormatter.format("Time: [d-m HH:MM]", new Date())
where the braces would save us from repeating $1 and make clear where the argument ends.
Currently, I'm having
private ThreadLocal<DateFormat> shortDateFormat = new ThreadLocal<DateFormat>() {
#Override protected DateFormat initialValue() {
final DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
return format;
}
};
Using my Android 4.1, this provides me date in format (In my localization. It may look different for other countries)
19/07/2013
However, sometimes I would like to have a much shorter version like 19/07/13
I do not want to hard code as
dd/MM/yy
As the above way would not portable across different countries. Some countries, their month come before date.
Is there any portable way to achieve so?
p/s Not only month/date order. There might be other problem as well. For instance, China is using 19-07-13 or 19-07-2013. There might be more edge cases for other countries, but I don't know.
SimpleDateFormat dateFormat= (SimpleDateFormat) DateFormat.getDateInstance();
dateFormat.applyPattern(dateFormat.toPattern().replaceAll("y{4}", "yy"));
Explanation:
applyPattern(String pattern) applies the given pattern string to this date format.
dateFormat.toPattern() gets the current pattern
dateFormat.toPattern().replaceAll(String regex, String replacement) returns the current pattern, with regex replaced by replacement.
"y{4}" looks through the date format pattern for a series of 4 y's, and
"yy" says that if you see 4 y's, replace them with 2 instead.
Hope that helped. Good luck.
EDIT:
As MH pointed out, since this is for android, it is probably more appropriate to use:
SimpleDateFormat dateFormat = (SimpleDateFormat)
android.text.format.DateFormat.getDateFormat(getApplicationContext());
This should work fine, since the above method call returns a DateFormat of java.text.DateFormat, not of android.text.format.DateFormat.
You should take a look at the functionality android.text.format.DateFormat provides, on top of the java.text.DateFormat.
In particular, the following method will be of interest:
getDateFormatOrder(Context context)
Javadoc:
Gets the current date format stored as a char array. The array will
contain 3 elements (DATE, MONTH, and YEAR) in the order specified by
the user's format preference. Note that this order is only appropriate
for all-numeric dates; spelled-out (MEDIUM and LONG) dates will
generally contain other punctuation, spaces, or words, not just the
day, month, and year, and not necessarily in the same order returned
here.
In other words, the method allows you to determine what order the day, month and year fields are in, according to the user's preference (which triumphs the user's locale, if you ask me). From there it should easy enough to figure out what 'short' format to use; i.e. dd/MM/yy or MM/dd/yy.
As pointed out by the documentation, the return value of the method is only useful in the context of all-numeric date representations. That should be fine in your case.
If you want portable, rather than using the date object, you could instead create an array with month,date, and year. (I would just use the cal object and access each of the three individually)
Calendar cal = Calendar.getInstance();
int year =cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day= cal.get(Calendar.DAY);
dateArray[0] = month;
dateArray[1] = year;
dateArray[2] = day;
How about creating a map with localized patterns based on country ISO code and a fallback default pattern in case you don't have a specific country defined?
This question already has answers here:
How to compare dates in Java? [duplicate]
(11 answers)
Closed 6 years ago.
So I am using dateString1.compareTo(dateString2) which does a lexicographic comparison with strings, based on the Unicode value of each character, and returns an int. Here is a code sample.
String dateString1 = "05-12-2012";
String dateString2 = "05-13-2012";
if (dateString1.compareTo(dateString2) <=0){
System.out.println("dateString1 is an earlier date than dateString2");
}
Is this a wrong approach to compare dates in Java?
In my tests, I have not run into a situation where I have gotten unexpected result. I really do not want to create a Date object out of the string, if I don't have to, because I am doing this inside a long running loop.
Ninja Edit
Gleaning from the answers below there is nothing wrong with comparing dates as a string if it is in yyyyMMdd format but if it is in any other format it will obviously result in error.
I actually have my date string as yyyyMMdd format in my actual code. (I typed the format wrong in the example I gave above.) So for now, I will just leave the code as it is, and add few lines of comments to justify my decision.
But I now see that comparing strings like this is very limiting and I will run into bugs if dba decides to change the date format down the road, which I don't see happening.
Use strings to handle dates in Java is not always the best option. For example, when it is a leap year, February has an extra day. Because strings can be seemingly correct, it is more appropriate to perform a conversion. Java validates that the date is correct.
You can convert strings to dates using the SimpleDateFormat class.
public static void main(String[] args) throws ParseException {
String dateString1 = "05-12-2012";
String dateString2 = "05-13-2012";
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
Date date1 = format.parse(dateString1);
Date date2 = format.parse(dateString2);
if (date1.compareTo(date2) <= 0) {
System.out.println("dateString1 is an earlier date than dateString2");
}
}
To find out which parameters are allowed to check Customizing Formats (The Java™ Tutorials > Internationalization > Formatting)
I suggest you do the Right Thing (as described here) and convert to proper Date objects to compare. Worry about the performance impact if and when it actually impacts your application (which it probably won't).
It is pretty bad as now you cannot handle a year change.
If you want to do it like that you might wanna format the date as YYYY-MM-DD so the new year doesn't ruin it.
It is bad to use the rules for alphabetization to handle date ordering, mostly because you run into issues where things are ordered differently according to the alphabet and the number system
For the alphabet
01-02-2011 comes before
01-1-2011 (because 0 in the date field is before 1 in the other date field)
For the number system
01, 02, 2011 comes after
01, 1, 2011 because all fields are being compared like numbers
Date objects extend numeric comparison to know which fields take precedence in the comparison, so you don't get a earlier month putting a date "before" another that actually occurs at a latter month but an earlier year.
If you have strict control over the date format, you can align the dates such that they also follow alphabetical rules; however, doing so runs a risk of having your entire program fail in odd ways if you accidentally inject a misformatted date.
The typical way to do this is (not recommended, please use non-String Date comparisons)
YYYYMMDD
(year)(month)(day) all zero-padded.
The last technique is included mainly as you will eventually see it in the wild, and should recognize it for what it is: an attempt to handle dates without a proper date library (aka a clever hack).
As discussed, generally better to work with date-time objects rather than strings.
java.time
The other Answers use old outmoded date-time classes that have proven to be poorly designed, confusing, and troublesome. They lack a class to truly represent a date-only value without time-of-day and without time zone.
Instead use the java.time framework built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
String input = "05-12-2012";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MM-dd-yyyy" );
LocalDate ld = LocalDate.parse( input , formatter );
The LocalDate implements compareTo. Also, you can call methods equals, isBefore, isAfter.
Boolean isEarlier = ld.isBefore( someOtherLocalDate );
if you are doing only one read of each date then YYYYMMDD (not MMDDYYYY as you did it) might be the most optimal solution. however when you intend to process each date more than once (e.g. you are sorting them) then for sure it's better to change them to an object that can be compared quicker than string (e.g. date)