DateTimeFormatter - parsing string with time zone - java

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.

Related

Java Date Time conversion to given timezone

I have a DateTime in the format of Tue, 30 Apr 2019 16:00:00 +0800 which is RFC 2822 formatted date
I need to convert this to the given timezone in the DateTime which is +0800
So if i summarized,
DateGiven = Tue, 30 Apr 2019 16:00:00 +0800
DateWanted = 01-05-2019 00:00:00
How can i achieve this in Java?
I have tried the below code but it gives 08 hours lesser than the current time which is
30-04-2019 08:00:00
Code i tried
String pattern = "EEE, dd MMM yyyy HH:mm:ss Z";
SimpleDateFormat format = new SimpleDateFormat(pattern);
Date startDate = format.parse(programmeDetails.get("startdate").toString());
//Local time zone
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
//Time in GMT
Date dttt= dateFormatLocal.parse( dateFormatGmt.format(startDate) );
You are on right approach but just use java-8 date time API module, first create DateTimeFormatter with the input format representation
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss Z");
And then use OffsetDateTime to parse string with offset
OffsetDateTime dateTime = OffsetDateTime.parse("Tue, 30 Apr 2019 16:00:00 +0800",formatter);
And the call the toLocalDateTime() method to get the local time
LocalDateTime localDateTime = dateTime.toLocalDateTime(); //2019-04-30T16:00
If you want the output in particular format again you can use DateTimeFormatter
localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) //2019-04-30T16:00:00
Note : As #Ole V.V pointed in comment, after parsing the input string into util.Date you are getting the UTC time
The class Date represents a specific instant in time, with millisecond precision.
So now if you convert the parsed date time into UTC you get 2019-04-30T08:00Z without offset, so you can use withOffsetSameInstant to convert it into any particular timezone
dateTime.withOffsetSameInstant(ZoneOffset.UTC)
You misunderstood. According to RFC 2822 +0800 means that an offset of 8 hours 0 minutes has already been applied to the time compared to UTC. So the output you got was the correct GMT time.
java.time
I recommend you skip the old and outdated classes SimpleDateFOrmat and Date. It’s much nicer to work with java.time, the modern Java date and time API. Furthermore it has the RFC format built in, so we don’t need to write our own formatter.
OffsetDateTime parsedDateTime = OffsetDateTime
.parse("Tue, 30 Apr 2019 16:00:00 +0800",
DateTimeFormatter.RFC_1123_DATE_TIME);
ZonedDateTime dateTimeInSingapore
= parsedDateTime.atZoneSameInstant(ZoneId.of("Asia/Singapore"));
System.out.println("In Singapore: " + dateTimeInSingapore);
OffsetDateTime dateTimeInGmt
= parsedDateTime.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("In GMT: " + dateTimeInGmt);
Output:
In Singapore: 2019-04-30T16:00+08:00[Asia/Singapore]
In GMT: 2019-04-30T08:00Z
The built-in formatter is named RFC_1123_DATE_TIME because the same format is used in multiple Requests for Comments (RFCs).
Links
RFC 2822 Internet Message Format
Oracle tutorial: Date Time explaining how to use java.time.
with the help of #ole v.v's explanation i have separated the datetime value for two
1. time
2. timezone
then i used this coding to extract the datetime which is related to the given timezone
//convert datetime to give timezone
private static String DateTimeConverter (String timeVal, String timeZone)
{
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat offsetDateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
offsetDateFormat2.setTimeZone(TimeZone.getTimeZone(timeZone));
String result =null;
try {
result = offsetDateFormat2.format(format.parse(timeVal));
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}

Java, unparsable date error, converting from String to Date

I have this String "2019-10-17T16:00:00+02:00" and I want to convert this String to a Date object, because I want to change the format. I tried this:
SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date dt = sd1.parse(mystring);
SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd");
String newDate = sd2.format(dt);
System.out.println(newDate);
But I have this message: Unparseable date: "2019-10-17T16:00:00+02:00"
What can I do?
Thank you all
For the sake of being up to date:
Please consider using the modern date and time API java.time.
You can easily parse and format dates, times and date times using it.
See this example:
public static void main(String[] args) {
String d = "2019-10-17T16:00:00+02:00";
OffsetDateTime odt = OffsetDateTime.parse(d, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println(odt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss Z")));
}
The output is this:
2019/10/17 16:00:00 +0200
That formatter is used be default, so no need to specify. The standard ISO 8601 formats are used by default in java.time.
OffsetDateTime.parse( "2019-10-17T16:00:00+02:00" ) // ISO 8601 formats can be parsed directly, without specifying a `DateTimeFormatter` object.
If you just want to extract the date part of a date time, then you can do that, too by just applying two additional lines of code:
LocalDate date = odt.toLocalDate();
System.out.println(date.format(DateTimeFormatter.ISO_DATE));
The pattern letter for ISO 8601 time zones is X not Z as others have noted.
Use:
SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
And parsing will succeed.

JodaTime: Datetime with Z instead -04:00

Hi I have a problem with joda time. I'm trying to get the 'Z' value at the end of datetime but couldn't :
I have tried with below syntax but no luck, not sure exactly
LocalDateTime currentDateTime = LocalDateTime.now(DateTimeZone.forID("GMT"));
Output: 2019-06-11T21:29:42.474
LocalDateTime currentDateTime = LocalDateTime.now(DateTimeZone.forID("GMT"));
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateTime parsedDateTimeUsingFormatter
= DateTime.parse(currentDateTime.toString(), fmt);
System.out.println(parsedDateTimeUsingFormatter);
Output: 2019-06-11T21:29:42.474-04:00
But I need like the below in GMT format:
Expected output: 2019-06-11T21:29:42.474Z
It sounds like you just need to create a DateTime in UTC:
DateTime utcNow = DateTime.now(DateTimeZone.UTC);
System.out.println(utcNow);
It's not a matter of "just putting a Z at the end" - you need to make sure you're actually obtaining a UTC timestamp to start with.
You can try this:
LocalDateTime localNow = LocalDateTime.now(TimeZone.getTimeZone("GMT").toZoneId());
Now That we have it set to GMT, we can proceed with;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String formatDateTime = localNow.format(formatter);
Answer will be in this format
2019-06-11T22:28:20.062Z

LocalDateTime : converting String to HH:mm:ss

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"));

DateTimeFormatter could not be parsed using "HH:mm E d MMM YYYY" pattern

I am retrieving a date/time from an external data source, this is returned in the following format "14:30 Sat 05 May" with no year.
I've been trying to parse this to a LocalDateTime unsuccessfully. The data returned does not return a year as it is an assumption that we are always operating in the current year.
//date to parse
String time = "14:30 Sat 05 May";
//specify date format matching above string
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm E d MMM YYYY") ;
//we do not have a year returned but i can make the assumption we use the current year
LocalDateTime formatDateTime = LocalDateTime.parse(time, formatter).withYear(2018);
The above code throws the following exception
Exception in thread "main" java.time.format.DateTimeParseException: Text '14:30 Sat 05 May' could not be parsed at index 16
Any help appreciated.
Default year
Specify a default year in your DateTimeFormatter, using the DateTimeFormatterBuilder class by calling parseDefaulting and specifying the year-field with ChronoField.YEAR.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("HH:mm E d MMM")
.parseDefaulting(ChronoField.YEAR, 2018) // <------
.toFormatter(Locale.ENGLISH);
With this formatter instead of yours:
LocalDateTime.parse( "14:30 Sat 05 May" , formatter )
…I get:
2018-05-05T14:30
See that code run live at IdeOne.com.
Points to note:
Your format pattern string needs to match the parsed string end-to-end. So when your date-time string doesn’t have a year in it, don’t include YYYY in your format pattern.
In any case don’t use uppercase YYYY here. It’s for week-based year and only useful with week numbers. If your string had had a year in it, you should have used uuuu or lowercase yyyy.
Make it a habit to give explicit locale to your formatter so you know it also works on other computers, and on yours when one day you play with its settings.
LocalDateTime.parse() expects a String that represents a valid date, which the year part.
You cannot set the year after invoking this method in this way :
LocalDateTime.parse(time, formatter).withYear(2018);
The year has to be set before because otherwise parse() throws DateTimeParseException.
As a workaround you may concatenate the current year in the input.
Some additional notes:
the pattern you use and the input date in textual format don't match exactly.
You don't specify a Locale for the parsing operation.
It means that it will work according to the local where the JVM is run.
To ensure that it works in any case, you should specify the Locale.
So you could try something like :
//date to parse
String time = "14:30 Sat 05 May";
time += " " + LocalDate.now().getYear();
//specify date format matching above string
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm EEE dd MMM yyyy", Locale.US) ;
//we do not have a year returned but i can make the assumption we use the current year
LocalDateTime formatDateTime = LocalDateTime.parse(time, formatter);

Categories