SimpleDateFormat - how to prevent timezone being reformatted - java

I am having issues with SimpleDateFormat changing the appearance of a datetimestamp when I parse a String and then format the resulting Date.
The code snippet below demonstrates the issue. Note: I know it seems futile to parse and then format the same date with the same SimpleDateFormat, but this is a contrived example just to demonstrate the principle:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
try {
Date date = dateFormat.parse(dateStringToConvert);
String convertedDateString = dateFormat.format(date);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
} catch (ParseException e) {
e.printStackTrace();
}
The output of this is as follows:
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000Z
As this date is to be used in an automated test to fill in a form, it is important that the format of the datetimestamp remains exactly the same after being parsed and formatted by the SimpleDateFormat, so I don't want it to remove the -00:00 and add a Z.
It seems like a very simple problem, but I can't find any obvious answers.

I'm afraid SimpleDateFormat can't help you. This class is poorly designed and very limited, not to mention all the problems it has: https://eyalsch.wordpress.com/2009/05/29/sdf/
If you have Java 8, just use the java.time API. Not sure why you are converting a String to a Date just to convert it back to another String, but if you want the final result as a String with -00:00 as offset, then you can do:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
// offset, use "-00:00" when it's zero
.appendOffset("+HH:MM", "-00:00")
// create formatter, always work in UTC
.toFormatter().withZone(ZoneOffset.UTC);
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
Instant instant = fmt.parse(dateStringToConvert, Instant::from);
String result = fmt.format(instant);
System.out.println(result);
This will print:
2016-03-12T22:00:00.000-00:00

As Jon Skeet said in a comment, there is no way around hardcoding this special requirement.
DateTimeFormatter formatter;
String dateStringToConvert = "2016-03-12T22:00:00.000-00:00";
if (dateStringToConvert.endsWith("-00:00")) {
formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd'T'HH:mm:ss.SSS'-00:00'")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
} else {
formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
}
OffsetDateTime dateTime = OffsetDateTime.parse(dateStringToConvert, formatter);
String convertedDateString = dateTime.format(formatter);
System.out.println("Wanted : " + dateStringToConvert);
System.out.println("Actual : " + convertedDateString);
This prints
Wanted : 2016-03-12T22:00:00.000-00:00
Actual : 2016-03-12T22:00:00.000-00:00
As has also already been said, the offset of -00:00 (negative zero) isn’t equivalent to zero offset, so it really isn’t correct at all to parse the string into an OffsetDateTime as I do. A correct version of the code would parse into a LocalDateTime in this case and format the LocalDateTime back using the same formatter. It would overall be a bit longer, on the other hand you would no longer need the parseDefaulting call.
I am using and warmly recommending java.time, the modern Java date and time API. Because Date, DateFormat and SimpleDateFormat are long outmoded and have proven to be troublesome to work with in varying degrees. The modern API is so much nicer.
Link: Oracle tutorial: Date Time explaining how to use java.time

Try this:
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat df = new SimpleDateFormat(pattern) {
public StringBuffer format(Date date, StringBuffer prefix, FieldPosition fieldPosition) {
StringBuffer finalStr = super.format(date, prefix, fieldPosition);
finalStr = finalStr.insert(finalStr.length()-2, ':');
finalStr = finalStr.deleteCharAt(finalStr.length() - 6);
finalStr = finalStr.insert(finalStr.length() - 5, '-');
return finalStr;
};
};
System.out.println(df.format(yourDate));

Related

How to convert java.util.Date to soap suppported date format "yyyy-MM-dd'T'HH:mm:ss" with zone id

I am dealing with a situation where I want to convert java.util date into soap supported format with specific zone (Europe/Brussels)
I tried using Java 8 zone id feature but it seems it works well with instant dates only.
ZoneId zoneId = ZoneId.of("Europe/Brussels");
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(),
zoneId);
GregorianCalendar calendar = GregorianCalendar.from(zonedDateTime);
String xmlNow = convertToSoapDateFormat(calendar);
calendar.add(Calendar.MINUTE, 61);
String xmlLater = convertToSoapDateFormat(calendar);
//Method for soap conversion
private String convertToSoapDateFormat(GregorianCalendar cal) throws DatatypeConfigurationException {
XMLGregorianCalendar gDateFormatted2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(
cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND),
DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
return gDateFormatted2.toString();// + "Z";
}
I want lets say this date (2002-02-06) converted to this SOAP format 2002-02-06T08:00:00
You can use the SimpleDateFormat class with setTimezone method
public class Main {
public static void main(String[] args) {
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-MM-yyyy'T'HH:mm:ss");
sdfAmerica.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
String sDateInAmerica = sdfAmerica.format(new Date());
System.out.println(sDateInAmerica);
}
}
I'm not sure if this is the answer you are looking for, so tell me if I misunderstood your question. Then I'll delete the answer.
You can use the SimpleDateFormat class to achieve your goal. Create the format with by
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
And then format the date with the following call:
df.format(date);
java.time
I tried using Java 8 zone id feature but it seems it works well with
instant dates only.
Using java.time, the modern Java date and time API that came out with Java 8 and includes ZoneId, certainly is the recommended approach. And it works nicely. I cannot tell from your question what has hit you. If I understand correctly, DateTimeFormatter.ISO_OFFSET_DATE_TIME will give you the format you are after for your SOAP XML.
ZoneId zoneId = ZoneId.of("Europe/Brussels");
ZonedDateTime zdtNow = ZonedDateTime.now(zoneId);
String xmlNow = zdtNow.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
ZonedDateTime zdtLater = zdtNow.plusMinutes(61);
String xmlLater = zdtLater.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println("Now: " + xmlNow);
System.out.println("Later: " + xmlLater);
When I ran this code just now, the output was:
Now: 2019-10-21T13:56:37.771+02:00
Later: 2019-10-21T14:57:37.771+02:00

Parsing and formatting LocalDate with unnecessary time and timezone

Edit :
I opened a bug and it has been confirmed by Oracle. You can follow the resolution here : https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8216414
I'm interfacing with a LDAP repository which store the birthdate of a person with the time and timezone like this :
If the birthdate is "27-12-2018", then the LDAP string is "20181227000000+0000".
I cannot find a way to parse AND format the birthdate using the same pattern.
The following code works well for formatting but not for parsing :
LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMdd'000000+0000'";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Outputs correctly 20181227000000+0000
date.format(birthdateFormat);
// Throw a DatetimeParseException at index 0
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
And the following code works well for parsing but not for formatting
LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMddkkmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Throws a UnsupportedTemporalTypeException for ClockHourOfDay not supported
// Anyway I would have an unwanted string with non zero hour, minute, second, timezone
date.format(birthdateFormat);
// Parse correctly the date to 27-12-2018
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
Which pattern could satisfy both parsing and formating ?
Am I forced to use 2 different patterns ?
I am asking because the pattern is configured in a property file. I want to configure 1 pattern only in this property file. I would like to externalize the pattern because the LDAP is not part of my project, it is a shared resource and I have no guarantee that the format cannot change.
Since your LDAP string has zoned format ...+0000, I would suggest using ZonedDateTime or OffsetDateTime.
This pattern yyyyMMddHHmmssZZZ would do the trick for both parsing and formatting.
LocalDate date = LocalDate.of(2018, 12, 27);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssZZZ");
Formatting
First convert your LocalDate to ZonedDateTime/OffsetDateTime:
ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneOffset.UTC);
// or
OffsetDateTime offsetDateTime = date.atStartOfDay().atOffset(ZoneOffset.UTC);
Then format it:
// Both output correctly 20181227000000+0000
System.out.println(zonedDateTime.format(formatter));
// or
System.out.println(offsetDateTime.format(formatter));
Parsing
First parse the ZonedDateTime/OffsetDateTime:
// Both parse correctly
ZonedDateTime zonedDateTime = ZonedDateTime.parse("20181227000000+0000", formatter);
// or
OffsetDateTime offsetDateTime = OffsetDateTime.parse("20181227000000+0000", formatter);
Once you have ZonedDateTime/OffsetDateTime, you can simply retrieve the LocalDate like this:
LocalDate date = LocalDate.from(zonedDateTime);
// or
LocalDate date = LocalDate.from(offsetDateTime);
Update
Both parsing and formatting can be simplified to one-liners:
LocalDate date = LocalDate.from(formatter.parse(ldapString));
String ldapString = OffsetDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC).format(formatter);
In case you're still unsatisfied with the code above then you can extract the logic to utility methods:
public LocalDate parseLocalDate(String ldapString) {
return LocalDate.from(formatter.parse(ldapString));
}
public String formatLocalDate(LocalDate date) {
return OffsetDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC)
.format(formatter);
}
I suggest:
LocalDate date = LocalDate.of(2018, Month.DECEMBER, 27);
String pattern = "yyyyMMddHHmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Outputs 20181227000000+0000
String formatted = date.atStartOfDay(ZoneOffset.UTC).format(birthdateFormat);
System.out.println(formatted);
// Parses to 2018-12-27T00:00Z
OffsetDateTime odt = OffsetDateTime.parse("20181227000000+0000", birthdateFormat);
System.out.println(odt);
// Validate
if (! odt.toLocalTime().equals(LocalTime.MIN)) {
System.out.println("Unexpected time of day: " + odt);
}
if (! odt.getOffset().equals(ZoneOffset.UTC)) {
System.out.println("Unexpected time zone offset: " + odt);
}
// Converts to 2018-12-27
date = odt.toLocalDate();
System.out.println(date);
The LDAP string represents both date, time and UTC offset. The good solution is to respect that and generate all of those when formatting (setting time of day to 00:00 and offset to 0) and parsing all of them back (at best also validating them to catch if any surprises should arise). Conversion between LocalDate and OffsetDateTime is straightforward when you know how.
Edit 3: Allowing the pattern to be configured
… the pattern is configured in a property file… I want to configure 1
pattern only in this property file.
… I have no guarantee that the format cannot change.
To take the possibility into account that the pattern may some day not contain time of day and/or no UTC offset use this formatter in the above code:
DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.toFormatter()
.withZone(ZoneOffset.UTC);
This defines a default time of day (midnight) and a default offset (0). As long as time and offset are defined in the string from LDAP, the defaults are not used.
If you think it is getting too complicated, using two configured formats, one for formatting and one for parsing, may be the best solution (the least annoying solution) for you.
Edit: Avoiding type conversions
I consider the above the nice solution. However, if you insist an avoiding the conversion from LocalDate to ZonedDateTime using atStartOfDay and from OffsetDateTime using toLocalDate, that is possible through the following hack:
DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 4, SignStyle.NEVER)
.appendValue(ChronoField.MONTH_OF_YEAR, 2, 2, SignStyle.NEVER)
.appendValue(ChronoField.DAY_OF_MONTH, 2, 2, SignStyle.NEVER)
.appendLiteral("000000+0000")
.toFormatter();
// Outputs 20181227000000+0000
String formatted = date.format(birthdateFormat);
System.out.println(formatted);
// Parses into 2018-12-27
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
System.out.println(date);
I am specifying the exact width of each field so that the formatter can know where to separate them in the string when parsing.
Edit 2: Is this a bug in parsing?
I would immediately have expected yyyyMMdd'000000+0000' to work for both formatting and parsing. You may try filing a bug with Oracle and seeing what they say, though I wouldn’t bee too optimistic.
Stupid simple solution:
String s1 = "20181227000000+0000";
DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate date = LocalDate.parse(s1.substring(0, 8), yyyyMMdd);
System.out.println("date = " + date);
String s2 = date.format(yyyyMMdd) + "000000+0000";
System.out.println("s2 = " + s2);
System.out.println(s1.equals(s2));

Convert java.util.Date to String

I want to convert a java.util.Date object to a String in Java.
The format is 2010-05-30 22:15:52
Convert a Date to a String using DateFormat#format method:
String pattern = "MM/dd/yyyy HH:mm:ss";
// Create an instance of SimpleDateFormat used for formatting
// the string representation of date according to the chosen pattern
DateFormat df = new SimpleDateFormat(pattern);
// Get the today date using Calendar object.
Date today = Calendar.getInstance().getTime();
// Using DateFormat format method we can create a string
// representation of a date with the defined format.
String todayAsString = df.format(today);
// Print the result!
System.out.println("Today is: " + todayAsString);
From http://www.kodejava.org/examples/86.html
Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = formatter.format(date);
Commons-lang DateFormatUtils is full of goodies (if you have commons-lang in your classpath)
//Formats a date/time into a specific pattern
DateFormatUtils.format(yourDate, "yyyy-MM-dd HH:mm:SS");
tl;dr
myUtilDate.toInstant() // Convert `java.util.Date` to `Instant`.
.atOffset( ZoneOffset.UTC ) // Transform `Instant` to `OffsetDateTime`.
.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME ) // Generate a String.
.replace( "T" , " " ) // Put a SPACE in the middle.
2014-11-14 14:05:09
java.time
The modern way is with the java.time classes that now supplant the troublesome old legacy date-time classes.
First convert your java.util.Date to an Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Conversions to/from java.time are performed by new methods added to the old classes.
Instant instant = myUtilDate.toInstant();
Both your java.util.Date and java.time.Instant are in UTC. If you want to see the date and time as UTC, so be it. Call toString to generate a String in standard ISO 8601 format.
String output = instant.toString();
2014-11-14T14:05:09Z
For other formats, you need to transform your Instant into the more flexible OffsetDateTime.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );
odt.toString(): 2020-05-01T21:25:35.957Z
See that code run live at IdeOne.com.
To get a String in your desired format, specify a DateTimeFormatter. You could specify a custom format. But I would use one of the predefined formatters (ISO_LOCAL_DATE_TIME), and replace the T in its output with a SPACE.
String output = odt.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME )
.replace( "T" , " " );
2014-11-14 14:05:09
By the way I do not recommend this kind of format where you purposely lose the offset-from-UTC or time zone information. Creates ambiguity as to the meaning of that string’s date-time value.
Also beware of data loss, as any fractional second is being ignored (effectively truncated) in your String’s representation of the date-time value.
To see that same moment through the lens of some particular region’s wall-clock time, apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
zdt.toString(): 2014-11-14T14:05:09-05:00[America/Montreal]
To generate a formatted String, do the same as above but replace odt with zdt.
String output = zdt.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME )
.replace( "T" , " " );
2014-11-14 14:05:09
If executing this code a very large number of times, you may want to be a bit more efficient and avoid the call to String::replace. Dropping that call also makes your code shorter. If so desired, specify your own formatting pattern in your own DateTimeFormatter object. Cache this instance as a constant or member for reuse.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss" ); // Data-loss: Dropping any fractional second.
Apply that formatter by passing the instance.
String output = zdt.format( f );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.
Altenative one-liners in plain-old java:
String.format("The date: %tY-%tm-%td", date, date, date);
String.format("The date: %1$tY-%1$tm-%1$td", date);
String.format("Time with tz: %tY-%<tm-%<td %<tH:%<tM:%<tS.%<tL%<tz", date);
String.format("The date and time in ISO format: %tF %<tT", date);
This uses Formatter and relative indexing instead of SimpleDateFormat which is not thread-safe, btw.
Slightly more repetitive but needs just one statement.
This may be handy in some cases.
Why don't you use Joda (org.joda.time.DateTime)?
It's basically a one-liner.
Date currentDate = GregorianCalendar.getInstance().getTime();
String output = new DateTime( currentDate ).toString("yyyy-MM-dd HH:mm:ss");
// output: 2014-11-14 14:05:09
It looks like you are looking for SimpleDateFormat.
Format: yyyy-MM-dd kk:mm:ss
In single shot ;)
To get the Date
String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
To get the Time
String time = new SimpleDateFormat("hh:mm", Locale.getDefault()).format(new Date());
To get the date and time
String dateTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefaut()).format(new Date());
Happy coding :)
public static String formateDate(String dateString) {
Date date;
String formattedDate = "";
try {
date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",Locale.getDefault()).parse(dateString);
formattedDate = new SimpleDateFormat("dd/MM/yyyy",Locale.getDefault()).format(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return formattedDate;
}
If you only need the time from the date, you can just use the feature of String.
Date test = new Date();
String dayString = test.toString();
String timeString = dayString.substring( 11 , 19 );
This will automatically cut the time part of the String and save it inside the timeString.
Here are examples of using new Java 8 Time API to format legacy java.util.Date:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS Z")
.withZone(ZoneOffset.UTC);
String utcFormatted = formatter.format(date.toInstant());
ZonedDateTime utcDatetime = date.toInstant().atZone(ZoneOffset.UTC);
String utcFormatted2 = utcDatetime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS Z"));
// gives the same as above
ZonedDateTime localDatetime = date.toInstant().atZone(ZoneId.systemDefault());
String localFormatted = localDatetime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
// 2011-12-03T10:15:30+01:00[Europe/Paris]
String nowFormatted = LocalDateTime.now().toString(); // 2007-12-03T10:15:30.123
It is nice about DateTimeFormatter that it can be efficiently cached as it is thread-safe (unlike SimpleDateFormat).
List of predefined fomatters and pattern notation reference.
Credits:
How to parse/format dates with LocalDateTime? (Java 8)
Java8 java.util.Date conversion to java.time.ZonedDateTime
Format Instant to String
What's the difference between java 8 ZonedDateTime and OffsetDateTime?
The easiest way to use it is as following:
currentISODate = new Date().parse("yyyy-MM-dd'T'HH:mm:ss", "2013-04-14T16:11:48.000");
where "yyyy-MM-dd'T'HH:mm:ss" is the format of the reading date
output: Sun Apr 14 16:11:48 EEST 2013
Notes: HH vs hh
- HH refers to 24h time format
- hh refers to 12h time format
public static void main(String[] args)
{
Date d = new Date();
SimpleDateFormat form = new SimpleDateFormat("dd-mm-yyyy hh:mm:ss");
System.out.println(form.format(d));
String str = form.format(d); // or if you want to save it in String str
System.out.println(str); // and print after that
}
Let's try this
public static void main(String args[]) {
Calendar cal = GregorianCalendar.getInstance();
Date today = cal.getTime();
DateFormat df7 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
String str7 = df7.format(today);
System.out.println("String in yyyy-MM-dd format is: " + str7);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Or a utility function
public String convertDateToString(Date date, String format) {
String dateStr = null;
DateFormat df = new SimpleDateFormat(format);
try {
dateStr = df.format(date);
} catch (Exception ex) {
ex.printStackTrace();
}
return dateStr;
}
From Convert Date to String in Java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = "2010-05-30 22:15:52";
java.util.Date formatedDate = sdf.parse(date); // returns a String when it is parsed
System.out.println(sdf.format(formatedDate)); // the use of format function returns a String
Date date = new Date();
String strDate = String.format("%tY-%<tm-%<td %<tH:%<tM:%<tS", date);
One Line option
This option gets a easy one-line to write the actual date.
Please, note that this is using Calendar.class and SimpleDateFormat, and then it's not
logical to use it under Java8.
yourstringdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());

Date conversion in Java

How can I take a string in a format such as: 2008-06-02 00:00:00.0 and convert it to: 02-Jun-2008?
Can I somehow take the original string, convert it to a Date object, then use a formatter to get the final output (rather than parsing the string myself)? Thanks!
You can use SimpleDateFormat to convert between a String and a Date object and vice versa based on a pattern. Click the API link, you'll see patterns being explained in detail. A 4-digit year can be represented with yyyy, a 3-character month abbreviation can be represented with MMM and so on.
First you need to parse the String of the first format into a Date object:
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date = sdf1.parse(inputString);
Then you need to format the Date into a String of the second format:
SimpleDateFormat sdf2 = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
String outputString = sdf2.format(date);
Note that you need to take the Locale into account as well to get the month to be printed in English, else it will use the platform's default locale to translate the month.
Use 2 instances of SimpleDateFormat class. One for converting your input string to date and second to convert date back to string but in another format.
Here is an example of using SimpleDateFormat.
DateFormat startFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
DateFormat endFormat = new SimpleDateFormat("dd-MM-yyyy");
String outputString = null;
try {
Date date = startFormat.parse(inputString);
outputString = endFormat.format(date);
} catch(ParseException pe) {
throw new IllegalArgumentException(inputString + " is not properly formated.", pe);
}
You can definitely use SimpleDateFormat class like others have recommended.
Another suggestion if it applies in your case. If you are getting this data from a sql query you can also use to_char() method to format it in the query itself. For example: to_char(column_name,'DD-MON-YYYY')

java date format incompatible with xquery xs:date format, how to fix?

In java, when using SimpleDateFormat with the pattern:
yyyy-MM-dd'T'HH:mm:ss.SSSZ
the date is outputted as:
"2002-02-01T18:18:42.703-0700"
In xquery, when using the xs:dateTime function, it gives the error:
"Invalid lexical value [err:FORG0001]"
with the above date. In order for xquery to parse properly, the date needs to look like:
"2002-02-01T18:18:42.703-07:00" - node the ':' 3rd position from end of string
which is based on the ISO 8601, whereas Java date is based on the RFC 822 standard.
I would like to be able to easily specify the timezone in Java so that it will output the way that xquery wants.
Thanks!
OK, the linked to forum post DID help, thank you. I did however find a simpler solution, which I include below:
1) Use Apache commons.lang java library
2) Use the following java code:
//NOTE: ZZ on end is not compatible with jdk, but allows for formatting
//dates like so (note the : 3rd from last spot, which is iso8601 standard):
//date=2008-10-03T10:29:40.046-04:00
private static final String DATE_FORMAT_8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
DateFormatUtils.format(new Date(), DATE_FORMAT_8601)
Great find regarding commons.lang.java! You can even save yourself from creating your own format string by doing the following:
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(new Date());
Well, I did run into a problem - it doesn't appear to me (and I could be wrong) that there was any way to convert from and ISO string that DateUtils (from apache commons lang) creates, back to a date!
ie. apache commons will format it the way I would like, but not convert it back to a date again
So, I switched to JodaTime, and its much easier since its based on ISO8601 - here is the code:
public static void main(String[] args) {
Date date = new Date();
DateTime dateTime = new DateTime(date);
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String dateString = fmt.print(dateTime);
System.out.println("dateString=" + dateString);
DateTime dt = fmt.parseDateTime(dateString);
System.out.println("converted date=" + dt.toDate());
}
Try this:
static public String formatISO8601(Calendar cal) {
MessageFormat format = new MessageFormat("{0,time}{1,number,+00;-00}:{2,number,00}");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
df.setTimeZone(cal.getTimeZone());
format.setFormat(0, df);
long zoneOff = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET) / 60000L;
int zoneHrs = (int) (zoneOff / 60L);
int zoneMins = (int) (zoneOff % 60L);
if (zoneMins < 0)
zoneMins = -zoneMins;
return (format.format(new Object[] { cal.getTime(), new Integer(zoneHrs), new Integer(zoneMins) }));
}

Categories