问题
I am fetching datetime from oracle db and parsing in java-11 using ZonedDateTime as below:
oracle -->
1/19/2020 06:09:46.038631 PM
java ZonedDateTime 0/p -->
2020-01-19T18:09:46.038631Z[UTC]
oracle -->
1/19/2011 4:00:00.000000 AM
java ZonedDateTime o/p -->
2011-01-19T04:00Z[UTC]
(So, here the 0s are truncated by default. However, my requirement is to have consistent fixed length o/p like #1.)
expected java ZonedDateTime o/p --> 2011-01-19T04:00:00.000000Z[UTC]
However, I didnt find any date api methods to achieve above expected o/p. Instead of manipulating string, is there any way to preserve the trailing 0s with fixed length. We have consistent ZonedDateTime type in application, so we do not prefer to change that.
回答1:
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
Food for thought:
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.]
来源:https://stackoverflow.com/questions/63931623/databse-datetime-milli-nano-seconds-are-truncated-by-default-if-its-0s-while-u