preventing the use of SimpleDateFormatter twice - java

I had a String in this form, EEE, dd MMM yy hh:mm:ss Z and I wanted to convert it into the Date object so i did this,
SimpleDateFormat fDate = new SimpleDateFormat("EEE, dd MMM yy hh:mm:ss Z",Locale.getDefault());
then I created the instance field of type Date
Date toDate = null;
and parse my String date and store it into toDate
toDate = fDate.parse(stringDate);
Now the date is stored in toDate variable in this form,
Tue Jan 20 07:33:06 GMT+05:30 2015
but this is not what i wanted.
I wanted my final Date object in this form,
Tue Jan 20, 2015
So, in order to achieve this, I created the new Calendar object and set its time to toDate,
Calendar s = Calendar.getInstance();
s.setTime(toDate);
then I create a new String and store Day of Week, Month Day of Month and year to get this format Tue Jan 20, 2015.
String newDate = s.getDisplayName(Calendar.DAY_OF_WEEK,0,Locale.getDefault()) + " "
+ s.getDisplayName(Calendar.MONTH, 0, Locale.getDefault())
+ " " + s.get(Calendar.DAY_OF_MONTH) + ","
+ s.get(Calendar.YEAR);
Now, my new string newDate has a date in this form Tue Jan 20, 2015 and the problem is it is a String object and not a Date object, and in order to convert it to Date object I have to use the SimpleDateFormatter again.
But this is a lot of work because in order to convert String of this form, EEE, dd MMM yy hh:mm:ss Z into the Date object of this form, Tue Jan 20, 2015, I am first using SimpleDateFormatter then I am parsing it in a Date object, then I extract my desire fields from that Date object using Calendar and store in a String, and then convert that String back to the Date object.
Is there any easier way to achieve this ? i.e, converting this String EEE, dd MMM yy hh:mm:ss Z directly into this format Tue Jan 20, 2015 of type Date without using SimpleDateFormatter twice ?

While the Java Date library is notoriously bad (which is pretty much why everyone uses the Joda-Time library, and why Oracle released the new java.time package with Java 8 (see article), there are a couple things to be aware of:
ALL java.util.Date represents is the number of milliseconds since midnight, Jan 1, 1970 in UTC. In other words, java.util.Date is really just a small wrapper around a long value.
Thus, java.util.Date does NOT store any kind of formatting info. Date.toString() just always produces a String in a human readable "debug" format.
To answer your question, no, there is really not a way to prevent the use of SimpleDateFormatter twice, but I don't see why you would want to avoid this, besides that it seems like you are misunderstanding the concepts of what a Date represents. If you have a java.lang.String and want to convert it to a java.util.Date, you use DateFormat.parse(), and if you have a java.util.Date and want to convert it to a java.lang.String, you use DateFormat.format().

Related

What is wrong with this java date formatter?

I'm trying to format the date you see as a String in the below code, to be able to have it as a LocalDateTime object, but I'm getting an exception, I'm following this guide https://mkyong.com/java8/java-8-how-to-convert-string-to-localdate/, but unfortunately it doesn't have and example like the date I have below, can someone please give me a hand here? I would really appreciate :)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE MMM d hh:mm:ss zzz yyyy", Locale.US);
String date = "Wed Nov 18 00:00:00 COT 2020";
LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);
System.out.println(localDateTime);
System.out.println(formatter.format(localDateTime));
I am getting:
java.time.format.DateTimeParseException: Text 'Wed Nov 18 00:00:00 COT
2020' could not be parsed at index 0
If you want round trip parsing/formatting with Zones try
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
String date = "Wed Nov 18 00:00:00 COT 2020";
ZonedDateTime localDateTime = ZonedDateTime.parse(date, formatter);
System.out.println(localDateTime);
System.out.println(formatter.format(localDateTime));
To answer the question as asked in the title, What is wrong with this Java date formatter?
EEEE is for full name of the day of the week like Monday. For the abbreviation like Mon you need either E, EE or EEE.
As others have said, lower case hh is for clock hour within AM or PM from 01 through 12, so cannot parse your hour of 00. And even if it could, it would not provide enough information for the time of day. For hour of day from 00 though 23 you need upper case HH.
There’s a more basic problem that Basil Bourque already mentioned in a comment: The result of parsing a time zone abbreviation like COT is generally undefined. While COT may have only one definition, I don’t know, most of the most common abbreviations are ambiguous, and you don’t know what you get from parsing them.
As has also been mentioned your formatter cannot be used for formatting a LocalDateTime. A LocalDateTime hasn’t got any time zone. The formatter requires a time zone for the abbreviated time zone name, zzz. You may either format a ZonedDateTime, or you may modify the formatter to have an override zone using its withZone method.
A tip: When you don’t know why parsing fails, try formatting the expected value with the same formatter and compare the result to the string you are trying to parse. Most often the difference will lead you on the right track. Like this:
ZonedDateTime val = ZonedDateTime.of(
2020, 11, 18, 0, 0, 0, 0, ZoneId.of("America/Bogota"));
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEEE MMM d hh:mm:ss zzz yyyy", Locale.US);
String toBeParsed = "Wed Nov 18 00:00:00 COT 2020";
String formatted = val.format(formatter);
System.out.println("String to be parsed: " + toBeParsed);
System.out.println("Formatted string: " + formatted);
Output:
String to be parsed: Wed Nov 18 00:00:00 COT 2020
Formatted string: Wednesday Nov 18 12:00:00 COT 2020
The difference are Wednesday and 12, so it seems the bugs in the pattern are at EEEE and hh.
Your string seems to come out of the toString method of the outdated java.util.Date class. To parse the string from there see one of the answers linked to at the bottom. Or still better, get hold of the Date object, convert it to a modern Instant using its toInstant method and perform any further conversions from there. Or yet still better, stop using Date completely.
Links
How to parse the result from Date.toString():
Answer by Arvind Kumar Avinash
Answer by Arvind Kumar Avihash
Answer by Arvind Kumar Avinash
My answer
Answer by Basil Bourque
And of course the answer by Scary Wombat to this question

Convert Date String Mon Mar 30 13:51:35 UTC 2015 to Date Object

I am trying to convert a string such as
String dateString = "Mon Mar 30 13:51:35 UTC 2015";
in a Date Object.
I tried this:
DateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Date Object:"+sdf.parse(dateString));
But the output of the date object is
Mon Mar 30 15:51:35 CEST 2015
as you can see:
1) it forwards the string's time ahead to two hours
2) it changes UTC --> CEST
I tried many solutions, but nothing worked. What is the correct way to do this?
EDIT: my objective here is to have a Date object from that original String. That Date Object should have the same parameters as the date string. In this case, the original hours of day (13) is turned to 15, but the desired is for it to stay at 13. I need this because in my program I will need to compare two different date objects.
EDIT: JAVA 8 SOLUTION
Searching the more recent Java 8, I found a better and more elegant solution. Here is the code
String pattern = "EEE MMM dd HH:mm:ss SSS zzz yyyy";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, Locale.UK).withZone(ZoneId.of("UTC"));
final ZonedDateTime parsed = ZonedDateTime.parse(dateString, formatter);
Furthermore, to compare it with, for example, the current time:
ZonedDateTime now = ZonedDateTime.now();
int compared = parsed.compareTo(now);
System.out.println("NOW:"+now.toLocalDateTime()+" PARSED:"+parsed.toLocalDateTime()+" COMPARED:"+compared);
You are doing it correctly. The date is being parsed correctly. You are just printing the date into your local computer timezone. When you do toString() to a date, prints the date in your local machine timezone.
Mon Mar 30 15:51:35 CEST 2015 == Mon Mar 30 13:51:35 UTC 2015
CEST is UTC +2
A java.util.Date does not have a time zone, practically speaking. There is a time zone inside but it cannot be set nor gotten. One of many poor design decisions made in these old date-time classes.
The Date::toString method applies your JVM’s current default time zone when generating the output string. Done with good intentions, but not helpful as it creates the illusion your Date object is in that zone when in fact it is not.
java.time
You are using a troublesome old legacy class, now supplanted by the java.time framework built into Java 8 and later.
Convert from a Date to an Instant, a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = myJavaUtilDate.toInstant();
Call toString. The java.time classes use standard ISO 8601 formats when parsing/generating strings.
String output = instant.toString();
To create strings, convert from Instant to OffsetDateTime using the constant ZoneOffset.UTC. Then work with the java.time.format classes to generate the string.
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , ZoneOffset.UTC );
Search Stack Overflow for more info and examples. These issues have addressed hundreds of times already.
Instead of UTC, use GMT when getting the timezone.
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Source
You already have the Date object. If you want to print it in format you want, you can use DateFormat to format the Date object as well:
Date date = sdf.parse(dateString);
System.out.println("Date Object:"+sdf.format(date));
// Use the date object ...

TimeZone Conversion with SimpleDateFormat in Java

I have a SimpleDateFormat parser that parse in this way:
sdf = new java.text.SimpleDateFormat("yyyy-MM-DD HH:mm:ss z").parse("2013-10-25 17:35:14 EDT");
log.debug(sdf);
This give me Sat Jan 26 03:05:14 IST 2013
What am i missing here?
First of all, DD stands for day in year, You should use dd instead.
Also, if you want to print a date in a specific format, you need to use two SimpleDateFormats.
SimpleDateFormat.parse returns a Date object represents the date you specified at the given format.
The Date object itself is saved as a regular Date, no format attached to it.
If you want to print it in a specific format, you need to use another SimpleDateFormat and call format method.
you should use Format
SimpleDateFormat sdf1 = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:SS z");
String sdf = sdf1.format(sdf1.parse("2013-10-25 17:35:14 EDT"));
There are two things.
sdf is an object of Date, which represents a specific instant in time (milliseconds elapsed since another instant known as "the epoch"). There is no format which is known to this object. And how this object is printed is solely handled by its class' toString method, which prints the date in this format:
dow mon dd hh:mm:ss zzz yyyy
This is exactly what you see in your output. Note that the timezone of the machine running the program is printed in this case. If you wish to print this object in a format of your choice you should use a DateFormat. To get output for a specific timezone you have to explicitly tell it to the DateFormat object (see below).
Another thing is you should be using dd instead of DD in the pattern. D is for day in year and d is for day in month, which I believe is what you want. Now keeping in mind both the points, this is one of the solutions to your problem:
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdf.setTimeZone(TimeZone.getTimeZone("EDT")); // Time Zone for output
Date d = sdf.parse("2013-10-25 17:35:14 EDT");
System.out.println(sdf.format(d)); // You need format method
which outputs:
2013-10-25 17:35:14 EDT
What are the people answering not getting here is more the question:
2013-10-25 17:35:14 EDT != Sat Jan 26 03:05:14 IST 2013
I think it is because 'EDT' is the timezone and so, when it is 17:35 in EDT is is 3:05 in the UK, ignoring Daylight saving adjustments.

Date format return wrong date

I'm trying to format a Date object and convert that formatted one back to Date type object
This is my code
SimpleDateFormat inputDf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zzz");
System.out.println("before format "+invoiceDate);
invoiceDate=inputDf.parse(inputDf.format(invoiceDate));
System.out.println("after format "+inputDf.format(invoiceDate));
System.out.println("after parse "+invoiceDate);
Out put from above code is
before format : Mon Jan 14 10:55:40 IST 2013
after format : Mon Jan 14 2013 10:55:40 IST
after parse : Mon Jan 14 10:55:40 IST 2013
You can see here after i parse the date object it converting back to original format(format which shows before format) but i want Date object like it appear in second print line(after format) thing is .format method returns String not a Date object, how can i fix this ?
Thanks
The Date object doesn't define any format. Date is just a long number with time in it.
In order to modify its format you have to use a String object, as you did in your example.
If you analyze your example:
before format: Shows the DEFAULT format for a Date that System.out.println offers.
after format: Shows the format given after using the SimpleDateFormat.
after parse: We are again in the first case.
This behaviour is because the SimpleDateFomat does not impose itself upon the date. The SimpleDateFormat is merely a pattern to get a formated output out of any Date, but it does not change the date itself. Date does not have a format, so
System.out.println("before format "+invoiceDate);
defaults to the default pattern format.
Actually, the SimpleDateFormat is exactly the way to achieve what you want, ie use it to properly format your output everytime you need it. Formating a date object gives you a representation of it, a String.
System.out.println("after parse "+invoiceDate);
Here you just trying to print the Date object . The Date object , per se, doesn't have any format. The class Date represents a specific instant in time, with millisecond precision. Hence we use DateFormat to format the output string which is printed on printing the Date object . To display the same output as second statement , you need to format it again.
System.out.println("after parse"+inputDf.format(invoiceDate));
Look at the Javadoc for implementation of the toString() for Date :
Converts this Date object to a String of the form:
dow mon dd hh:mm:ss zzz yyyy

How can I use Java's SimpleDateFormat to parse a timezone given as "GMT+0100 (BST)"?

I have a date that's in the form of:
Wed Aug 17 2011 09:57:09 GMT+0100 (BST)
and have a filter that takes a time in a certain format. The problem seems to be the time zone on the end, none of the format strings I'm putting in the filter seem to work for this type of date format.
For example,
Wed Aug 17 2011 09:57:09 GMT+0100 (BST)
EEE MMM dd yyyy HH:mm:ss zZ?
The time zone part of this, keeps throwing an error.
Can anyone tell me what the correct format to parse the time zones on these dates is?
"z" needs a colon between hours and minutes. "Z" is only +/-HHMM (i.e. no "GMT" prefix).
One way to parse it is: EEE MMM dd yyyy HH:mm:ss 'GMT'Z. The "BST" bit is ignored, and it's based on assumption that there's always "GMT" before offset.
I would parse out and interpret the time zone information separately, then use that to construct the Date/Calendar object in the proper time zone.
The following code seems to work well enough with your example:
String source = "Wed Aug 17 2011 09:57:09 GMT+0100 (BST)";
String tzid = "GMT" + source.substring(28, 31)
+ ":" + source.substring(31, 33);
TimeZone tz = TimeZone.getTimeZone(tzid);
// if (tz == null) ?
SimpleDateFormat f = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
f.setTimeZone(tz);
Date date = f.parse(source);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println(date);
Prints "Wed Aug 17 08:57:09 UTC 2011".
A more sophisticated approach would be to use regex to extract individual parts ("+/-", "hh" and "mm") of the time zone offset.
Alternatively, you can attempt to discern the 3-letter time zone id (the string in between ( and )), and use the corresponding Java TimeZone if it exists.
In your particular example, though, "BST" resolves to Bangladesh Time which is GMT+0600 so you're better off with the numeric offset. "BST" here should probably be taken as British Summer Time (GMT+0100). This can be important because numeric offsets do not indicate the use of daylight savings time, which can be in effect depending on the date.
A more heuristic routine could take this into account and attempt to resolve the name first, but verify that the GMT offsets match, and fallback on the simple "GMT+hh:mm" timezones otherwise.
If you can not find a pattern matching your use case, try:
try{
new Date("Wed Aug 17 2011 09:57:09 GMT+0100 (BST)")
}catch(Exception e)
{
// Parse exception
}

Categories

Resources