This question already has answers here:
Java: unparseable date exception
(3 answers)
Closed 5 years ago.
I have implemented the following method to convert a String to a Date because the Date(String) constructor is deprecated:
private Date format(String inputString) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
try {
return dateFormat.parse(inputString);
} catch (ParseException e) {
return new Date();
}
}
One inputString sample is 2017-06-01T01:00:00Z. However, when I examine the output, I observe that the exception handler was triggered and new Date() was returned, meaning there's something wrong with my pattern: "Jun 17, 2017 1:12:02 PM".
What am I missing with the pattern yyyy-MM-dd'T'HH:mm:ssZ?
The Z pattern represents a numerical timezone offset. Thus the offset required here would be +0000.
The X pattern would allow you to use time zone offsets such as Z. (Yes, it seems counter-intuitive, but there you go.)
Source
I agree with the comments by Joe C and Louis Wassermann: stay off the long outdated Date class if there’s any way you can. And there is. The modern replacement classes are so much more convenient and programmer friendly.
Furthermore, your input string conforms to the ISO 8601 standard for an instant, a point in time, so fits the Instant class precisely. No need for any explicit formatter for parsing it. I suggest:
private static Instant parse(String inputString) {
try {
return Instant.parse(inputString);
} catch (DateTimeParseException dtpe) {
System.err.println("Parsing: " + dtpe);
return Instant.now();
}
}
Use the method like the following, for example:
String inputString = "2017-06-01T01:00:00Z";
System.out.println(parse(inputString));
This prints:
2017-06-01T01:00:00Z
Well, it’s the same string you started out from, because Instant.toString() produces the same ISO 8601 string back.
I admit scottb a point too: we sometimes need to interoperate with legacy code that does require an oldfashioned Date instance. If this is your case, produce one from Date.from(parse(inputString)). This will produce a Date equal to the instant (on my computer printed as Thu Jun 01 03:00:00 CEST 2017 because that happens to be my time zone). In any case I recommend converting to Date in the last moment before entering your legacy code to minimize your own use of it.
Just for the experiment, let’s try to use your incorrect format pattern string with the newer DateTimeFormatter class:
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ").parse(inputString);
This yields a java.time.format.DateTimeParseException: Text '2017-06-01T01:00:00Z' could not be parsed at index 19. It’s trying to be helpful to you: index 19 of 2017-06-01T01:00:00Z is where it says Z. As the two other answers say, this is exactly where the format pattern doesn’t match the input. Take my word, this is just one example out of many where you get better help from the modern classes than from the old ones.
You have a literal Z in your input string, so you need to quote that too (or use X). Like,
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
or better (as pointed out in the comments)
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
Also, don't throw away exceptions (at least print a stack trace). In Java 8+, you should be using the new java.time classes. That might look something like,
private static LocalDateTime format(String inputString) {
String pattern = "yyyy-MM-dd'T'HH:mm:ssX";
return LocalDateTime.from(DateTimeFormatter.ofPattern(pattern)
.parse(inputString));
}
Related
I have found that SimpleDateFormat::parse(String source)'s behavior is (unfortunatelly) defaultly set as lenient: setLenient(true).
By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds.
If I set the leniency to false, the documentation said that with strict parsing, inputs must match this object's format. I have used paring with SimpleDateFormat without the lenient mode and by mistake, I had a typo in the date (letter o instead of number 0). (Here is the brief working code:)
// PASSED (year 199)
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("03.12.199o"));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("03.12.199o")); //WTF?
In my surprise, this has passed and no ParseException has been thrown. I'd go further:
// PASSED (year 1990)
String string = "just a String to mess with SimpleDateFormat";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("03.12.1990" + string));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("03.12.1990" + string));
Let's go on:
// FAILED on the 2nd line
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("o3.12.1990"));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("o3.12.1990"));
Finally, the exception is thrown: Unparseable date: "o3.12.1990". I wonder where is the difference in the leniency and why the last line of my first code snippet has not thrown an exception? The documentation says:
With strict parsing, inputs must match this object's format.
My input clearly doesn't strictly match the format - I expect this parsing to be really strict. Why does this (not) happen?
Why does this (not) happen?
It’s not very well explained in the documentation.
With lenient parsing, the parser may use heuristics to interpret
inputs that do not precisely match this object's format. With strict
parsing, inputs must match this object's format.
The documentation does help a bit, though, by mentioning that it is the Calendar object that the DateFormat uses that is lenient. That Calendar object is not used for the parsing itself, but for interpreting the parsed values into a date and time (I am quoting DateFormat documentation since SimpleDateFormat is a subclass of DateFormat).
SimpleDateFormat, no matter if lenient or not, will accept 3-digit year, for example 199, even though you have specified yyyy in the format pattern string. The documentation says about year:
For parsing, if the number of pattern letters is more than 2, the year
is interpreted literally, regardless of the number of digits. So using
the pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
DateFormat, no matter if lenient or not, accepts and ignores text after the parsed text, like the small letter o in your first example. It objects to unexpected text before or inside the text, as when in your last example you put the letter o in front. The documentation of DateFormat.parse says:
The method may not use the entire text of the given string.
As I indirectly said, leniency makes a difference when interpreting the parsed values into a date and time. So a lenient SimpleDateFormat will interpret 29.02.2019 as 01.03.2019 because there are only 28 days in February 2019. A strict SimpleDateFormat will refuse to do that and will throw an exception. The default lenient behaviour can lead to very surprising and downright inexplicable results. As a simple example, giving the day, month and year in the wrong order: 1990.03.12 will result in August 11 year 17 AD (2001 years ago).
The solution
VGR already in a comment mentioned LocalDate from java.time, the modern Java date and time API. In my experience java.time is so much nicer to work with than the old date and time classes, so let’s give it a shot. Try a correct date string first:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.mm.yyyy");
System.out.println(LocalDate.parse("03.12.1990", dateFormatter));
We get:
java.time.format.DateTimeParseException: Text '03.12.1990' could not
be parsed: Unable to obtain LocalDate from TemporalAccessor:
{Year=1990, DayOfMonth=3, MinuteOfHour=12},ISO of type
java.time.format.Parsed
This is because I used your format pattern string of dd.mm.yyyy, where lowercase mm means minute. When we read the error message closely enough, it does state that the DateTimeFormatter interpreted 12 as minute of hour, which was not what we intended. While SimpleDateFormat tacitly accepted this (even when strict), java.time is more helpful in pointing out our mistake. What the message only indirectly says is that it is missing a month value. We need to use uppercase MM for month. At the same time I am trying your date string with the typo:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(LocalDate.parse("03.12.199o", dateFormatter));
We get:
java.time.format.DateTimeParseException: Text '03.12.199o' could not
be parsed at index 6
Index 6 is where is says 199. It objects because we had specified 4 digits and are only supplying 3. The docs say:
The count of letters determines the minimum field width …
It would also object to unparsed text after the date. In short it seems to me that it gives you everything that you had expected.
Links
DateFormat.setLenient documentation
Oracle tutorial: Date Time explaining how to use java.time.
Leniency is not about whether the entire input matches but whether the format matches. Your input can still be 3.12.1990somecrap and it would work.
The actual parsing is done in parse(String, ParsePosition) which you could use as well. Basically parse(String) will pass a ParsePosition that is set up to start at index 0 and when the parsing is done the current index of that position is checked.
If it's still 0 the start of the input didn't match the format, not even in lenient mode.
However, to the parser 03.12.199 is a valid date and hence it stops at index 8 - which isn't 0 and thus the parsing succeeded. If you want to check whether everything was parsed you'd have to pass your own ParsePosition and check whether the index is matches to the length of the input.
If you use setLenient(false) it will still parse the date till the desired pattern is meet. However, it will check the output date is a valid date or not. In your case, 03.12.199 is a valid date, so it will not throw an exception. Lets take an example to understand where the setLenient(false) different from setLenient(true)/default.
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
System.out.println(simpleDateFormat.parse("31.02.2018"));
The above will give me output: Sat Mar 03 00:00:00 IST 2018
But the below code throw ParseException as 31.02.2018 is not a valid/possible date:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("31.02.2018"));
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
Date test = dateFormat.parse(text);
The first three lines work fine. When I try to parse the string into a date again I get an error. How can I solve this?
The error looks like this:
Caused by: java.text.ParseException: Unparseable date: "2018-02-07T15:32:13.214+0100"
at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_151]
at TimeRange.parseDateFromIsoString(TimeRange.java:33) ~[classes/:na]
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
worked for me. With "SSSZ" instead of "SZ" at the end of the pattern.
I should like to contribute the modern answer. Because I discourage the use of SimpleDateFormat, more about that later.
java.time
OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("Europe/Rome"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
String text = dateTime.format(formatter);
OffsetDateTime test = OffsetDateTime.parse(text, formatter);
This produces a string like 2018-02-07T17:51:21.087+0100, pretty close to what I think you were after in the question, and parses it back nicely. With SSS in the format pattern string it always produces 3 decimals on the seconds and also requires exactly 3 decimals by parsing. You may use S or SSSSSS to get 1 or 6 decimals, for example. On my Java 9, OffsetDateTime.now() has a precision of 6 decimals (microseconds), so if I specify fewer, I lose precision in the formatting.
EDIT: For backward compatibility you cannot use the following, but for anyone reading along I should like to present a variant without an explicit formatter:
String text = dateTime.toString();
OffsetDateTime test = OffsetDateTime.parse(text);
The two differences in the produced string are:
It produces as many groups of 3 decimals as are necessary to render the precision. Usually 3 decimals on my Java 8 and 6 decimals on my Java 9, but occassionally it hits a round number of milliseconds and produces fewer decimals. It parses a string with everything from 0 through 9 decimals, so this doesn’t present a problem in parsing. And I always preserve the full presicion of the original OffsetDateTime object.
The offset from UTC is rendered with a colon, for example +01:00.
What went wrong in your code?
The SimpleDateFormat class is long outdated and notoriously troublesome, so even if you hadn’t had a problem with it at present, I would still recommend you drop it and use java.time, the modern Java date and time API, instead, as I do above.
One difference between the old SimpleDateFormat and the modern DateTimeFormatter is that while S in the modern formatter means fraction of second, in SimpleDateFormat it means milliseconds, so any other number than three is meaningless. However, it accepts other numbers. When formatting, your formatter produced enough digits for the milliseconds, for example 89 if there were 21.089 seconds or 214 when you had 13.214 as in the question.The former is incorrect, the 21.089 seconds were rendered as 21.89. I strongly believe that three-digit milliseconds caused your parsing to fail when you had only one S. On my Java 8 and 9 it works and also parses 21.89 as 21 seconds 89 milliseconds so the error evens out.
This behaviour agrees with the Java 9 documentation, which states: “For formatting, the number of pattern letters is the minimum number of digits, and shorter numbers are zero-padded to this amount. For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields.”
Link
Oracle tutorial: Date Time explaining how to use java.time.
SimpleDateFormat documentation for Java 9
I Removed Z in the simple date format which relates to time zone Which gives Correct out Put Below is the snippet.
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
I have the following date
2017-08-23-11.19.02.234850
it has the following date format
yyyy-MM-dd-HH.mm.ss.SSSSSS
What I want to do is to convert the date to format yyyy-MM-dd'T'HH:mm:ss.SSSSSS
I have the following code
public static void main(String[] args) {
String strDate = "2017-08-23-11.19.02.234850";
String dateFmt = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
System.out.println("converted Date: " + convertDate(strDate, dateFmt));
}
public static String convertDate(String strDate, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
sdf.setLenient(true);
try {
Date dateIn = sdf.parse(strDate);
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS").format(dateIn);
}catch(ParseException e) {
e.printStackTrace();
}
return "";
}
the result is
converted Date: 2017-08-23T11:22:56.000850
input date 2017-08-23-11.19.02.234850
converted date 2017-08-23T11:22:56.000850
doesn't look the same, it seems java is rounding the milliseconds besides if I turn lenient off for date validation
sdf.setLenient(false);
I get the following
java.text.ParseException: Unparseable date: "2017-08-23-11.19.02.234850"
at java.text.DateFormat.parse(Unknown Source)
at mx.santander.canonical.datamodel.enums.Main.convertDate(Main.java:74)
at mx.santander.canonical.datamodel.enums.Main.main(Main.java:66)
converted Date:
How to build a function which validates and converts date strings like this in a proper way?
EDIT:
I added a new function to obtain results
/**
* Gets the ISO 8601 date str from string.
*
* #param strDate the str date
* #return the ISO 8601 date str from string
*/
private String getISO8601DateStrFromString (String strDate) {
String responseISO8601Date = "";
if(strDate == null || "".equals(strDate.trim())) {
return responseISO8601Date;
}
try {
String strDtWithoutNanoSec = strDate.substring(0, strDate.lastIndexOf("."));
String strDtNanoSec = strDate.substring(strDate.lastIndexOf(".") + 1, strDate.length());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss");
formatter.setLenient(false);
Date date = formatter.parse(strDtWithoutNanoSec);
Timestamp t = new Timestamp(date.getTime());
t.setNanos(Integer.parseInt(strDtNanoSec));
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'");
NumberFormat nf = new DecimalFormat("000000");
responseISO8601Date = df.format(t.getTime()) + nf.format(t.getNanos());
} catch (ParseException | StringIndexOutOfBoundsException | NumberFormatException e) {
String errorMsg = String.format("The date provided for conversion to ISO 8601 format [%s] is not correct", strDate);
System.out.println(errorMsg);
}
return responseISO8601Date;
}
What I get:
Uptadet date 2017-12-20T11:19:02.234850
As others have already mentioned, your requirement does not fit the use of Date and SimpleDateFormat since these only support milliseconds, that is, three decimals on the seconds, where you have six decimals (microseconds). So we need to find some other way. This is basically a good idea anyway, since Date and SimpleDateFormat are long outdated, and today we have better tools for the job.
I have got two suggestions for you.
java.time
Even in Java 7 I think that it’s a good idea to use the modern Java date and time API that came out with Java 8, AKA JSR-310. Can you do that? Certainly; use the backport for Java 6 and 7, ThreeTen Backport. The modern API supports anything from 0 through 9 decimals on the seconds, and the code is straightforward when you know how:
private static DateTimeFormatter inputParser
= DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS");
private static DateTimeFormatter outputFormatter
= DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
public static String convertDate(String strDate) {
return LocalDateTime.parse(strDate, inputParser)
.format(outputFormatter);
}
I am using your own two format pattern strings. convertDate("2017-08-23-11.19.02.234850") returns 2017-08-23T11:19:02.234850.
There is a simplification possible: Since the format you want to obtain, conforms with ISO 8601, you don’t need an explicit formatter for it. The modern classes understand and produce ISO 8601 formats natively, so you may use:
return LocalDateTime.parse(strDate, inputParser).toString();
However, if the decimals on the seconds happened to end in 000, this will not print the last three zeroes. So if six decimals are required even in this case, use the formatter.
Regular expression
If you don’t want to rely on an external library, even temporarily until once you upgrade to Java 8 (or 9), your job can be done with a regular expression:
return strDate
.replaceFirst("^(\\d{4}-\\d{2}-\\d{2})-(\\d{2})\\.(\\d{2})\\.(\\d{2}\\.\\d{6})$",
"$1T$2:$3:$4");
It’s less elegant and harder to read, and it doesn’t offer the level of input validation you get from using a proper date and time API. Other than that, it’s a way through.
java.sql.Timestamp?
As others have said, java.sql.Timestamp offers nanosecond precision and thus will hold your date-time. Parsing your string into a Timestamp isn’t straightforward, though, so I don’t think it’s worth the trouble. Usagi Miyanmoto correctly identifies Timestamp.valueOf() as the method to use, but before you could do that, you would have change the format, so you would end up changing the format twice instead of just once. Or maybe three times since Timestamp also doesn’t produce your desired ISO 8601 format readily. Additionally you would need to decide a time zone for the timestamp, but I assume you could do that without any trouble.
If you needed to keep the the date-time around, a Timestamp object might be worth considering, but again, it’s a long outdated class. In any case, for reformatting alone, I certainly would not use it.
What happened in your code?
SimpleDateFormat understood 234850 as milliseconds, that is, 234 seconds 850 milliseconds. So it added 234 seconds to your time, 11:19:02. And then printed the remaining 850 milliseconds in 6 decimal places as you had requested.
Date has precision only till milli seconds. Please use timestamp instead - it has precision till nano seconds, which is expected in your case.
Please refer this answer - precision till nano seconds
TimeStamp API
A thin wrapper around java.util.Date that allows the JDBC API to
identify this as an SQL TIMESTAMP value. It adds the ability to hold
the SQL TIMESTAMP fractional seconds value, by allowing the
specification of fractional seconds to a precision of nanoseconds. A
Timestamp also provides formatting and parsing operations to support
the JDBC escape syntax for timestamp values.
SimpleDateFormat of Java does not support microsecond in pattern.
java.util.Date format SSSSSS: if not microseconds what are the last 3 digits?
You have several choices:
Manually handle the parsing and formatting of the microseconds
Switch to use Java 8 as Time API supports fraction of second in pattern (https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html)
If you need to use Java 7, consider using JODA Time for your date-time logics. JODA support fraction of second in its DateTimeFormat (http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html)
That result you got is expected. In your format string S were used. S is for milliseconds, hat is thousandths of seconds, and in this case the number of S's does not matter for parsing.
Your input string ends with 11.19.02.234850, the last part is interpreted as an integer value, and added to the date and time as milliseconds. That is as 234.850 seconds. Now, if you add 234 secs to 11:19:02, it becomes 11:22:56, just as you got in the result...
You cannot make a SimpleDateFormat mask that can parse microseconds into a Date, and Date cannot hold microseconds value either.
You have to choose, whether you want to use Date, or really need the finer then milliseconds resolution?
If you stick with Date, you should truncate the string of the last 3 characters.
Or you could use java.sql.Timestamp, which has a valueOf() method, hat uses SQL timestamp format.
Unfortunately it is not exactly he same as yours (being yyyy-[m]m-[d]d hh:mm:ss[.f...])...
Another way could be to split the string by separators (like [-.]), parse them to integers, and use hese integers with the Timestamp() constructor...
I am reading data from Wikidata. They represent their point in time property, P585 using ISO 8601 spec. However, the same beings with a +.
If I were using Joda then converting the String to joda dateTime would have been very simple.
new DateTime(dateTime, DateTimeZone.UTC);
However, when I do LocalDateTime.parse("+2017-02-26T00:00:00Z") I get an error saying can't parse the character at index 0. Is there a reason for this in Java 8. Joda does it pretty easily without any errors.
I also tried LocalDateTime.parse("+2017-02-26T00:00:00Z", DateTimeFormatter.ISO_DATE_TIME) but in vain.
How do we get around the Plus sign without having to remove it by string manipulation?
Java's DateTimeFormatter class may be of help. Here is some sample code that I believe addressses your problem (or at least gives you something to think about):
class DateTimeTester {
---
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("+yyyy-MM-dd'T'HH:mm:ss'Z'")
.withZone(ZoneId.of("UTC"));
LocalDateTime date = LocalDateTime.parse("+2017-02-26T01:02:03Z", formatter);
System.out.println(date);
}
}
Refer to the section called Patterns for Formatting and Parsing in the javadoc for DateTimeFormatter for details about the format-string passed to DateTimeFormatter.ofPattern().
Something to note:
Wikidata's list of available data types says about the time data type:
"explicit value for point in time, represented as a timestamp resembling ISO 8601, e.g. +2013-01-01T00:00:00Z. The year is always signed and padded to have between 4 and 16 digits.".
So Wikidata's time data type only resembles ISO 8601.
If your code needs to handle negative years (before year 0), you will need to adjust my suggested solution accordingly.
Unfortunately, the accepted answer is wrong for three reasons:
The given date-time string +2017-02-26T00:00:00Z does not represent a LocalDateTime. It represents an OffsetDateTime.
It uses a + sign with the pattern which means the pattern will fail to parse a date-time with a negative year.
'Z' is not the same as Z.
You can create the required DateTimeFormatter using the DateTimeFormatterBuilder as shown below:
class Main {
public static void main(String[] args) {
DateTimeFormatter parser = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 4, SignStyle.ALWAYS)
.appendPattern("-MM-dd'T'HH:mm:ssXXX")
.toFormatter(Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse("+2017-02-26T00:00:00Z", parser);
System.out.println(odt);
// If you want a LocalDateTime, you can get it from `odt`
LocalDateTime ldt = odt.toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2017-02-26T00:00Z
2017-02-26T00:00
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
A quick solution can be :
LocalDateTime.parse(yourDate, DateTimeFormatter.ISO_DATE_TIME);
Don't forget to manage the DateTimeParseException in the case of a non supported date format 😉
I have a varaibles:
Date date;
Time time;
and methods:
MyDateMethod(Date date){
//do stuff
}
MyTimeMethod(Time time){
//do stuff
}
I tried using MyDateMethod() with the following call:
MyDateMethod(1995-03-7);
I get an error saying I've supplied it with type int when it expected type Time.
I also tried using MyTimeMethod() with the following call:
MyTimeMethod(03:04:55);
I get an error saying Type mismatch: Cannot convert type int to boolean.
What is the format to put in a variable of these different types? Date is obviously not xxxx-xx-xx and Time is obviously not xx:xx:xx.
There are a few options,
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d = sdf.parse("1995-03-07");
System.out.println(d);
} catch (ParseException e) {
e.printStackTrace();
}
Output is
Tue Mar 07 00:00:00 EST 1995
Or, you could use
// -1 because January is 0... I didn't design it!
Calendar c = new GregorianCalendar(1995, 3 - 1, 7);
System.out.println(c.getTime());
with the same output as before.
SimpleDateFormat is what You need. It's need to be initialized by format of date.
Use it like this:
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy/MM/dd HH:mm:ss", Locale.getDefault());
and then:
Date date = (Date) dateFormat.parse("2014/04/02 22:22:22");
Take a look at DateFormat and particularly SimpleDateFormat.
Your example would be coded like this, using SimpleDateFormat:
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1995-03-07")
(I'm assuming you have months before days here, you will need to interchange the MM and dd if not).
Java does not support Date literals. You need to use a constructor or a static factory method to obtain an instance of this class.
1995-03-07 returns 1985 because you have three int literals here and the hyphens are interpreted as subtraction operators.
Take a look at the documentation for the Date class and the DateFormat class
Here's a way you could represent these values:
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = dateFormat.parse("1995-03-07");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
Date time = timeFormat.parse("03:46:16");
You can use the same format objects to perform the reverse of this conversion. Please mind that these Date instances represent a specific moment in time, down to millisecond level. Internally, this is represented as the number of milliseconds since January 1, 1970, 00:00:00 GMT
This API is hardly the prettiest one in Java and by looking at the docs you can see how many changes it has undergone. Just look at the number of deprecated methods.
I recommend taking a look at the Joda-Time library instead.
Alternatively, if using Java 8 is an option for you, you can try the brand new API that comes with it
The answer by Tom is correct. No date-time literals inJava.
And as he stated, the old bundled java.util.Date and .Calendar classes are notoriously troublesome. Avoid them. Use either the Joda-Time library or the new java.time package in Java 8.
Joda-Time
In Joda-Time:
If you want only a date without time and time zone, use the LocalDate class.
Similarly to use only time while ignoring time zone and date, use the LocalTime class.
But most often you'll probably want to use the DateTime class which tracks date, time, and time zone all in one object.
A Date-Time Is Not Text
A DateTime object does not contain text. No String. If you need a string representation, use a formatter object to generate one. Search StackOverflow for many examples.
Built into Joda-Time are formatters for the sensible and increasingly common ISO 8601 standard. For example, the toString implementation on the DateTime class produces a String like this…
2014-04-01T20:17:35-08:00