LocalDateTime : converting String to HH:mm:ss - java

What I need to do :
I need to pass a LocalDateTime object to a constructor and I have a string that have "18:14:00" as value.
My question :
How can I convert the string to LocalDateTime ?
What I have done :
After some researches, I put this but it didn't work :
LocalDateTime.parse("18:14:00", DateTimeFormatter.ofPattern("HH:mm:ss"));
java.time.format.DateTimeParseException: Text '18:14:00' could not be
parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO
resolved to 18:14 of type java.time.format.Parsed

The "Unable to obtain LocalDateTime" exception is because the parsed text only has time values, no date values, so it is impossible to construct a Local​Date​Time object.
Parse to a LocalTime instead:
LocalTime time = LocalTime.parse("18:14:00");
System.out.println(dateTime); // Prints: 18:14
The "HH:mm:ss" pattern is the default for a LocalTime, so there is no need to specify it (see: DateTimeFormatter.ISO_LOCAL_TIME).
If you want/need a LocalDateTime object, parsed similarly to how SimpleDateFormat did it, i.e. defaulting the Jan 1, 1970, then you need to explicitly specify the default date value:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.parseDefaulting(ChronoField.EPOCH_DAY, 0)
.toFormatter();
LocalDateTime dateTime = LocalDateTime.parse("18:14:00", fmt);
System.out.println(dateTime); // Prints: 1970-01-01T18:14
For comparison, that is equivalent to the old SimpleDateFormat result:
Date date = new SimpleDateFormat("HH:mm:ss").parse("18:14:00");
System.out.println(date); // Prints: Thu Jan 01 18:14:00 EST 1970

You have a time component, not a date component. So the best you can do (with what you have) is use a LocalTime (instead of a LocalDateTime). Like,
LocalTime lt = LocalTime.parse("18:14:00", DateTimeFormatter.ofPattern("HH:mm:ss"));

Related

Convert the TimeStamp from an API to local TimeStamp

I need a help with the code.
My API has TimeStamp in UTC format and I need to convert it to my local TimeStamp i.e., CST.
For example:
MY API has TimeStamp value as : 2019-01-08T13:17:53.4225514 (which is in UTC).
I need the output to be like Jan 8, 2019 8:28:18.514 AM (Which is in CST my local Time )
How to convert it in local TimeStamp?
Timestamp createdOn = api.getCreatedOn(); (HERE I get the TimeStamp as Object from api)
Turns out a bit difficult to do right after all.
Here's how you parse a String timestamp in UTC to obtain a ZonedDateTime object of your preferred time zone:
// define formatter once to be re-used wherever needed
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss") // all fields up seconds
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) // handle variable-length fraction of seconds
.toFormatter();
String text = "2019-01-08T13:17:53.4225514";
LocalDateTime localTime = LocalDateTime.parse(text, formatter); // parse string as a zone-agnostic LocalDateTime object
ZonedDateTime utcTime = localTime.atZone(ZoneId.of("UTC")); // make it zoned as UTC zoned
ZonedDateTime cstTime = utcTime.withZoneSameInstant(ZoneId.of("America/Chicago")); // convert that date to the same time in CST
// print resulting objects
System.out.println(utcTime);
System.out.println(cstTime);

Parsing date with timezone from a string

Quick (I suppose) question. How to parse string like that "2018-07-22 +3:00" to OffsetDateTime (setting time to 0:0:0.0)?
DateTimeFormatter formatter =cDateTimeFormatter.ofPattern("yyyy-MM-dd xxx");
OffsetDateTime dt = OffsetDateTime.parse("2007-07-21 +00:00", formatter);
java.time.format.DateTimeParseException: Text '2007-07-21 +00:00'
could not be parsed: Unable to obtain OffsetDateTime from
TemporalAccessor: {OffsetSeconds=0},ISO resolved to 2007-07-21 of type
java.time.format.Parsed
The trick here is to start by getting the TemporalAccessor:
TemporalAccessor ta = DateTimeFormatter.ofPattern("yyyy-MM-dd XXX").parse("2018-07-22 +03:00");
From there, you can extract a LocalDate and a ZoneOffset:
LocalDate date = LocalDate.from(ta);
ZoneOffset tz = ZoneOffset.from(ta);
And combine them like so:
ZonedDateTime zdt = date.atStartOfDay(tz);
An OffsetDateTime requires a time-of-day, but your format string doesn't supply that, so you need to tell the DateTimeFormatter to default time-of-day to midnight.
Also, offset +3:00 is invalid, since hour must be 2-digit, which means you need to fix that first.
This will do both:
public static OffsetDateTime parse(String text) {
// Fix 1-digit offset hour
String s = text.replaceFirst("( [+-])(\\d:\\d\\d)$", "$10$2");
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd xxx")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.toFormatter();
return OffsetDateTime.parse(s, formatter);
}
Test
System.out.println(parse("2018-07-22 +3:00"));
System.out.println(parse("2018-07-22 +03:00"));
System.out.println(parse("2007-07-21 +00:00"));
Output
2018-07-22T00:00+03:00
2018-07-22T00:00+03:00
2007-07-21T00:00Z

Unable to convert UTC to IST, it is still returning me UTC only

I am trying to convert UTC Date to IST. But to my surprise, after converting everything, it is still returning me UTC only. How is it possible?
INPUT:
StartDateTimeUtc='2017-09-15T14:00:00',
EndDateTimeUtc='2017-09-15T15:00:00'
Code:
public static final String DATE_FORMATE_CURRENT = "yyyy-MM-dd'T'HH:mm:ss";
Date meetingStartDate = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(model.StartDateTimeUtc);
Date meetingEndDate = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(model.EndDateTimeUtc);
//Convert Date to String
DateFormat df = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT);
String meetinStartDateString = df.format(meetingStartDate);
String meetingEndDateString = df.format(meetingEndDate);
//Convert String Date to IST
SimpleDateFormat dftwo = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT);
dftwo.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date = null;
Date datetwo = null;
try {
date = dftwo.parse(meetinStartDateString);
datetwo = dftwo.parse(meetingEndDateString);
} catch (ParseException e) {
e.printStackTrace();
}
dftwo.setTimeZone(TimeZone.getDefault());
String formattedStartDate = dftwo.format(date);
String formattedEndDate = dftwo.format(datetwo);
//Convert String Date back to Date format so that we can pass into Calendar code
Date meetingStartDateFinal = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(formattedStartDate);
Date meetingEndDateFinal = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(formattedEndDate);
OUTPUT again in UTC:
Start Date : Fri Sep 15 14:00:00 GMT+05:30 2017
End Date : Fri Sep 15 15:00:00 GMT+05:30 2017
A java.util.Date doesn't have any timezone information. It just contains one value: the number of milliseconds since unix epoch (1970-01-01T00:00Z, or January 1st 1907, at midnight in UTC).
This number of milliseconds is the same, everywhere in the world. What's is different is the corresponding date and time in each timezone. Example: right now, this millis value is 1505481835424, which corresponds, in UTC, to 2017-09-15T13:23:55.424Z. This same value corresponds to 10:23 AM in São Paulo, 18:53 in Kolkata, 14:23 in London and so on. The local date/time is different in each timezone, but the millis value is the same for everyone.
That's why you don't convert a Date itself: the millis value is the same, and there's no need to change it. What you can change is the representation of this date in different timezones.
SimpleDateFormat, by default, uses the JVM default timezone to parse dates. But if you know that the inputs are in a specific zone, you must set in the formatter. So, to parse your inputs, you must do:
String startDateTimeUtc = "2017-09-15T14:00:00";
String endDateTimeUtc = "2017-09-15T15:00:00";
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss");
// input is in UTC
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// parse dates
Date meetingStartDate = sdf.parse(startDateTimeUtc);
Date meetingEndDate = sdf.parse(endDateTimeUtc);
The 2 Date objects above will correspond to 14:00 and 15:00 UTC (which is the same as 19:30 and 20:30 in Kolkata timezone).
But if you just print the Date objects directly (using System.out.println, logging, or even checking their values in a debugger), it'll implicity call the toString() method, which uses the JVM default timezone behind the scenes, resulting in the output you're seeing (Fri Sep 15 14:00:00 GMT+05:30 2017).
If you want to print in a specific format, and in a specific timezone, you'll need another formatter:
// another formatter for output
SimpleDateFormat outputFormat= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
// output will be in Asia/Kolkata timezone
outputFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
System.out.println(outputFormat.format(meetingStartDate));
System.out.println(outputFormat.format(meetingEndDate));
The output will be:
2017-09-15T19:30:00
2017-09-15T20:30:00
Which corresponds to the same UTC dates in Kolkata timezone.
Just remember: you don't convert the Date's between timezones (because their millis values are "absolute" - they are the same for everyone in the world). You just change the String representation of those dates (the corresponding date/time in a specific timezone).
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).
This new API has lots of different date/time types for each situation. In this case, the inputs have date and time, but no timezone information, so first I parse them to a org.threeten.bp.LocalDateTime, using a org.threeten.bp.format.DateTimeFormatter:
// parse the inputs
DateTimeFormatter fmt = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime startDt = LocalDateTime.parse(startDateTimeUtc, fmt);
LocalDateTime endDt = LocalDateTime.parse(endDateTimeUtc, fmt);
Then I use a org.threeten.bp.ZoneOffset to convert them to UTC, and later a org.threeten.bp.ZoneId to convert this to another timezone. The result will be a org.threeten.bp.ZonedDateTime:
// input is in UTC
ZoneOffset utc = ZoneOffset.UTC;
// convert to Asia/Kolkata
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime start = startDt.atOffset(utc).atZoneSameInstant(zone);
ZonedDateTime end = endDt.atOffset(utc).atZoneSameInstant(zone);
Then I use the same DateTimeFormatter to format the output:
System.out.println(fmt.format(start));
System.out.println(fmt.format(end));
The output is:
2017-09-15T19:30:00
2017-09-15T20:30:00
Note that I don't need to set the timezone in the formatter, because the timezone information is in the objects (they are responsible to do the conversion).

Cannot resolve 00 seconds when preparing specific Format of UTC date in Java SE 8 API

Code:
LocalDateTime ldt3 = getUtcDateTime("2016-02-01T10:11:00Z");
System.out.println(ldt3);
Output:
2016-02-01T10:11
Required Output:
2016-02-01T10:11:00
Is it possible to derive such a output? Also how to print the UTC String value out of LocalDateTime having zero seconds?
Code:
LocalDateTime localDateTime = getCurrentUtcDateTime();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Z"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
ZonedDateTime.parse(zonedDateTime.format(formatter), formatter)
.toString();
Output:
2016-02-12T12:12Z
Required Output:
2016-02-12T12:12:00Z
How to get the required outputs in both cases?
You should use the DateTimeFormatter to print out your output, instead of reparsing it again. A LocalDateTime has no system to store the formatter it was created with.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
System.out.println(zonedDateTime.format(formatter));

DateTimeFormatter - parsing string with time zone

I have a JSpinner for selecting specific time (with today's date) and I need to convrert the String result into LocalDateTime instance. However, I can't seem to write the regex string right. Could you tell me what am I doing wrong, please?
JSpinner:
SpinnerDateModel sm = new SpinnerDateModel(date, null, null, Calendar.HOUR_OF_DAY);
spinnerStart = new JSpinner(sm);
JSpinner.DateEditor de = new JSpinner.DateEditor(spinnerStart, "hh:mm");
spinnerStart.setEditor(de);
When checking the value with spinnerStart.getValue().toString(), I get the following:
Mon May 25 12:21:24 CEST 2015
I am trying to parse the string according to this documentation but am getting an exception:
SEVERE [global]
java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {MinuteOfHour=21, MilliOfSecond=0, NanoOfSecond=0, HourOfAmPm=0, MicroOfSecond=0, SecondOfMinute=24},ISO,Europe/Paris resolved to 2015-05-25 of type java.time.format.Parsed
at java.time.LocalTime.from(LocalTime.java:409)
at java.time.LocalDateTime.from(LocalDateTime.java:457)
This is my progress so far:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd hh:mm:ss zzzz yyyy");
LocalDateTime startTime = LocalDateTime.parse(spinnerStart.getValue().toString(), dtf);
I tried using 'V' instead of 'z' and some other choices with offsets as well but cannot seem to figure it out. Thanks for any tips.
So, you have a java.util.Date object, which represents a precise instant on the time-line. And to transform it into a LocalDateTime, you're transforming the Date into a String, and then parse the String.
That's a bad strategy. You shouldn't do that.
Just use the date transformation methods:
LocalDateTime localDateTime =
date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
Of course, if you want the value for another time zone than the default one, you'll need to pass the appropriate ZoneId.

Categories