Reputation: 63
I am fetching datetime from an Oracle database and parsing in Java 11 using ZonedDateTime as below:
Oracle --> 1/19/2020 06:09:46.038631 PM
Java ZonedDateTime output --> 2020-01-19T18:09:46.038631Z[UTC]
Oracle --> 1/19/2011 4:00:00.000000 AM
Java ZonedDateTime output --> 2011-01-19T04:00Z[UTC]
(So, here the 0s are truncated by default.
However, my requirement is to have consistent fixed length output like #1.)
Expected Java ZonedDateTime output --> 2011-01-19T04:00:00.000000Z[UTC]
However, I didn’t find any date API methods to achieve above expected output. Instead of manipulating a string, is there a way to preserve the trailing 0s with fixed length?
We have consistent ZonedDateTime types in the application, so we do not prefer to change that.
Upvotes: 2
Views: 1223
Reputation: 2821
Small thing to add to other answers: The fraction-of-second (S
) and nanos (n
) are similar but nanos will output more places/digits if more are available. The docs didn't seem to elaborate this well. If only up to 6 nano digits are available, then there shouldn't be a difference.
import java.time.*;
import java.util.*;
import java.time.format.*;
public class TestFormats {
public static void main(String[] args)
{
LocalDateTime dt = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS'Z'");
System.out.println("Current time: "
+ formatter.format(dt));
System.out.println("New LocalDateTime with 0 nano: "
+ formatter.format(dt.withNano(0)));
System.out.println("New LocalDateTime with specific nano: "
+ formatter.format(dt.withNano(80888)));
System.out.println("New LocalDateTime with specific bigger nano: "
+ formatter.format(dt.withNano(8088888)));
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.nnnnnn'Z'");
System.out.println("Format2 Current time: "
+ formatter2.format(dt));
System.out.println("Format2 New LocalDateTime with 0 nano: "
+ formatter2.format(dt.withNano(0)));
System.out.println("Format2 New LocalDateTime with specific nano: "
+ formatter2.format(dt.withNano(80888)));
System.out.println("Format2 New LocalDateTime with specific bigger nano: "
+ formatter2.format(dt.withNano(8088888)));
}
}
Result:
Current time: 2023-07-12 15:55:30.321719Z
New LocalDateTime with 0 nano: 2023-07-12 15:55:30.000000Z
New LocalDateTime with specific nano: 2023-07-12 15:55:30.000080Z
New LocalDateTime with specific bigger nano: 2023-07-12 15:55:30.008088Z
Format2 Current time: 2023-07-12T15:55:30.321719992Z
Format2 New LocalDateTime with 0 nano: 2023-07-12T15:55:30.000000Z
Format2 New LocalDateTime with specific nano: 2023-07-12T15:55:30.080888Z
Format2 New LocalDateTime with specific bigger nano: 2023-07-12T15:55:30.8088888Z
Upvotes: 0
Reputation: 79075
We have consistent ZonedDateTime type in application, so we do not prefer to change that.
Why do you think 2011-01-19T04:00Z[UTC]
is inconsistent? A date-time object is supposed to hold (and provide methods/functions to operate with) only the date, time, and time-zone information. It is not supposed to store any formatting information; otherwise, it will violate the Single-responsibility principle. The formatting should be handled by a formating class e.g. DateTimeFormatter (for modern date-time API), DateFormat
(for legacy java.util
date-time API) etc.
Every class is supposed to override the toString()
function; otherwise, Object#toString
will be returned when its object will be printed. A ZonedDateTime
has date, time and time-zone information. Given below is how its toString()
for time-part has been implemented:
@Override
public String toString() {
StringBuilder buf = new StringBuilder(18);
int hourValue = hour;
int minuteValue = minute;
int secondValue = second;
int nanoValue = nano;
buf.append(hourValue < 10 ? "0" : "").append(hourValue)
.append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
if (secondValue > 0 || nanoValue > 0) {
buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
if (nanoValue > 0) {
buf.append('.');
if (nanoValue % 1000_000 == 0) {
buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
} else if (nanoValue % 1000 == 0) {
buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
} else {
buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
}
}
}
return buf.toString();
}
As you can see, the second and nano parts are included in the returned string only when they are greater than 0
. It means that you need to use a formatting class if you want these (second and nano) zeros in the output string. Given below is an example:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String input = "1/19/2011 4:00:00.000000 AM";
// Formatter for input string
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("M/d/u H:m:s.n a")
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = LocalDateTime.parse(input, inputFormatter).atZone(ZoneOffset.UTC);
// Print `zdt` in default format i.e. the string returned by `zdt.toString()`
System.out.println(zdt);
// Formatter for input string
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.nnnnnnz");
String output = zdt.format(outputFormatter);
System.out.println(output);
}
}
Output:
2011-01-19T04:00Z
2011-01-19T04:00:00.000000Z
public class Main {
public static void main(String[] args) {
double d = 5.0000;
System.out.println(d);
}
}
What output do you expect from the code given above? Does 5.0
represent a value different from 5.0000
? How will you print 5.0000
? [Hint: Check String#format
, NumberFormat
, BigDecimal
etc.]
Upvotes: 2