How to modify decimal fractions from UTC Date Time to Date [duplicate] - java

This question already has answers here:
Illegal pattern character 'T' when parsing a date string to java.util.Date
(4 answers)
Date object SimpleDateFormat not parsing timestamp string correctly in Java (Android) environment
(7 answers)
Closed 2 years ago.
I'm trying to convert a utc date time in local date time, but I have some problem the the decimal fraction.
I call a web service the return a series of data. One of these data is the utc date time in this format
I must the use this library org.threeten.bp, I can't use a different library.
2020-06-22T18:28:57.957535800Z
To converte utcFormat to Date,I have found this piece of code that it works fine
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = utcFormat.parse("2012-08-15T22:56:02.038Z");
DateFormat pstFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
pstFormat.setTimeZone(TimeZone.getTimeZone("ECT"));
System.out.println(pstFormat.format(date));
but it doesen't work well from my code, because return this date
2020-07-03T22:27:52.800
How you can see it's different. I did some test and if I leave only 3 decimal after dot, that part of code it will work fine. Have a look the example:
2020-06-22T18:28:57.800Z
return the right date time from ECT zone
2020-06-22T20:28:57.800
I am looking for a way to receive the utc dateTime with only three decimals or to change the utc dateTime by removing the excess decimals. With this last case I am not if it can be a good idea.

Your input format is standard so you can simply parse it to an Instant for example:
String input = "2020-06-22T18:28:57.957535800Z";
Instant date = Instant.parse(input);
If you want to get rid of the last 3 decimals (i.e. only keep the result to a microsecond precision), you can truncate the result:
Instant truncated = date.truncatedTo(ChronoUnit.MICROS);
Also note that the classes you use in your example (DateFormat, Date etc) are not part of threeten.

Here's an approach similar to yours but using classes from org.threeten.bp only instead of mixing it with java.util:
public static void main(String[] args) throws ParseException {
String datetimeUtc = "2020-06-22T18:28:57.957535800Z";
// parse it to a ZonedDateTime, this is default formatting ==> no formatter needed
ZonedDateTime utcTime = ZonedDateTime.parse(datetimeUtc);
// print the result
System.out.println(utcTime);
// convert it to another zone
ZonedDateTime estTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Paris"));
// print that, too
System.out.println(estTime);
// define a non-default output format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
// and print the estTime using that format
System.out.println(estTime.format(dtf));
}
This outputs the following:
2020-06-22T18:28:57.957535800Z
2020-06-22T20:28:57.957535800+02:00[Europe/Paris]
2020-06-22T20:28:57.957

Related

Parse time format yyyy-MM-dd'T'HH:mm:ss.SSS'+' [duplicate]

This question already has answers here:
Why can't OffsetDateTime parse '2016-08-24T18:38:05.507+0000' in Java 8
(5 answers)
Closed 3 months ago.
I am working with jira api and in one of request I get the response with date field in format like this: 2022-10-26T09:34:00.000+0000. I need to convert this to LocalDate but I do not know how to to this with this strange format.
Here are some of formats I already tried:
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
DateTimeFormatter.ISO_LOCAL_DATE_TIME
but both cannot deserialize this + sign at the end of the date.
Text '2022-10-27T09:34:00.000+0000' could not be parsed, unparsed text found at index 24
You have to add the timezone:
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
Checkout the documentation
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
The error message is telling you that your DateTimeFormatter is not able to parse the zone offset of +0000 at the end of your String. That's because a DateTimeFormatter.ISO_LOCAL_DATE_TIME just does not expect an offset, it is supposed to only parse
year
month of year
day of month
hour of day
minute of hour
second of minute
fraction of second (and nanos)
That's it! No offset! No zone!.
But that also means it could perfectly parse everything until this offset in your example!
However, the String is nearly formatted as an OffsetDateTime, but unfortunately its ISO formatter expects an offset where hours and minutes are separated by a colon, e.g. +00:00, and your String does not have one.
java.time grants you the possibility of building a custom formatter based on an exisiting one. That's why I mentioned above that everything apart from the offset could be parsed with a DateTimeFormatter.ISO_LOCAL_DATE_TIME. You can take that one and attach an offset-x pattern which then parses your unseparated offset. Let's call it extending an existing formatter, here's an example:
public static void main(String[] args) {
// your example String
String someTimes = "2022-10-26T09:34:00.000+0000";
// build a suitable formatter by extending an ISO-formatter
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("xxxx")
.toFormatter(Locale.ENGLISH);
// then parse
LocalDate localDate = LocalDate.parse(someTimes, dtf);
// and print
System.out.println(localDate);
}
Output:
2022-10-26
It is always a good idea to create a formatter with a Locale, but in most cases where exclusively numerical values are to be parsed, a formatter without a Locale might be sufficient. That counts for DateTimeFormatter.ofPattern(String, Locale) as well.

How do I convert any Timestamp string to a single Format in Java

I want to convert the timestamps which are in different formats to one format
I want to convert following timestamps to single format
Time Stamp 1 : 2022-08-17T18:28:07.288496+05:30
Time Stamp 2 : 2022-10-27T13:17:47.987736542Z
to
yyyy-MM-dd'T'HH:mm:ss format
I have tried using DateFormatter of Java but it gives ParseException. Also used SimpleDateFormatter but was getting same exceptions.
Please suggest package or methods for the same.
Edit : Code I used for conversion
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(timestamp, formatter);
System.out.println(localDateTime);
Using java.time here is a good idea compared to java.util.Date, Calendar and so on, but you have to use specific classes that match the information inside a String that represents a datetime or timestamp.
In your case, the String contains the following information:
year
month of year
day of month
hour of day
minute of hour
second of minute
fractions of second
offset from UTC
In particular, it's the last one (offset from UTC) which makes your attempt fail because you (1) don't consider it in the pattern of the DateTimeFormatter and (2) you use a class that cannot store it (LocalDateTime is not able / designed to hold information about a zone or an offset.
Having Strings with an offset can be stored in / parsed to OffsetDateTimes, if they are ISO formatted (as your examples are), you don't even need to apply a custom DateTimeFormatter. You can simply call OffsetDateTime.parse(String).
You can then define a desired format for an output by creating a custom DateTimeFormatter and apply it in OffsetDateTime.format(DateTimeFormatter).
Here's an example:
public static void main(String[] args) {
// example Strings (your ones)
String timestampOne = "2022-08-17T18:28:07.288496+05:30";
String timestampTwo = "2022-10-27T13:17:47.987736542Z";
// directly parse them to get instances of OffsetDateTime
OffsetDateTime odtOne = OffsetDateTime.parse(timestampOne);
OffsetDateTime odtTwo = OffsetDateTime.parse(timestampTwo);
// prepare a formatter for your desired output
DateTimeFormatter dtfOut = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss");
// and print the values of the OffsetDateTimes formatted by that DateTimeFormatter
System.out.println(odtOne.format(dtfOut));
System.out.println(odtTwo.format(dtfOut));
}
Output:
2022-08-17T18:28:07
2022-10-27T13:17:47

Convert java.util.Date with custom time zone to UTC [duplicate]

This question already has answers here:
How to set time zone of a java.util.Date?
(12 answers)
Closed 2 years ago.
I have a java.util.Date object. When I format it to String using:
String timeString = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss-Z").format(time);
I get:
2020-03-26-14:40:55-+0200
So, I somehow have the correct time zone (but I can have any time zone, not only +2), this is good.
I want to convert this date to UTC, and then convert it to String. If I send an object with a date to the client, then Jackson will automatically convert it to UTC. But I want to do this manually.
How can I do this?
It is not recommended anymore to use java.util for date-time operations, especially not for time-zone or offset conversions...
Instead, use java.time:
public static void main(String[] args) {
// the String (with a strange formatting) to be parsed
String datetime = "2020-03-26-14:40:55-+0200";
// parse it to an OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse(datetime,
// using a formatter for this specific pattern
DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss-x"));
// print the parsing result
System.out.println(odt);
// then convert it to UTC (keeping the moment & adjusting the offset)
OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC);
// print the conversion result
System.out.println(odtUtc);
}
gives you the following output
2020-03-26T14:40:55+02:00
2020-03-26T12:40:55Z
java.time
I understand that you have got a field of type java.util.Date that you cannot afford to change just now. For any operation on that Date you should still convert it to a modern Instant first and then do your further work from there. For converting it to a string in UTC you may use the very simple:
String timeString = yourJavaUtilDate.toInstant().toString();
System.out.println(timeString);
Example output:
2020-03-26T12:40:55Z
While an Instant is a point in time without time zone or offset, just like a Date is, Instant.toString() produces a string in UTC in ISO 8601 format, which I find quite nice. If you wanted the peculiar format mentioned in your question (you must have very special reasons for that):
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss-Z");
String timeString = yourJavaUtilDate.toInstant()
.atOffset(ZoneOffset.UTC)
.format(formatter);
2020-03-26-12:40:55-+0000
Your format pattern string from SimpleDateFormat works with the modern DateTimeFormatter too. That is not always the case, there are differences between the sets of format pattern letters for the two, only many of the letters have the same or similar meaning.
I am myself working with a very old code base that over the years has acquired a messy mixture of outdated and modern date and time classes. So we’re constantly converting back and forth between Date, LocalDate, OffsetDateTime, XMLGregorianCalendar and many other classes, which is far from ideal, and it will take some years still to get to the sweet spot where we will be using the modern classes only.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601

Converting string date to string in yyyy-MM-dd'T'HH:mm:ss.SSSSSS format in java 7

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...

SimpleDateFormat parse is changing time according to timezone [duplicate]

This question already has answers here:
java.sql.Timestamp: changing timezone of Timestamp
(2 answers)
Closed 6 years ago.
I get timestamps as a String in a stream and they are of the format "2016-12-08 05:44:48 <timezone like IST, UTC>" and "2016-12-08 05:44:48 <timezone like +0000>"
I want to convert the string to java.sql.Timestamp so I wrote a function as follows
private static Timestamp convertToTimestamp(String s) throws ParseException{
String dateFormat = new String("yyyy-MM-dd hh:mm:ss z");
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
Date d = sdf.parse(s);
return new Timestamp(d.getTime());
}
When I run
Timestamp t = convertToTimestamp("2016-12-08 05:44:48 UTC");
System.out.println(t);
The output is 2016-12-08 11:14:48.0
It is automatically converting into IST (Probably my JVM default).
How to make the change so that the output time not changed to IST and is same as input?
Java's java.util.Date and java.sql.Timestamp do not store timezone.
They always track time in UTC.
When parsing a date string that includes a timezone, the string is correctly parsed and adjusted from the given timezone to UTC.
When parsing a date string without timezone, the string is parsed in the JVM's default timezoneand converted to UTC, unless another timezone has been explicitly given to the date parser (commonly SimpleDateFormat).
When displaying (aka formatting) a Date/Timestamp, it will be shown in the JVM's default timezone, unless otherwise specified.
The Date/Timestamp objects cannot store a timezone, so they cannot remember what the original timezone was.
If you need that, use Java 8's ZonedDateTime.
You have to ignore the time-zone when parsing the date
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

Categories