Reputation: 22974
I want to convert the following patterns to yyyy-mm-ddThh:mm:ssz
.
2017-feb-02
2017-05-02
2017-01-01 03:00:00
2017-01-01 00:00:00.0
I have gone through the SimpleDateFormat
class of Java. But I haven’t been able to achieve it.
Upvotes: -1
Views: 6312
Reputation: 41
As Basil Bourque and Anonymous say, use java.time, the modern Java date and time API, for your date and time work. You mentioned SimpleDateFormat
. Avoid it. It was a notorious troublemaker of a class and was obsoleted by java.time in Java 8 in 2014.
In the simplest of run-once-and-throw-away programs it’s probably OK to convert a date and time in a string to a string in a different format. For all other purposes store your dates and times in proper date-time objects, for example a ZonedDateTime
object for a date and time in a known time zone. When accepting string input, parse into such an object. Only when giving string output, format the date and time into a string again.
For parsing your three or four different formats you may use the following. We may regard the last two of your example strings as having the same format, only without and with a decimal fraction on the seconds.
/** Formatter for parsing a string like "2017-feb-02" */
private static final DateTimeFormatter dateWithMonthAbbreviationParser
= new DateTimeFormatterBuilder()
.parseCaseInsensitive() // Allow "feb" in lower case.
.appendPattern("uuuu-MMM-dd")
// Before Java 19 use Locale.forLanguageTag("en-IN")
.toFormatter(Locale.of("en", "IN"));
/** Formatter for parsing a string like "2017-01-01 03:00:00" or "2017-01-01 00:00:00.0" */
private static final DateTimeFormatter dateTimeParser
= new DateTimeFormatterBuilder()
// Reuse existing formatters for date and time.
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter(Locale.ROOT);
private static ZonedDateTime parseDifferentFormats(String dateTimeString) {
if (dateTimeString.length() == 10) {
// ISO 8601 format; no explicit formatter needed.
return LocalDate.parse(dateTimeString)
.atStartOfDay(ZoneId.systemDefault());
}
if (dateTimeString.length() < 15) {
return LocalDate.parse(dateTimeString, dateWithMonthAbbreviationParser)
.atStartOfDay(ZoneId.systemDefault());
}
return LocalDateTime.parse(dateTimeString, dateTimeParser)
.atZone(ZoneId.systemDefault());
}
Try it out:
List<String> inputExamples = List.of(
"2017-feb-02", "2017-05-02",
"2017-01-01 03:00:00", "2017-01-01 00:00:00.0");
for (String input : inputExamples) {
ZonedDateTime zdt = parseDifferentFormats(input);
System.out.format(Locale.ENGLISH, "%-21s parsed to %s%n", input, zdt);
}
Output so far when running in Asia/Kolkata time zone:
2017-feb-02 parsed to 2017-02-02T00:00+05:30[Asia/Kolkata] 2017-05-02 parsed to 2017-05-02T00:00+05:30[Asia/Kolkata] 2017-01-01 03:00:00 parsed to 2017-01-01T03:00+05:30[Asia/Kolkata] 2017-01-01 00:00:00.0 parsed to 2017-01-01T00:00+05:30[Asia/Kolkata]
You want a result in format YYYY-MM-DDTHH:mm:ssZ
. This is ISO 8601 format with a trailing Z
implying date and time in UTC (so-called Zulu time). I suggest this formatter:
private static final DateTimeFormatter isoFormatter
= new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendPattern("HH:mm:ssX")
.toFormatter(Locale.ROOT);
We need to convert to UTC before formatting:
String formattedDateTime = zdt.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC)
.format(isoFormatter);
System.out.format(Locale.ENGLISH, "%s formatted to %s%n", zdt, formattedDateTime);
Example output:
2017-02-02T00:00+05:30[Asia/Kolkata] formatted to 2017-02-01T18:30:00Z
Upvotes: 1
Reputation: 340098
The legacy date-time classes are a terrible awful mess. Avoid them. Avoid Date
, Calendar
, SimpleDateFormat
, etc.
Instead, use only the modern java.time classes built into Java 8+.
Your second input complies with the ISO 8601 standard format for a date-only value: YYYY-MM-DD. The java.time classes use ISO 8601 formats by default when parsing/generating text. So no need for any formatting pattern.
LocalDate ld = LocalDate.parse ( "2017-05-02" ) ;
Your desired format of YYYY-MM-DDTHH:mm:ssZ
ends with a Z
. That letter is an abbreviation for an offset of zero hours-minutes-seconds from UTC, pronounced “Zulu”. Text in this format represents a date, with time-of-day, as seen with an offset-from-UTC of zero. Such a value represents a moment, a point on the timeline.
So we are in bit of a pickle. Your input is a date-only, but you want a date with time-of-day in an offset. To resolve this, we need to find the first moment of the day as seen in an offset of zero.
LocalDate ld = LocalDate.parse ( "2017-05-02" );
ZonedDateTime zdt = ld.atStartOfDay ( ZoneOffset.UTC );
zdt.toString() = 2017-05-02T00:00Z
Your third & fourth inputs have a date and a time but lack the offset. So parse as LocalDateTime
objects. Standard ISO 8601 format requires a T
in the middle, where you have a SPACE. So swap, then parse.
String input = "2017-01-01 03:00:00".replace ( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse ( input ) ;
Assign the desired offset of zero.
OffsetDateTime odt = ldt.atOffset ( ZoneOffset.UTC ) ;
odt.toString() = 2017-01-01T03:00Z
Upvotes: 1
Reputation: 1361
I would solve your problem like this, with the help mentioned in the comment section of your question:
public static void main(final String[] args) throws Exception {
String[] formatStrings = { "yyyy-MMM-dd", "yyyy-MM-dd", "yyyy-MMM-dd hh:mm:ss", "yyyy-MMM-dd hh:mm:ss.S" };
String yourDate = "2017-Mar-02";
Date date = null;
for (String formatString : formatStrings) {
try {
date = new SimpleDateFormat(formatString, Locale.US).parse(yourDate);
} catch (ParseException e) {
}
}
DateFormat formatTo = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssz", Locale.US);
System.out.println(formatTo.format(date));
}
Upvotes: 0
Reputation: 427
The pattern you want to convert it should be like: yyyy-MM-dd'T'HH:mm:ssz
. See more here.
You can do it with SimpleDateFormat
, a small example:
String date = "2017-05-02";
String oldFormat = "yyyy-MM-dd";
String newFormat = "yyyy-MM-dd'T'HH:mm:ssz";
SimpleDateFormat sdf = new SimpleDateFormat(oldFormat);
try {
Date newDate = sdf.parse(date);
sdf.applyPattern(newFormat);
System.out.println(sdf.format(newDate));
} catch (ParseException e) {
e.printStackTrace();
}
Upvotes: 0