I want to save a Date object to a readable string (for example 22/10/2009 21:13:14) that is also parsable back to a Date object.
I have tried many things and the best I could find was to use DateFormater for parsing and formating but it has a setback. When you format a date you lose seconds information. I tried to find if there is an option to format it and display the seconds (even better would be to the millisecond level since that's the resolution the Date object allows you to have) but I came up short.
Any ideas?
Take a look at java.text.SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS");
Date dt = new Date();
String S = sdf.format(dt); // formats to 09/23/2009 13:53:28.238
Date dt2 = sdf.parse(S); // parses back
SimpleDateFormat can format and parse a date based on a very simple pattern system that include second and even milliseconds.
Other answers are all good.
But when doing this kind of thing please pick a format that sorts properly when coded as a string.... "yyyy/MM/dd HH:mm:ss" is fine. It always astounds me when software engineers pick a date format which doesn't sort in the obvious, convenient way.
You'll save your fellow developers a lot of pain at some distant point in the future - think of it as good karma :-)
ISO 8601
Use ISO 8601 format.
It’s flexible, it includes seconds and fraction of second if there are any, but you may also leave them out if they are 0.
It’s standard, so more and more tools format and parse it. Great for serialization for storage or data interchange.
It goes like 2009-10-22T21:13:14, I should say it’s pretty human-readable (though the T in the middle that denotes the start of the time part may feel unusual at first).
The strings sort properly, as mikera requested in another answer, as long as the years are in the four-digit range from 1000 through 9999.
The classes of java.time, the modern Java date and time API, as well as those of Joda Time parse ISO 8601 as their default, that is, without any explicit formatter, and produce the same format from their toString methods.
A modest demonstration of using java.time:
LocalDateTime dateTime = LocalDateTime.of(2009, 10, 22, 21, 13, 14);
String readableString = dateTime.toString();
System.out.println(readableString);
LocalDateTime parsedBack = LocalDateTime.parse(readableString);
System.out.println(parsedBack);
This prints two identical lines:
2009-10-22T21:13:14
2009-10-22T21:13:14
The latter System.out.println() call implicitly calls toString() once more, so this shouldn’t surprise.
A little off-topic, but I always feel the need to remind people that DateFormat and SimpleDateFormat are not thread safe! The Sun documentation clearly states this, but I keep finding code out in the wild where people stick a SimpleDateFormat in a static ...
If you want to do it a little simpler, and be spared from making your own DateFormat that most other Answers involve, you can leverage the default format in java.time.Instant:
(new Date()).toInstant.toString();
Related
I have a soap webservice with a date tag with the following format
2019-12-01T04:00:00.0000000Z (seven zeros)
Now that I am implementing the client I cannot create an XMLGregorianCalendar with seven zeros, I only have three zeros left
My code
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'");
Date date = df.parse("2019-12-01T04:00:00.0000000Z");
GregorianCalendar gcal = new GregorianCalendar();
gcal.setTime(date);
gcal.setTimeZone(TimeZone.getTimeZone("UTC"));
XMLGregorianCalendar fecha = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
System.out.println("fecha ->"+fecha.toString());
output
fecha ->2019-12-01T07:00:00.000Z
How can I make the XMLGregorianCalendar keep me with seven zeros in the format?
You probably don’t need 7 decimals
Generally a SOAP web service doesn’t require any particular number of decimals on the seconds of a time. It needs XML with date and time in XML format. XML’s date and time format is inspired from ISO 8601 format (links at the bottom). The W3Schools page on Date and Time Data Types doesn’t even mention the possibility of specifying any fraction of second:
The dateTime is specified in the following form "YYYY-MM-DDThh:mm:ss" …
Fraction of second is allowed, though, “to an arbitrary level of precision” to quote W3C’s XML Schema Part 2: Datatypes Second Edition. So if your web service insists on exactly 7 decimals, it’s a peciliar and unusual restriction. You may want to challenge it.
Alternatives to XMLGregorianCalendar
The XMLGregorianCalendar class is old now. It was used exactly for producing ISO 8601 format for XML documents as used with SOAP and in many other places. The classes of java.time, the modern Java date and time API, produce ISO 8601 format too. We prefer to use these (unless very special requirements necessitate XMLGregorianCalendar).
OffsetDateTime odt = OffsetDateTime.of(2019, 12, 1, 4, 0, 0, 0, ZoneOffset.UTC);
System.out.println(odt);
This snippet outputs:
2019-12-01T04:00Z
If you do need 7 decimals, use a formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSSSX");
System.out.println(odt.format(formatter));
2019-12-01T04:00:00.0000000Z
Of course, if you already got your string, 2019-12-01T04:00:00.0000000Z, as in your question, just put it into your XML document directly. If you need to validate it first, pass it to Instant.parse() and see if you get a DateTimeFormatException.
If you really cannot avoid the need for an XMLGregorianCalendar with 7 decimals on the seconds, there are two ways to produce one:
DatatypeFactory.newXMLGregorianCalendar(String) as used in the other answer:
XMLGregorianCalendar fecha = DatatypeFactory.newInstance()
.newXMLGregorianCalendar("2019-12-01T04:00:00.0000000Z");
System.out.println(fecha);
2019-12-01T04:00:00.0000000Z
Passing a BigDecimal to DatatypeFactory:
XMLGregorianCalendar fecha = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(BigInteger.valueOf(2019), 12, 1,
4, 0, 0, new BigDecimal("0.0000000"), 0);
In any case, under all circumstances I recommend you don’t use SimpleDateFormat and Date. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. The same is true for GregorianCalendar. We might sometimes use it with XMLGregorianCalendar because conversion between the two exist (as used in your question). GregorianCalendaronly has millisecond precision, so you will never get 7 decimals through such a conversion.
Bugs in your code
There are two bugs in your code.
Hardcoding Z as a literal in your format pattern string is wrong. Z is an offset (of zero) from UTC and needs to be parsed as such, or you will get a wrong time on the vast majority of JVMs.
SimpleDateFormat too only supports milliseconds, exactly three decimals in the seconds. When the fraction is all zeroes, you won’t notice the error, but as soon as someone puts in a non-zero digit somewhere, you will get an incorrect result. There is no way that SimpleDateFormat can handle 2 or 4 or 7 fractional digits correctly.
Links
XML Schema Part 2: Datatypes Second Edition on W3C.
Subsection D ISO 8601 Date and Time Formats
XSD Date and Time Data Types on W3Schools
ISO 8601 on Wikipedia
Oracle tutorial: Date Time explaining how to use java.time.
You can use the factory method that accepts a lexical representation of the data type:
XMLGregorianCalendar fecha = DatatypeFactory.newInstance().newXMLGregorianCalendar(df.format(date));
This question already has answers here:
want current date and time in "dd/MM/yyyy HH:mm:ss.SS" format
(11 answers)
Closed 4 years ago.
I am trying to convert a java.util.Date to XMLGregorianCalendar in Italian format (dd/mm/yyyy) with no time. Whatever I try the output always prints yyyy-mm-dd.
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Rome"));
XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH),
DatatypeConstants.FIELD_UNDEFINED);
System.out.println(xmlDate);
I am a consumer of SOAP web-service, and the date attribute is defined as XMLGregorianCalendar.
Please advise how can I change the code to get the output with format (dd/mm/yyyy).
You don’t need an XMLGregorianCalender. It will not, cannot give you what you ask for. Instead you need a LocalDate and a DateTimeFormatter:
DateTimeFormatter italianDateFormatter
= DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(Locale.ITALIAN);
LocalDate date = LocalDate.now(ZoneId.of("Europe/Rome"));
String formattedDate = date.format(italianDateFormatter);
System.out.println(formattedDate);
When I ran this code today, the output was:
21/01/19
The difference from what you ask for is the two digit year, 19. If instead of FormatStyle.SHORT we use FormatStyle.MEDIUM, we get four digit year, but the month as a three letter abbreviaiton:
21-gen-2019
The advantage is that the code lends itself very well to internationalization: you just need to change the locale to get proper code for some other language and country. If you do need 21/01/2019 (with four digit year), specify the format explicitly using a pattern:
DateTimeFormatter italianDateFormatter
= DateTimeFormatter.ofPattern("dd/MM/uuuu");
21/01/2019
What’s wrong with using XMLGregorianCalendar?
When you call System.out.println(xmlDate), you are implicitly calling toString on your XMLGregorianCalendar. When it hasn’t got time and zone offset, toString always generates yyyy-MM-dd format, there is no way you can change that. On the other hand you can have any format you like in a String. Next obstacle is, there is no formatter that can format an XMLGregorianCalendar directly. You would need to convert to a different type, like ZonedDateTime, for example, first. Since you only want the date, neither the time of day nor the time zone, it’s simpler and easier to start out from LocalDate from the start. Not least for those reading and maintaining your code after you.
Your question mentions java.util.Date and your code uses GregorianCalendar too. Both of those classes are poorly designed and long outdated, fully replaced by java.time, the modern Java date and time API. So I suggest you don’t use them.
Link
Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API.
I'm wondering if there is a static String or DateFormat anywhere in the standard Java library for formatting dates 'completely'. By completely, I mean the date and time including milliseconds and timezone, something along the lines of "dd MMM yyyy HH:mm:ss.SSS zzz". It's easy to just declare the string myself, but it would be nice if I didn't have to do that for every project I use that needs millisecond-precision date parsing. I have been unable to find one so far.
As an aside, I think it's a little silly that java.util.Date#toString() doesn't account for milliseconds when the class it represents does.
Edit - Unfortunately, it is not as simple as beginning the conversion over to DateTime usage, as that is not something that is in my control. I am the 2nd most junior developer on the project. I would love to use DateTime going forward, but without the support of my supervisor, I cannot.
Also for Java 8 Date Time Api you can use
LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
for results like that
2017-03-27T20:46:03.852
I am having problems parsing time strings in Java that are in the format of 2013-01-09 09:15:03.000000. In my data, the last three digits are always 0 (meaning the input strings have only millisecond precision), so I passed this format to SimpleDateFormat:
formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS'000'");
but formatter.parse("2013-01-09 09:15:02.500000"); throws an exception:
Unparseable date: "2013-01-09 09:15:02.500000"
at java.text.DateFormat.parse(DateFormat.java:357)
Anyone knows how to do it correctly? I can work around by using format yyyy-MM-dd HH:mm:ss.SSS and using substring to get rid of last three digits but that's really hacky.
EDIT: can anyone explain why the format string yyyy-MM-dd HH:mm:ss.SSS'000' can't be used to parse time "2013-01-09 09:15:02.500000"
try java.sql.Timestamp
Timestamp ts = Timestamp.valueOf("2013-01-09 09:15:03.500000");
Date date = new Date(ts.getTime())
it's also thread-safe and fast as opposed to SimpleDateFormat
java.time
I should like to contribute the modern answer. Use java.time, the modern Java date and time API. One option, you may use a formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS");
LocalDateTime dateTime = LocalDateTime.parse(timeString, formatter);
System.out.println(dateTime);
When using the string from your question, "2013-01-09 09:15:02.500000", this printed:
2013-01-09T09:15:02.500
If you want the value printed with six decimals on the seconds even when the last three decimals are 0, use the same formatter to format the time back into a string:
System.out.println(dateTime.format(formatter));
The other option, you may exploit the fact that your string resembles the ISO 8601 format, the format that the modern classes parse as their default, that is, without any explicit formatter. Only ISO 8601 has a T to denote the start of the time part, but we can fix that easily:
LocalDateTime dateTime = LocalDateTime.parse(timeString.replace(' ', 'T'));
It gives the same result, 2013-01-09T09:15:02.500. It’s shorter, but also more tricky.
Why bother?
The classes Date and Timestamp are long outdated, and SimpleDateFormat in particular has proven troublesome. Its surprising behaviour in your situation is just one little story out of very many. The modern API is generally so much nicer to work with.
Why didn’t your formatter work?
While the format pattern strings used by SimpleDateFormat and DateTimeFormatter are similar, there are differences. One is that SimpleDateFormat understands uppercase S as milliseconds no matter of there are one or nine of them, whereas to DateTimeFormatter they mean fraction of second. Your SimpleDateFormat furthermore grabbed all six digits after the decimal point, ignoring the fact that you had typed only three S, so there were no zeroes left to match the '000' (by the way, the apostrophes are not necessary, only letters need them).
Link
Oracle Tutorial
I've figured out myself. Just FYI, Apache commons' FastDateFormat seems accepting the SSS000 format and parses the time correctly.
Is there a way to format a UTC time into any arbitrary string format I want in java? Basically I was thinking of having some class take the timestamp and I pass it is string telling it how I want it formated, and it returns the formatted string for me. Is there a way to do this?
The java.text.SimpleDateFormat class provides formatting and parsing for dates in a locale-sensitive manner.
The javadoc header for SimpleDateFormat is a good source of detailed information. There is also a Java Tutorial with example usages.
The DateFormat class or SimpleDateFormat should get you there. For example, http://www.epochconverter.com/ lists the following example to convert a epoch time to human readable timestamp with Java:
String date = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new java.util.Date (epoch*1000));
Date instances are insufficient for some purposes.
Use Joda Time instead.
Joda time integrates with Hibernate and other databases.
One gotcha to be aware of is that SimpleDateFormat is NOT thread-safe. Do not put it in a static field and use it from multiple threads concurrently.