Reputation: 5384
Am using Java 1.7.
Trying to convert:
2018-05-23T23:18:31.000Z
into
2018-05-23 23:18:31
DateUtils class:
public class DateUtils {
public static String convertToNewFormat(String dateStr) throws ParseException {
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
sdf.setTimeZone(utc);
Date convertedDate = sdf.parse(dateStr);
return convertedDate.toString();
}
}
When trying to use it:
String convertedDate = DateUtils.convertToNewFormat("2018-05-23T23:18:31.000Z");
System.out.println(convertedDate);
Get the following exception:
Exception in thread "main" java.text.ParseException: Unparseable date: "2018-05-23T23:22:16.000Z"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.myapp.utils.DateUtils.convertToNewFormat(DateUtils.java:7)
What am I possibly doing wrong?
Is there an easier way to do is (e.g. Apache Commons lib)?
Upvotes: 8
Views: 57358
Reputation: 79550
The java.util
Date-Time API and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API.
Also, quoted below is a notice from the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time
, the modern Date-Time API:
ZonedDateTime.parse("2018-05-23T23:18:31.000Z")
.format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH));
Note that you do not need a custom DateTimeFormatter
to parse the date-time string, 2018-05-23T23:18:31.000Z as it is already in the default pattern used by ZonedDateTime
. The modern date-time API is based on ISO 8601.
Learn more about the modern Date-Time API from Trail: Date Time.
Some helpful answers using java.time
API:
'Z'
is not the same as Z
.DateTimeFormatter
.For the sake of completeness, given below is a solution using the legacy date-time API:
DateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date dateTime = parser.parse("2018-05-23T23:18:31.000Z");
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
formatter.setTimeZone(parser.getTimeZone());
String formattedDateTimeString = formatter.format(dateTime);
System.out.println(formattedDateTimeString);
Upvotes: 1
Reputation: 2957
You can try this below the idea. I am not an expert in JAVA but I did it in javascript/node.js
import * as momentTimeZone from 'moment-timezone';
let d = new Data(); // d = '2018-05-23T23:18:31.000Z'; or we can take this date
let finalOutput = momentTimeZone(d).tz(this.locationService.locationTimeZone).utc().format('YYYY-MM-DD HH:mm:ss');
console.log('Result: ', finalOutput); // Result: "2018-05-23 23:18:31";
It also works with moment.js
.
Here is more about format.
Upvotes: 0
Reputation: 340060
Instant.parse( "2018-05-23T23:18:31.000Z" ) // Parse this String in standard ISO 8601 format as a `Instant`, a point on the timeline in UTC. The `Z` means UTC.
.atOffset( ZoneOffset.UTC ) // Change from `Instant` to the more flexible `OffsetDateTime`.
.format( // Generate a String representing the value of this `OffsetDateTime` object.
DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss" ) // Specify a formatting pattern as desired.
) // Returns a `String` object.
2018-05-23 23:18:31
Your input string is in standard ISO 8601 format.
The java.time classes use these standard formats by default when parsing/generating strings.
The T
separates the year-month-day portion from the hour-minute-second. The Z
is pronounced Zulu
and means UTC.
You are using troublesome old date-time classes that were supplanted years ago by the java.time classes. The Apache DateUtils
is also no longer needed, as you will find its functionality in java.time as well.
Parse that input string as a Instant
object. 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).
String input = "2018-05-23T23:18:31.000Z" ;
Instant instant = Instant.parse( input ) ;
To generate a string in another format, we need a more flexible object. The Instant
class is meant to be a basic building block. Lets convert it to a
OffsetDateTime`, using UTC itself as the specified offset-from-UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Define a formatting pattern to match your desired output.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss" ) ;
String output = odt.format( f ) ;
Tip: Consider using DateTimeFormatter::ofLocalized…
methods to automatically localize the String generation per some Locale
rather than hard-coding a formatting pattern.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Upvotes: 13
Reputation: 2769
In Kotlin and using ThreeTenABP,
fun getIsoString(year: Int, month: Int, day: Int): String {
val localTime = ZonedDateTime.of(year, month, day, 0, 0, 0, 0, ZoneId.of("Z"))
val utcTime = localTime.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC)
val isoString = utcTime.toInstant().toString() // 1940-15-12T00:00:00Z
val formattedIsoString = val formattedIsoString =
Instant.parse(isoString)
.atOffset(ZoneOffset.UTC)
.format(DateTimeFormatter
.ofPattern("uuuu-MM-dd'T'HH:mm:ss")) // 'T' in quotes so that it is retained.
return formattedIsoString
}
// print it
print(getIsoString(1940, 15, 12)) // 1940-15-12T00:00:00
Upvotes: 0
Reputation: 2476
For others without Java 1.7 Restrictions:
Since Java 1.8 you can do it using LocalDateTime
and ZonedDateTime
from the package java.time
public static void main(String[] args) {
String sourceDateTime = "2018-05-23T23:18:31.000Z";
DateTimeFormatter sourceFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateTimeFormatter targetFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(sourceDateTime, sourceFormat);
String formatedDateTime = dateTime.atZone(ZoneId.of("UTC")).format(targetFormat);
System.out.println(formatedDateTime);
}
EDIT: (see Comments)
Quote from the Oracle Java documentation of LocalDateTime:
LocalDateTime is an immutable date-time object that represents a date-time, often viewed as year-month-day-hour-minute-second. Other date and time fields, such as day-of-year, day-of-week and week-of-year, can also be accessed. Time is represented to nanosecond precision. For example, the value "2nd October 2007 at 13:45.30.123456789" can be stored in a LocalDateTime.
This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
the OP is asking to JUST parsing an Input String to a date-time (as year-month-day-hour-minute-second) and the Documentation says
LocalDateTime ... represents a date-time, often viewed as year-month-day-hour-minute-second
so no important information are lost here. And the part dateTime.atZone(ZoneId.of("UTC"))
returns a ZonedDateTime
so the ZimeZone is handled at this point again if the user needs to work with the timezone ...etc.
so don't try to force users to use the "One and Only" solution you present in your answer.
Upvotes: 5
Reputation: 944
Try this. You have to use one pattern for parsing and another for formatting.
public static String convertToNewFormat(String dateStr) throws ParseException {
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat sourceFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
SimpleDateFormat destFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sourceFormat.setTimeZone(utc);
Date convertedDate = sourceFormat.parse(dateStr);
return destFormat.format(convertedDate);
}
Upvotes: 9
Reputation: 18235
YYYY
does not match with year part. In java 7 you need yyyy
.
For T
, use 'T'
to match it
You're also missing the faction of millsecond part: .SSS
Try this:
String dateStr="2018-05-23T23:18:31.000Z";
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss.SSS'Z'");
sdf.setTimeZone(utc);
Date convertedDate = sdf.parse(dateStr);
convertedDate.toString();
Upvotes: 0