Remove time zone part from - ZonedDateTime : JAVA - java

I am converting milliseconds into ZonedDateTime
Long lEpochMilliSeconds = 1668415926445;
System.out.println(ZonedDateTime.ofInstant(Instant.ofEpochMilli(lEpochMilliSeconds),ZoneId.of("UTC"));
It gives output:
2022-10-28T12:59:34.939Z[UTC]
I don't want the time zone "[UTC]" part in my output.
I need my out to be like this in ZonedDateTime format:
2022-10-28T12:59:34.939Z
I need the format in ZonedDateTime only not string, as I will be returning the value & use it somewhere else

I need the format in ZonedDateTime only not string
This is like saying "I need an int that knows it's in hex rather than decimal". There's just no such concept.
If you need to format the value in a particular way, you should apply that format where you do the formatting.
It's possible that what you should actually do is return an Instant instead of a ZonedDateTime. That will format the way you want by default, although it's still not "part of the object" - just the default format for all instants.
It's important to understand the difference between "the value being represented" (and the type you're using to represent that value) and "a string representation of that value". You should try use the semantically-appropriate type for what you're trying to represent (e.g. ZonedDateTime, Instant etc) for as much of the time as possible, only converting to and from string representations at system boundaries. Those system boundaries need to be aware of the expected textual representation, and perform the appropriate conversion, rather than expecting a particular string representation to travel with the value itself through the system.

It is giving me the desired output when I gave ZoneOffset as an argument instead of ZoneId.
ZonedDateTime.ofInstant(Instant.ofEpochMilli(lEpochMilliSeconds), ZoneOffset.UTC);

Related

what is the actual return type for LocalDate.now().toString()

I am trying to save LocalDateTime to DB. So my scenario is I have consumer and producer. Producer generated some code and gives it to consumer, and consumer saves the entries to database.
Code on Producer Side
LocalDate.now().toString() // returns 2021-07-13T12:25:38.841775700 sometimes it returns 2021-07-13T12:25:38.841 so basically after the last decimal point the precision can be anything.
Code on Consumer side
On the consumer side i want to save entries from received from producer into the db for that i need to convert the str to LocalDateDime.
private static DateTimeFormatter timeFormatterInMs= DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
public static LocalDateTime unmarshalDateTime(final String dateTimeStr) {
return dateTimeStr == null ? null : LocalDateTime.parse(str, timeFormatterInMs);
}
Here the problem is what is the format for return type of LocalDateTime
i know it return data in the format yyyy-MM-dd'T'HH:mm:ss.SSS by in our case ms have sometimes 9, sometimes 6 decimal places? if i will give this string to the function unmarshalDateTime(..) the function will break and it wont work properly. because it expects the ms part to be 3 decimal places. what to do about it
The direct answer to your question is in the documentation of LocalDateTime.toString() (link at the bottom):
Outputs this date-time as a String, such as 2007-12-03T10:15:30.
The output will be one of the following ISO-8601 formats:
uuuu-MM-dd'T'HH:mm
uuuu-MM-dd'T'HH:mm:ss
uuuu-MM-dd'T'HH:mm:ss.SSS
uuuu-MM-dd'T'HH:mm:ss.SSSSSS
uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
The format used will be the shortest that outputs the full value of
the time where the omitted parts are implied to be zero.
To parse such a string back into a LocalDateTime don’t use any formatter at all. The one-arg LocalDateTime.parse(CharSequence) parses every one of those formats.
Let me show you:
System.out.println(LocalDateTime.parse("2021-07-13T12:25:38.841775700"));
System.out.println(LocalDateTime.parse("2021-07-13T12:25:38.841"));
System.out.println(LocalDateTime.parse("2021-07-13T12:26"));
Output:
2021-07-13T12:25:38.841775700
2021-07-13T12:25:38.841
2021-07-13T12:26
This said Ali Behzadian Nejad is correct in his answer: assuming that those values are supposed to define points in time, LocalDateTime is the wrong type for them. Use Instant. If you can, use timestamp with time zone on the SQL side. Depending on your JDBC driver you may or may not need to convert via OffsetDateTime. If you need to store strings, Instant.toString() too can produce different formats and can parse each and every one of them back through the one-arg Instant.parse().
Documentation links
LocalDateTime.toString()
LocalDateTime.parse(CharSequence)
Storing local dates in database is not a good idea because they are not instants of time, they are just localized presentation of time.
Create an Instant object from LocalTime and its timezone and save that time Instant in database column with Timestamp type:
LocalDateTime localDateTime = ...
Instant instant = localDateTime.atZone(ZoneId.of("Europe/Paris")).toInstant();
From Java documentation:
This class [LocalDateTime] 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.
With jdk11: The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.
Also there have LocalDate.format to generate a time string by format.
BTW, if you want save time to database I suggest use long or Timestamp instead of String
You can use a DateTimeFormatter that considers different patterns in order to parse Strings with different amounts of fractions-of-second (here: 6 or 9):
public static void main(String[] args) throws Exception {
String datetime = "2021-07-13T12:25:38.841775700";
String datetimeShort = "2021-07-13T12:25:38.841775";
// provide a formatter that "knows" two different patterns
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
"[uuuu-MM-dd'T'HH:mm:ss.nnnnnnnnn][uuuu-MM-dd'T'HH:mm:ss.SSSSSS]");
// parse the one with 9 fractions-of-second
LocalDateTime ldt = LocalDateTime.parse(datetime, dtf);
// and the one with 6 using the same formatter
LocalDateTime ldtShort = LocalDateTime.parse(datetimeShort, dtf);
// output the parsed LocalDateTimes
System.out.println(ldt + " and " + ldtShort + " are successfully parsed");
}
This outputs
2021-07-13T12:25:38.841775700 and 2021-07-13T12:25:38.841775 are successfully parsed

Can I switch between formats for DateTimeFormatterBuilder?

I'm using DateTimeFormatterBuilder() to turn the JSON data I take in (the commented code) and convert them into one of two formats. To decide which format to use, I'm using a REGEX to find any instances of a square, [] , bracket (with anything inside " .*? " ). After choosing the correct format, I would parse the new value into another JSON object.
The problem is, my program either does not correctly choose which format to use (either a REGEX and method error), or doesn't format it correctly (formatting error), not sure which, and sends an error back (bottom of code), instead.
However, this is only for data that has square brackets. Data without square brackets gets processed correctly. I'm wondering if there are any solutions/suggestions to fix this?
// 2018-11-28T13:09:00.2-04:00
def utcDateFormatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
.appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
.appendPattern("xxx")
.toFormatter()
// 2018-11-28T13:09:00.528-08:00[America/New_York]
def utcDateFormatterWithZone = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
.appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
.appendPattern("xxx'['VV']'")
.toFormatter()
if (json.beginDateTime.find("\\[.*?\\]") == true) {
object.setDate(LocalDateTime.parse("${json.beginDateTime}", utcDateFormatterWithZone).format(outFormatter))
} else {
object.setDate(LocalDateTime.parse("${json.beginDateTime}", utcDateFormatter).format(outFormatter))
}
Error: Text '2019-09-26T15:01:07.941-05:00[America/New_York]' could not be parsed, unparsed text found at index 29
This is built-in: DateTimeFormatter.ISO_ZONED_DATE_TIME
This can be done a lot more easily. The built-in DateTimeFormatter.ISO_ZONED_DATE_TIME matches both of your formats.
String stringWithoutZoneId = "2018-11-28T13:09:00.2-04:00";
String stringWithZoneId = "2018-11-28T13:09:00.528-08:00[America/New_York]";
LocalDateTime parsedWithoutZoneId = LocalDateTime.parse(
stringWithoutZoneId, DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println(parsedWithoutZoneId);
LocalDateTime parsedWithZoneId = LocalDateTime.parse(
stringWithZoneId, DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println(parsedWithZoneId);
Output from this snippet is:
2018-11-28T13:09:00.200
2018-11-28T13:09:00.528
Use the offset too
A word of warning, though: Are you sure you want to ignore the offsets in the strings? With those offsets the strings represent unambiguous points in time. What you get from parsing into LocalDateTime are datetimes belonging at different unknown offsets. I can’t see how you can reliably use them for anything useful.
Consider parsing into ZonedDateTime. The one-arg ZonedDateTIme.parse will even do this without any explicit formatter. Then either store these ZonedDateTime directly in your objects or convert to Instant and store those. An Instant represents a point in time. If you cannot change the type stored, you will probably want to convert your ZonedDateTime to UTC (or another agreed-upon time zone), then convert to LocalDateTime. All of this said without knowing your real requirements, so I could be wrong, only I think not.
What went wrong in your code?
#daggett is correct: CharSequence.find returns a string, so for you if statement to work you would have needed:
if (json.beginDateTime.find("\\[.*?\\]") != null) {
A String can never be equal to true, so the formatter without zone was always chosen.
Link
Documentation of DateTimeFormatter.ISO_ZONED_DATE_TIME

java.time.format.DateTimeParseException: could not be parsed at index 0

I am trying to convert a String to timestamp.
my string contains time and time zone ('05:03:05.875+02:00') but I get the following error:
error
java.time.format.DateTimeParseException: Text '05:03:05.875+02:00'
could not be parsed at index 0
Code
String timewithZone= "05:03:05.875+02:00";
DateTimeFormatter formatter=DateTimeFormatter.ISO_OFFSET_DATE_TIME;
final ZonedDateTime a2=ZonedDateTime.parse(timewithZone,formatter);
String timewithZone = "05:03:05.875+02:00";
OffsetTime time = OffsetTime.parse(timewithZone);
System.out.println("Parsed into " + time);
This outputs
Parsed into 05:03:05.875+02:00
Your string contains a time and an offset, but no date. This conforms nicely, neither with an ISO_OFFSET_DATE_TIME nor a ZonedDateTime, but with an OffsetTime, a seldom used class that I think is there exactly because such a thing sometimes occurs in XML.
There is also an ISO_OFFSET_TIME formatter built in, but since this is the default format for OffsetTime we do not need to specify it.
It is failing because your string does not have the date related tokens. Check the example in the official documentation. In order to make it work you will need to add year/month/day data:
String timewithZone= "2018-07-3T05:03:05.875+02:00";
You cannot use the DateTimeFormatter.ISO_OFFSET_DATE_TIME because your date format does not adhere to that.
In fact, you don't even have a real date because there is no date component, only a time component.
You could define your own SimpleDateFormat instance with the format you're receiving, but you'll have to handle the fact that this data isn't really all that useful without date information. For example, that offset doesn't really tell us that much, because it might be in some region's Daylight Savings Time (DST) or not. And this heavily depends on on what actual DATE it is, not just what time.
You'll have to find out what the provider of this data even means with this, because right now you simply don't have enough information to really parse this into a proper date.
If this data just means a simple time stamp, used for for example saying "our worldwide office hours lunch time is at 12:30" then you could us the LocalTime class. That would be one of the few cases where a time string like this without a date is really useful. I have a sneaking suspicion this is not your scenario though.
A workaround may be
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSz");
String str = "05:03:05.875+02:00";
LocalTime time = LocalTime.parse(str, formatter);
System.out.println(time);
I tried the code in the format what you are getting,
Output :
05:03:05.875
Is this the one you are looking for?

Java time instant formatting discrepancies

The way Java time handles simple things like timestamps leaves me a little taken aback. Maybe I'm doing it wrong.
I want to generate an ISO 8601 timestamp string. The obvious way would be to create an Instance.now() and format it use DateTimeFormatter.ISO_INSTANT to format it. Except that Instance has no format() method, so I can't format it with the "instance" formatter. Imagine that.
So I have to create a ZonedDateTime from the instance. It shouldn't matter which zone I choose, so I choose UTC because that's what DateTimeFormatter.ISO_INSTANT is going to put it in anyway:
Instant.now().atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)
Now I get back a string, and obviously I want to get it back to a ZonedDateTime instance, because that's what I used to format it with! So I try:
ZonedDateTime.parse(timestamp, DateTimeFormatter.ISO_INSTANT)
It complains at me that there is no time zone information. But I used a ZonedDateTime to generate it --- it's not my fault that it wouldn't let me use an Instance to format it.
Oddly Instance doesn't have a format() method, but it does have a parse() method, which, again oddly, is parsed using DateTimeFormatter.ISO_INSTANT (even though I can't format an Instance using that formatter).
As pointed out in the comments, I can use DateTimeFormatter.ISO_INSTANT.format(Instance.now()) to format an instance directly, so why isn't there an Instance.format(…)?
So just generating and parsing a timestamp seems convoluted and inconsistent. Or am I doing it wrong?
First, you can just DateTimeFormatter.ISO_INSTANT.format(Instant.now()).
Next, I don't see why you expect to parse back what you've formatted. Formatting is not guaranteed to be a lossless operation. If you format a LocalDateTime with just the year, you wouldn't expect to parse it back to LocalDateTime, would you?
And of course you can parse Instant using DateTimeFormatter.ISO_INSTANT. DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from) - this is what Instant.parse(...) does.
There is no need for a format(DateTimeFormatter) method in Instant, because toString() does the job. The toString() method of Instant is implemented as:
return DateTimeFormatter.ISO_INSTANT.format(this);
Thus, all you need to do is call instant.toString().
To round-trip parse this back in, simply use parse():
Instant instant = Instant.parse(text);
Why do you need to respecify the formatter when parsing back the string?
Can't you just do ZonedDateTime.parse(timestamp);?

joda-time: new DateTime(String) vs DateTime.parse(String)

Using the joda-time-2.0 version library, I was wondering, which of this functions is better to construct from an ISO date (suposed XML xs:dateTime format): new DateTime(String) versus DateTime.parse(String).
Because both return a different result from same value. Example:
new DateTime("2012-08-16T07:22:05Z")
DateTime.parse("2012-08-16T07:22:05Z")
Resulting different because of the ISOChronology. First says is ISOChronology[Europe/Paris] and second ISOChronology[UTC], although milliseconds are the same.
Also, here recomends to use ISODateTimeFormat.dateTimeNoMillis(), giving the same result as using the first version (new).
The two methods use two different conversion methods: the constructor uses an instance of InstantConverter, which in case of strings is a StringConverter and which doesn't yet support reading the timezone from the passed string, while the parse method uses a DateTimeFormatter which knows how to parse the timezone.
Although both formats in theory accept an ISO datetime format, I consider that the constructor is buggy since it always uses the system timezone instead of the one specified in the string. This is inconsistent with the other possible values accepted by this constructor, which do take into account a chronology with its timezone offset. For example, this constructor will return a DateTime object with the UTC timezone:
new DateTime(DateTime.parse("2012-08-16T07:22:05Z"))

Categories