I am trying to parse 14th March 2011 to a date in Java for a time converter application... I get 26th Dec 2010... Please help.
import java.util.*;
import java.text.*;
class date {
public static void main(String[] args) {
try {
String timestampOrig = "11/03/14,15:00:00";
SimpleDateFormat inFormat = new SimpleDateFormat("YY/MM/dd','HH:mm:ss");
Date parseDate = inFormat.parse(timestampOrig);
System.out.println("parsed date: " + parseDate.toString());
}
catch(ParseException pe){
}
}
}
output:
parsed date: Sun Dec 26 15:00:00 EST 2010
YY should be yy (in lower case). You can find the list of available characters and their meaning in the documentation.
Out of curiosity, more information about YY, which is for week year, here (not 100% sure what it is to be honest).
java.time
I am providing the modern answer using java.time, the modern Java date and time API (since March 2014).
DateTimeFormatter inFormat = DateTimeFormatter.ofPattern("uu/MM/dd,HH:mm:ss");
String timestampOrig = "11/03/14,15:00:00";
LocalDateTime parsedDateTime = LocalDateTime.parse(timestampOrig, inFormat);
System.out.println("parsed date: " + parsedDateTime.toString());
Output is:
parsed date: 2011-03-14T15:00
I recommend you don’t use SimpleDateFormat and Date. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use LocalDateTime and DateTimeFormatter, both from java.time, the modern Java date and time API. The modern API is so much nicer to work with. And BTW would throw an exception if you tried with YY for year, which I find somewhat more helpful for catching your error.
The quotes around the comma in the format pattern string are optional. I know that the documentation recommends them, but I find the format pattern string more readable without them, so left them out.
What went wrong in your code?
Uppercase Y in the format patterns string is for week based year and only useful with a week number. Apperently SimpleDateFormat wasn’t able to combine your specified month and day of month with the week based year of 2011 and instead just took the first day of the week-based year (this is typical behaviour of SimpleDateFormat, giving you a result that cannot be but wrong and pretending all is well). Assuming your locale is American or similar, week 1 is the week that contains January 1 and begins on the Sunday of the same week, therefore in this case the last Sunday of the previous year, December 26, 2010.
With java.time you may use either lowercase y or u for year. The subtle difference is explained in the question linked to at the bottom. In any case a two-digit year is interpreted into the range from year 2000 through 2099 (there are ways to control the interpretation if you need to).
Links
Oracle tutorial: Date Time explaining how to use java.time.
Question: uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java?
Related
I am trying to convert a String with format 1/1/2010 3:23:12 PM +00:00 to a Java.util.Date
Unable to convert the String format to a Java Date.
It is not identifying the time asAM/PM
String s = "1/1/2010 3:23:12 PM +00:00";
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss a",Locale.ENGLISH);
Date date = sdf.parse(s));
Need the date converted with time identified as AM/PM
OffsetDateTime is what you're looking for.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy h:mm:ss a XXX");
OffsetDateTime time = OffsetDateTime.parse(str, formatter);
System.out.println(time);
Your pattern has some problems:
Your day-of-the-month is without a leading zero, yet you are using dd;
Same for month with MM;
Same for hour with HH;
You are using AM/PM in conjunction with a 24-hour hour format specifier (H); you should use h instead.
I don't know exactly how SimpleDateFormat handles the timezone part of the string, but no formatting specifiers for the timezone are given.
That's one of the reasons why I like this Date and Time API: it's pretty straightforward.
Ideone example
Unable to convert the String format to a Java Date. It is not
identifying the time as AM/PM
You are asking the impossible. A Date is a point in time (internally implemented as a count of milliseconds since the so-called epoch), so it “knows” nothing about AM and PM in your time zone.
That’s just the same, though, because the Date class was always poorly designed and is fortunately long outdated. You should not use it at all.
java.time
java.time, the modern Java date and time API that we should use instead of Date, comes closer to fulfilling your requirement. MC Emperor has already shown the basic code you need for parsing your datetime string. The output from his code is:
2010-01-01T15:23:12Z
There’s no AM or PM here. When we print an OffsetDateTime in this way, its toString method is implicitly called. It produces an ISO 8601 formatted string. ISO 8601 prescribes a 24 hour clock (no AM or PM). But! With assistance from the correct TemporalField object the OffsetDateTime is able to calculate and return whether it is in AM or PM. time.get(ChronoField.AMPM_OF_DAY) returns 0 for AM or 1 for PM:
System.out.println("AM or PM? 0 for AM. 1 for PM. time: "
+ time.get(ChronoField.AMPM_OF_DAY));
AM or PM? 0 for AM. 1 for PM. time: 1
So in this case we got 1 for PM as expected since your original string had PM in it.
I have deliberately not answered all of your question because much of it has been covered in other Stack Overflow questions and their answers already. So it’s better to keep the information there. I include links to a couple of relevant questions below.
What went wrong in your code?
There are at least two bugs in your code that each cause you to get an incorrect result. I tried running your code in America/Los_Angeles time zone and got
Fri Jan 01 03:23:12 PST 2010
The time printed is on a 24 hour clock (Date always does that), so we got 03:23:12 AM instead of PM. And we got the time in the default time zone (PST is for Pacific Standard Time), so the point in time corresponds to 11:23:12 AM at offset +00:00, the offset in the string.
The wrong clock hour comes from conflicting indications in your code: HH in the format pattern string is for hour of day from 00 through 23, so 3 is taken to mean 03 AM and apparently “wins” over the PM marker (for hour within AM or PM, from 1 through 12, you would have needed lowercase h).
The default time zone comes from the fact that you are making no attempt to parse the offset from the string (in conjunction with SimpleDateFormat being satisfied with not parsing all of the string).
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
Question: want current date and time in “dd/MM/yyyy HH:mm:ss.SS” format
Question: Unable to parse DateTime-string with AM/PM marker
Question: Display current time in 12 hour format with AM/PM
Question: Convert String to java.util.Date
I am trying to parse following date time string
2018-01-30T23:59:59.000
I am not able to understand which standard format it is like UTC or ISO_8601
while parsing in the following manner:
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'HH:MM:SS:MS");
Date date = null;
try {
date = sdf.parse("2018-01-30T23:59:59.000");
} catch (ParseException e) {
e.printStackTrace();
}
But It is throwing following exception:
java.text.ParseException: Unparseable date: "2018-01-30T23:59:59.000"
Any help is appreciated.
See the doc of SimpleDateFormat and try this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime dateTime = LocalDateTime.parse("2018-01-30T23:59:59.000");
System.out.println(dateTime);
This prints:
2018-01-30T23:59:59
Your string is in ISO 8601 format. UTC or Coordinated Universal Time is not a format, it is a standard time used to define the time the rest of use in our respective time zones.
The date-time classes you were using, SimpleDateFormat and Date, are long outdated and the former in particular notoriously troublesome. I recommend that you instead use java.time, the modern Java date and time API. It is so much nicer to work with.
A LocalDateTime is a date with time of day and without time zone or offset from UTC. Its one-argument parse method parses ISO 8601, which is why no explicit formatter is needed.
What went wrong in your code
Your format pattern string has a number of issues to it. Which is one reason why you should appreciate the above solution without any explicit formatter. The first thing that goes wrong is: Your format pattern string has a colon, :, between seconds and milliseconds, whereas your date-time string has a dot, .. This is why you get the exception.
However, fixing this, your code yields the following Date:
Sun Dec 31 23:00:00 CET 2017
It’s one month off from the expected, and the minutes and seconds are missing. Because:
Uppercase YYYY is for week-based year and only useful with a week number. You need lowercase yyyy for year.
Uppercase DD is for day of year. You need lowercase dd for day of month.
You correctly used uppercase MM for month. Trying the same again for minutes won’t work. Maybe you can guess by now: it’s lowercase mm.
Not surprising you need lowercase ss for seconds.
UsingMS for milliseconds is interesting. SimpleDateFormat takes it as M for month (which we’ve already had twice before) and uppercase S for millisecond. Instead you needed uppercase SSS for the three digits of milliseconds.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
Wikipedia article: Coordinated Universal Time on UTC
You need to escape the literal T:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:SS");
See This SO Answer for more examples
Update: Your string is in the format
yyyy-MM-dd'T'HH:mm:ss.SSS
but you are trying to parse it with a completely uppercase format string.
This does not do what you want it to do and you should read the documentation on SimpleDateFormat and the format string placeholders
I need to parse a string to date in java. My string has the following format:
2014-09-17T12:00:44.0000000Z
but java throws the following exception when trying to parse such format... java.lang.IllegalArgumentException: Illegal pattern character 'T'.
Any ideas on how to parse that?
Thank you!
Given your input of 2014-09-17T12:00:44.0000000Z, it is not sufficient to escape the letter T only. You also have to handle the trailing Z. But be aware, this Z is NOT a literal, but has the meaning of UTC+00:00 timezone offset according to ISO-8601-standard. So escaping Z is NOT correct.
SimpleDateFormat handles this special char Z by pattern symbol X. So the final solution looks like:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX");
Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
System.out.println(d); // output: Wed Sep 17 14:00:44 CEST 2014
Note that the different clock time is right for timezone CEST (toString() uses system timezone), and that the result is equivalent to UTC-time 12:00:44. Furthermore, I had to insert seven symbols S in order to correctly process your input which pretends to have precision down to 100ns (although Java pre 8 can only process milliseconds).
You have to escape the 'T' character:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date parse = format.parse("2014-09-17T12:00:44.0000000Z");
Using Answer to: What is this date format? 2011-08-12T20:17:46.384Z
java.time
It is time for the modern answer: always use java.time, the modern Java date and time API, for your date and time work. When this question was asked, java.time had been out with Java 8 for 7 months. Today (2020) no one should use the SimpleDateFormat class that appears to have been the trouble in the question. It is notoriously troublesome and long outdated.
Using java.time we need no explicit formatter:
String str = "2014-09-17T12:00:44.0000000Z";
Instant i = Instant.parse(str);
System.out.println("As Instant: " + i);
Output is:
As Instant: 2014-09-17T12:00:44Z
Your format is ISO 8601 (link at the bottom). The classes of java.time generally parse ISO 8601 as their default and print ISO 8601 back from their toString methods. In ISO 8601 the fraction of second is optional.
If you need a Date object for a legacy API not yet upgraded to java.time:
Date oldfashionedDate = Date.from(i);
System.out.println("As old-fashioned Date: " + oldfashionedDate);
Output in my time zone:
As old-fashioned Date: Wed Sep 17 14:00:44 CEST 2014
Output will vary by time zone because Date.toString() confusingly takes the JVM’s default time zone and uses it for rendering the string.
What went wrong for you?
You haven’t shown us your code, but we can already tell that a couple of things are wrong:
SimpleDateFormat cannot parse a string with 7 fractional digits on the seconds correctly. It supports only milliseconds, exactly three decimals.
In your format pattern string you need to escape the literal T by enclosing it in single quotes, 'T', or SimpleDateFormat will understand it as a pattern letter, and there is no format pattern letter T. This is what your exception message meant.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601.
Related question: Date object SimpleDateFormat not parsing timestamp string correctly in Java (Android) environment about parsing more than three decimals on the seconds.
Related question: ISO 8601 String to Date/Time object in Android.
Try this.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateClass {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
System.out.println(d); //output Wed Sep 17 12:00:44 IST 2014
}
}
Consider this code:
Date date = new SimpleDateFormat("MMddyyyy").parse("01011500");
LocalDate localDateRight = LocalDate.parse(formatter.format(date), dateFormatter);
LocalDate localDateWrong = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();
System.out.println(date); // Wed Jan 01 00:00:00 EST 1500
System.out.println(localDateRight); // 1500-01-01
System.out.println(localDateWrong); // 1500-01-10
I know that 1582 is the cutoff between the Julian and Gregorian calendars. What I don't know is why this happens, or how to adjust for it.
Here's what I've figured out so far:
The date Object has a BaseCalender set to JulianCalendar
date.toInstant() just returns Instant.ofEpochMilli(getTime())
date.getTime() returns -14830974000000
-14830974000000 is Wed, 10 Jan 1500 05:00:00 GMT Gregorian
So it seems like either the millis returned by getTime() is wrong (unlikely) or just different than I expect and I need to account for the difference.
LocalDate handles the proleptic gregorian calendar only. From its javadoc:
The ISO-8601 calendar system is the modern civil calendar system used
today in most of the world. It is equivalent to the proleptic
Gregorian calendar system, in which today's rules for leap years are
applied for all time. For most applications written today, the
ISO-8601 rules are entirely suitable. However, any application that
makes use of historical dates, and requires them to be accurate will
find the ISO-8601 approach unsuitable.
In contrast, the old java.util.GregorianCalendar class (which is indirectly also used in toString()-output of java.util.Date) uses a configurable gregorian cut-off defaulting to 1582-10-15 as separation date between julian and gregorian calendar rules.
So LocalDate is not useable for any kind of historical dates.
But bear in mind that even java.util.GregorianCalendar often fails even when configured with correct region-dependent cut-off date. For example UK started the year on March 25th before 1752. And there are many more historical deviations in many countries. Outside of Europe even the julian calendar is not useable before introduction of gregorian calendar (or best useable only from a colonialist perspective).
UPDATE due to questions in comment:
To explain the value -14830974000000 let's consider following code and its output:
SimpleDateFormat format = new SimpleDateFormat("MMddyyyy", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
Date d = format.parse("01011500");
long t1500 = d.getTime();
long tCutOver = format.parse("10151582").getTime();
System.out.println(t1500); // -14830974000000
System.out.println(tCutOver); // default gregorian cut off day in "epoch millis"
System.out.println((tCutOver - t1500) / 1000); // output: 2611699200 = 30228 * 86400
It should be noted that the value -12219292800000L mentioned in your earlier comment is different by 5 hours from tCutOver due to timezone offset difference between America/New_York and UTC. So in timezone EST (America/New_York) we have exactly 30228 days difference. For the timespan in question we apply the rules of julian calendar that is every fourth year is a leap year.
Between 1500 and 1582 we have 82 * 365 days + 21 leap days. Then we have also to add 273 days between 1582-01-01 and 1582-10-01, finally 4 days until cut-over (remember 4th of Oct is followed by 15th of Oct). At total: 82 * 365 + 21 + 273 + 4 = 30228 (what was to be proved).
Please explain to me why you have expected a value different from -14830974000000 ms. It looks correct for me since it handles the timezone offset of your system, the julian calendar rules before 1582 and the jump from 4th of Oct 1582 to cut-over date 1582-10-15. So for me your question "how do I tell the date object to return the ms to the correct Gregorian date?" is already answered - no correction needed. Keep in mind that this complex stuff is a pretty long time in production use and can be expected to work correctly after so many years.
If you really want to use JSR-310 for that stuff I repeat that there is no support for gregorian cut-over date. The best thing is that you might do your own work-around.
For example you might consider the external library Threeten-Extra which contains a proleptic julian calendar since release 0.9. But it will still be your effort to handle the cut-over between old julian calendar and new gregorian calendar. (And don't expect such libraries to be capable of handling REAL historic dates due to many other reasons like new year start etc.)
Update in year 2017: Another more powerful option would be using HistoricCalendar of my library Time4J which handles much more than just julian/gregorian-cutover.
I'm working on taking a date value (createWhen) from Active Directory, and translating it into a Java date, for the purposes of getting a list of accounts created between two dates. Everything is working fine, save for one method: the method where I go from the AD Date to the Java date. The method looks like this:
private Date getParsedDate(String givenString) {
System.out.println("Value from AD is: " + givenString);
Date parsedDate = null;
String formattedString = this.formatDateString(givenString);
System.out.println("Formatted String is: " + formattedString);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/DD");
try {
parsedDate = sdf.parse(formattedString);
System.out.println("Final date string is: " + parsedDate.toString());
} catch (ParseException ex) {
ex.printStackTrace();
}
return parsedDate;
}
And, for a single piece of arbitrary data from AD:
Value from AD is: 20050912190509.0Z
Formatted String is: 2005/09/12
Final date string is: Wed Jan 12 00:00:00 EST 2005
Obviously, it's picking up the day and year correctly (and if I choose to include hours/minutes/seconds it includes those correctly as well), but every single date is being placed in January for some reason.
Now, I'm sure that my error is a pretty simple one, but I've rechecked my formatting about ten times, and I'm at the point where I just can't see it any more. Can a second pair of eyes hopefully look over my code and point out where I'm going wrong to get the month so grossly incorrect?
Thanks.
Change the pattern string from "yyyy/MM/DD" to "yyyy/MM/dd"
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Make sure you don't use 'mm' instead of 'MM' or 'MMM'. As small m denotes minutes and caps M denotes month.
TL;DR
LocalDate parsedDate = OffsetDateTime
.parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
.toLocalDate();
This yields a LocalDate of 2005-09-12.
java.time
I am contributing the modern answer. Suhas Phartale’s answer is correct and was a good answer when it was written 7 years ago. Now the notoriously troublesome SimpleDateFormat class is long outdated and we have so much better in java.time, the modern Java date and time API. I warmly recommend you use this instead of the old date-time classes.
Details
It seems from your code that you reformat your string from AD before parsing it. There’s no need for that, the string from AD can be parsed directly. We might have parsed it directly into a LocalDate, but I recommend parsing it into an OffsetDateTime to grab the time and offset from the string; as you can see, this can be directly converted to a LocalDate afterwards. A LocalDate is a date without time of day, so it seems to match your requirements better than the old Date class.
The string is in UTC (denoted by the Z in the end). The above gives you the date from the string, that is the date in UTC. If instead you wanted the date it was in your local time zone when it was September 12 19:05 in UTC:
LocalDate parsedDate = OffsetDateTime.parse(givenString, adDateTimeFormatter)
.atZoneSameInstant(ZoneId.of("America/Coral_Harbour"))
.toLocalDate();
I assumed we have declared the formatter a static field:
private static final DateTimeFormatter adDateTimeFormatter
= DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX");
In this case the result is the same, for other time zones it will not be. Please substitute your own desired time zone for America/Coral_Harbour. To use the JVM’s time zone setting, specify ZoneId.systemDefault(). Beware, however, that the setting may be changed by other parts of your program or other programs running in the same JVM, so this is fragile.
And the point from Suhas Phartale’s answer is valid in java.time too: format pattern strings are case sensitive, and I needed to use lowercase dd for day of month.
Tutorial
Learn more about java.time in the Oracle tutorial and/or search for other resources on the net.
I am posting this answer because i was redirected from here and above solutions did not resolve my issue
For me the scenario was that after parsing this date "2020-03-01T07:00:00+0530" i was getting the result as 1/2 [dd/MM] which is the format that i wanted, but that result contained the wrong month since the date string clearly indicates the month is 3 [MARCH].
So basically cal.get(Calendar.DAY_OF_MONTH) was returning me 2 instead of actual 3.
And as per docs in MONTH section
"the first month of the year in the Gregorian and Julian calendars is
JANUARY which is 0; the last depends on the number of months in a
year."
so we just need to add a +1 and we would get the actual month. Guess this behavior is there may be to return the names of month from month array or so ?! [January,February,etc..]
Below is a sample of my implementation (my date format in string is "yyyy-MM-dd'T'HH:mm:ssZ"):
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(Constant.DATE_FORMAT_WITH_TIMEZONE,Locale.ENGLISH);
try {
cal.setTime(Objects.requireNonNull(sdf.parse(forecastList.get(listPosition).fcst_valid_local)));
} catch (ParseException e) {
e.printStackTrace();
}
String s = "%s/%d";
String output = String.format(s,cal.get(Calendar.DAY_OF_MONTH),(cal.get(Calendar.MONTH)+1)));
hope this helps some one.