SimpleDateFormat Ignore Characters - java

I am using a SimpleDateFormat and I am getting results from two different sources. One source uses the format "yyyy-MM-dd HH:mm:ss", while the other uses "yyyy-MM-ddTHH:mm:ssZ". I am not interested in obtaining the time zone ('Z' value) from the second format, is there a way I can obtain these times without using different format strings? Something that will ignore the middle character as well as the characters after 'ss'.

The cleanest and clearest solution is if you can separate the strings from the two sources and use an appropriate formatter for each.
Another approach that you might consider is “taking a taste” to determine which format you’ve got and pick the formatter based on that. For example if (result.contains("T") && results.endsWith("Z")).
Since you asked about avoiding different format strings, that is possible too:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd[ ]['T']HH:mm:ss[X]");
System.out.println(LocalDateTime.parse("2015-11-06 21:23:18", formatter));
System.out.println(LocalDateTime.parse("2018-08-25T08:18:49Z", formatter));
Output from this snippet is:
2015-11-06T21:23:18
2018-08-25T08:18:49
I recommend you avoid the SimpleDateFormat class. It is long outdated and notoriously troublesome. Instead I recommend you use java.time, the modern Java date and time API. It’s so much nicer to work with.
The square brackets denote optional parts of the format. The format will accept also a string that has both a space and a T in the middle, and one that hasn’t got any of them. For most purposes I suggest that we can live with that. Edit: You cannot play a similar trick with SimpleDateFormat, it does not accept square brackets or any other syntax for optional parts.
I am not happy about ignoring the offset in the second string and doing that only because you said you wanted to. I’d clearly prefer the following just slightly longer solution:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd[ ]['T']HH:mm:ss[X]")
.withZone(ZoneOffset.UTC);
System.out.println(OffsetDateTime.parse("2015-11-06 21:23:18", formatter));
System.out.println(OffsetDateTime.parse("2018-08-25T08:18:49Z", formatter));
Output is the same, only now with offset:
2015-11-06T21:23:18Z
2018-08-25T08:18:49Z
Link: Oracle tutorial: Date Time explaining how to use java.time.

I know this is old but for the date with the T in the middle and the time zone at the end "2018-08-24T08:02:05-04:00" use the following in your simpledateformat: "yyyy-MM-dd\'T\'HH:mm:ssX"

Related

Strange String Format for Date

Java application gets a stream of JSON messages,
within those, the String fields, that represent some date are formatted like \"2019-01-01+01:00\".
It looks like a normal date, followed by the timezone-offset, this guess of mine has been confirmed on the producer side.
Problem:
Even though I still do not really get the logic behind it, I have to parse it in my Java App.
The simplest approach would be to split that string on the '+' character and just parse the date part with some pattern in LocalDate.
But out of curiosity, maybe there is some Date format in Java I do not know of, which could allow for this strange string format?
Yes there is. DateTimeFormatter.ISO_OFFSET_DATE. I agree that it’s weird, and I don’t know what use you should have of the offset. But you can parse into a LocalDate using the formatter:
String stringFromJson = "2019-01-01+01:00";
LocalDate date = LocalDate.parse(stringFromJson, DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(date);
Output:
2019-01-01
Splitting at the + (plus sign) will not always work. A date with an offset may also come with a negative offset, for example -04:00, and with offset Z (for zero, that is, UTC). Of course you could write code to handle each of those situations manually, but it’s better to use the built-in formatter.
Don’t use Date and SimpleDateFormat. Those classes are poorly designed and long outdated, the latter in particular notoriously troublesome. Use LocalDate and DateTimeFormatter, both from java.time, the modern Java date and time API.

Xmlgregoriancalendar not allowed leading zero in ddMMyyyy

I tried to get XMLGregorianCalendar with date format ddMMyyy. When I tried to convert it from Date, it kept throwing me:
java.lang.IllegalArgumentException: Leading zeros are not allowed.
Is there anyway to fix it?
Thanks!
DateFormat format = new SimpleDateFormat("ddMMyyyy");
XMLGregorianCalendar gTest = DatatypeFactory.newInstance().newXMLGregorianCalendar(format.format(new Date(1, 9, 2018)));
First, you shouldn’t use the Date class if you can avoid it. You may also want to avoid XMLGregorianCalendar. Date and SimpleDateFormat are long outdated, and the latter in particular renowned for being troublesome. Today we have so much better in java.time, the modern Java date and time API. It may also sometimes replace XMLGregorianCalendar.
But taking your word for it, you’ve got an old-fashioned Date object — maybe from a legacy API that you cannot change or don’t want to change just now. You need to convert it to an XMLGregorianCalendar. I still prefer to use java.time for the conversion.
Date oldfashionedDate = // some Date equal to 1 August 2018 at 00:00 in my time zone;
LocalDate modernDate = oldfashionedDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
XMLGregorianCalendar gTest = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(modernDate.toString());
System.out.println(gTest);
This prints:
2018-08-01
You asked for format ddMMyyyy. You cannot have that. Or more precisely, the only way you can have that is in a string, not in an XMLGregorianCalendar. XMLGregorianCalendar.toString() produces XML format, and this is defined in the XML Schema (see the link at the bottom). It goes like for example 2018-08-01, 2018-08-01T00:00:00 or 2018-08-01T00:00:00+02:00.
What went wrong in your code?
I could not reproduce your IllegalArgumentException. On my Java 10 the leading 0 of 01082018 was accepted (on Java 8 too). However, the data type factory parsed the string into a year of 1082018 (more than a million years from now), and since the string ended there, it didn’t parse any month or day of month. So the resulting XMLGregorianCalendar had only a year in it, no other fields were defined.
newXMLGregorianCalendar(String) accepts only XML format. Apparently a year alone is accepted. The format still follows the specification linked to at the bottom of this answer.
Accepting the leading 0 is probably a bug, though, since the leading zero is not printed back from the toXMLFormat method, which was supposed to give the same string back as was parsed, according to the documentation of newXMLGregorianCalendar(String).
Links
Oracle tutorial: Date Time explaining how to use java.time.
XML Schema Part 2: Datatypes Second Edition: Lexical representation
Documentation of DatatypeFactory.newXMLGregorianCalendar(String)

How to present a date that can be parsed by any DateTimeFormatter pattern in Java?

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");

Java SimpleDateFormat Timezone offset with minute separated by colon

How can I get my date formatted as 2012-11-25T23:50:56.193+01:00 using SimpleDateFormat?
If I use Z in the format like
yyyy-MM-dd'T'hh:mm:ss.SSSZ
then it shows
2013-03-06T11:49:05.490+0100
You can get the timezone offset formatted like +01:00 with the SimpleDateFormat in Java 7 (yyyy-MM-dd'T'HH:mm:ss.SSSXXX), or with the Joda's DateTimeFormat (yyyy-MM-dd'T'HH:mm:ss.SSSZZ).
Here’s the 2017 answer. If there is any way you can (which there is), throw the outdated classes like SimpleDateFormat overboard and use the modern and more convenient classes in java.time. In particular, the desired format, 2012-11-25T23:50:56.193+01:00 complies with ISO-8601 and therefore comes out of the box with the newer classes, just use OffsetDateTime.toString():
OffsetDateTime time = OffsetDateTime.now();
System.out.println(time.toString());
This prints something like
2017-05-10T16:14:20.407+02:00
One thing you may or may not want to be aware of, though, it prints as many groups of 3 decimals on the seconds as it takes to print the precision in the OffsetDateTime object. Apparently on my computer “now” comes with a precision of milliseconds (seconds with three decimals).
If you have an oldfashioned Date object, for example, you got it from a call to some legacy method, I recommend the first thing you do is convert it to Instant, which is one of the modern classes. From there you can easily other conversions depending on your requirements:
Date now = new Date();
OffsetDateTime time = now.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
System.out.println(time.toString());
I am really doing more conversions than necessary. atZone(ZoneId.systemDefault()) produced a ZonedDateTime, and its toString() will not always give you the format you said you wanted; but it can easily be formatted into it:
ZonedDateTime time = now.toInstant().atZone(ZoneId.systemDefault());
System.out.println(time.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

Comparing date strings in Java [duplicate]

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)

Categories

Resources