I have a time with string type like: "2015-01-05 17:00" and ZoneId is "Australia/Sydney".
How can I convert this time information to the corresponding to UTC time using Java 8 datetime API?
Also need to considering DST stuff.
You are looking for ZonedDateTime class in Java8 - a complete date-time with time-zone and resolved offset from UTC/Greenwich. In terms of design, this class should be viewed primarily as the combination of a LocalDateTime and a ZoneId. The ZoneOffset is a vital, but secondary, piece of information, used to ensure that the class represents an instant, especially during a daylight savings overlap.
For example:
ZoneId australia = ZoneId.of("Australia/Sydney");
String str = "2015-01-05 17:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime localtDateAndTime = LocalDateTime.parse(str, formatter);
ZonedDateTime dateAndTimeInSydney = ZonedDateTime.of(localtDateAndTime, australia );
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInSydney);
ZonedDateTime utcDate = dateAndTimeInSydney.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("Current date and time in UTC : " + utcDate);
An alternative to the existing answer is to setup the formatter with the appropriate time zone:
String input = "2015-01-05 17:00";
ZoneId zone = ZoneId.of("Australia/Sydney");
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(zone);
ZonedDateTime utc = ZonedDateTime.parse(input, fmt).withZoneSameInstant(UTC);
Since you want to interact with a database, you may need a java.sql.Timestamp, in which case you don't need to explicitly convert to a UTC time but can use an Instant instead:
ZonedDateTime zdt = ZonedDateTime.parse(input, fmt);
Timestamp sqlTs = Timestamp.from(zdt.toInstant());
**// Refactored Logic**
ZoneId australia = ZoneId.of("Australia/Sydney");
ZoneId utcZoneID= ZoneId.of("Etc/UTC");
String ausTime = "2015-01-05 17:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
//converting in datetime of java8
LocalDateTime ausDateAndTime = LocalDateTime.parse(ausTime, formatter);
// DateTime With Zone
ZonedDateTime utcDateAndTime = ausDateAndTime.atZone(utcZoneID);
// output - 2015-01-05T17:00Z[Etc/UTC]
// With Formating DateTime
String utcDateTime = utcDateAndTime.format(formatter);
// output - 2015-01-05 17:00
Related
I'm trying to parse 2009-07-30T16:10:36+06:00 to a date using yyyy-MM-dd'T'HH:mm:ssXXXXX.
However the output I get appears to have not factored in the offset, as I get yyyy-MM-dd'T'HH:mm:ssXXXXX.
Any ideas what I'm missing?
final DateTimeFormatter iso8601Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXXXX");
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", iso8601Formatter);
final String formatted = zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
If my understanding is correct you should set the zone similar to withZoneSameInstant(ZoneId.of("UTC"))
final ZonedDateTime zonedDateTime = ZonedDateTime.parse("2009-07-30T16:10:36+06:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
System.out.println("Without ZoneId: " + zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
System.out.println("With ZoneId: " + zonedDateTime.withZoneSameInstant(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
Result
Without ZoneId: 30/07/2009 16:10:36
With ZoneId: 30/07/2009 10:10:36
OffsetDateTime odt = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
ZonedDateTime zdt = ZonedDateTime.ofInstant(odt.toInstant(), ZoneOffset.UTC);
// 2009-07-30T10:10:36Z
First you have no zoned date time, which would also depend on the country.
Then actually you want the Greenwich time, the UTC.
If you want the time in UTC (which is not clear from the question), then the other answers give you the correct result. Since there is no time zone (such as Europe/London Pacific/Rarotonga) in your data, there is no point in using a ZonedDateTime. OffsetDateTime is a better fit:
final OffsetDateTime dateTime = OffsetDateTime.parse("2009-07-30T16:10:36+06:00");
final OffsetDateTime utcDateTime = dateTime.withOffsetSameInstant(ZoneOffset.UTC);
final String formatted = utcDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
System.out.println(formatted);
30/07/2009 10:10:36
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
final ZonedDateTime zonedDateTime1 =
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
But I want to get the converted date time as 2031-04-26 00:00:00+5:30 as my timestamp value is in the UTC Timezone.
Please help.
First, you should not use Timestamp. You can use DateTimeFormatter to parse into a LocalDateTime.
You then zone that LocalDateTime to UTC before converting to the Calcutta zone with ZonedDateTime.withZoneSameInstant.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter();
LocalDateTime localDateTime = LocalDateTime.parse("2031-04-25 18:30:00", formatter);
ZoneId calcuttaZone = ZoneId.of("Asia/Calcutta");
ZonedDateTime calcuttaZonedDateTime = localDateTime.atZone(ZoneOffset.UTC)
.withZoneSameInstant(calcuttaZone);
Using DateTimeFormatter to format ZonedDateTime:
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
System.out.println(formatter.format(zonedDateTime));
final ZonedDateTime zonedDateTime1 =
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
System.out.println(formatter.format(zonedDateTime1));
The output:
2031-04-25 23:00:00+05:30
2031-04-25 18:30:00+05:30
Edited: according to the comment from #Ole V.V. - The local date time has to be converted to the zonedatetime , before applying the format :
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
LocalDateTime ldt = rawDateTime.toLocalDateTime();
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
ZonedDateTime zdt = ldt.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(zoneId);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
System.out.println(formatter.format(zdt));
This will give the output:
2031-04-26 00:00:00+5:30
Instead of ZonedDateTime with named zones having (supra-)national standards like day-time-savings, use OffsetDateTime.
OffsetDateTime utc = OffsetDateTime.parse("2031-04-25T18:30:00Z");
OffsetDateTime asia = utc.withOffsetSameInstant(ZoneOffset.ofHoursMinutes(5, 30));
The default parsing is for the ISO format.
Z means zero, UTC, +0:00.
The resulting default formatting is 2031-04-26T00:00+05:30.
After comment of Ole V.V.
The above is especially error prone if summer time is involved, like in Central European Time with varying offsets +1:00 and +2:00.
Instant raw = Instant.parse("2031-04-25T18:30:00Z");
ZonedDateTime zoned = raw.atZone(ZoneId.of("Asia/Calcutta"));
OffsetDateTime offset = OffsetDateTime.from(zoned);
I read over the literature for ZonedDate and Instant and found that I can convert a local time to utc via the below:
LocalDate d = LocalDate.now();
LocalTime time = LocalTime.of(00, 00, 00);
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = ZonedDateTime.of(d, time, zone);
System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
Instant instant = zonedDateTime.toInstant();
System.out.println(instant);
The problem is the output looks like this:
2018-11-26T00:00:00
2018-11-26T08:00:00Z
I'm trying to get both strings in the format of "yyyy-MM-dd HH:mm:ss" but am having a hard time getting anything to work properly. Since I am using the output to query an MYSQL database I could just manually do:
String zoneDate = zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
String utcDate = zonedDateTime.toInstant().toString();
zoneDate = zoneDate.replace('T', ' ').replace('Z', ' ');
utcDate = utcDate.replace('T', ' ').replace('Z', ' ');
With my new output being:
2018-11-26 00:00:00
2018-11-26 08:00:00
But I feel like this is bad practice and there should be a method to convert to the proper format within the classes. Is there such a way to perform formatting as above from the default classes?
Follow snippet below.
LocalDate d = LocalDate.now();
LocalTime time = LocalTime.now();
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = ZonedDateTime.of(d, time, zone);
String zoneDate = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(zonedDateTime);
ZonedDateTime utcZonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of(ZoneOffset.UTC.getId()));
String utcZoneDate = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(utcZonedDateTime);
System.out.println(zoneDate);
System.out.println(utcZoneDate);
Output for this is
2018-11-26 02:20:08
2018-11-26 10:20:08
For more information please visit java doc -> https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
The data I fetch from DB is in UTC time. I need to convert it to CET/CEST. I am using below code. I am not sure if both CET and CEST will be taken care of. Please let me know if it takes care of CET and CEST ?
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
return LocalDateTime.parse(ptu, formatter)
.atOffset(ZoneOffset.UTC)
.atZoneSameInstant(ZoneId.of("Europe/Amsterdam"))
.format(formatter);
CET and CEST are not always the same, so you can't guarantee that one result will satisfy both timezones.
Consider using OffsetDateTime for your example
Printing the time now, and in "CET" is straightforward:
OffsetDateTime odt = OffsetDateTime.now();
System.out.println(odt); // 2018-10-26T11:25:49.215+01:00
System.out.println(odt.atZoneSameInstant(ZoneId.of("CET"))); // 2018-10-26T12:25:49.215+02:00[CET]
However, I don't believe there is a "CEST" in the ZoneID class.
So you could print the time of a particular country you know is in CEST and compare them.
For example, Algiers is currently in CET, but Amsterdam is in CEST:
System.out.println(odt.atZoneSameInstant(ZoneId.of("Europe/Amsterdam")));
System.out.println(odt.atZoneSameInstant(ZoneId.of("Africa/Algiers")));
Output:
2018-10-26T12:42:29.897+02:00[Europe/Amsterdam]
2018-10-26T11:42:29.897+01:00[Africa/Algiers]
The class you should be using is ZonedDateTime; as it has full time-zone support(including daylight savings).
Your code should be replaced with:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
ZonedDateTime utcTime = LocalDateTime.parse(ptu,formatter).atZone(ZoneId.of("UTC"));
ZonedDateTime yourTime = utcTime.withZoneSameLocal(ZoneId.of("Europe/Amsterdam"));
return yourTime.format(formatter);
Please refer below snippet :
ZonedDateTime dateTime =null;
Date finalDate = null;
DateTimeFormatter format =null;
String date = yourdate;
LocalDateTime lid = LocalDateTime.parse(date,
DateTimeFormatter.ofPattern(""yyyy-MM-dd"));
ZoneId id = ZoneId.of("GMT");//Add yours
ZonedDateTime gmtZonedDateTime = lid.atZone(id);
ZoneId zoneId = ZoneId.of("America/Los_Angeles"); //in case your add your
dateTime = gmtZonedDateTime.withZoneSameInstant(id);
format = DateTimeFormatter.ofPattern("yyyy-MM-dd");
SimpleDateFormat sfmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
finalDate = sfmt.parse(format.format(dateTime));
I have a datetime-string WITHOUT a specified timezone.
But I want to parse it with ZonedDateTime to give it a timezone-meaning in the act of parsing.
This code is working but uses LocalDateTime for parsing - and then convert it to ZonedDateTime with giving it a timezone-meaning.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern ("yyyyMMddHHmm");
String tmstr = "201810110907";
LocalDateTime tmp = LocalDateTime.parse (tnstr,dtf);
ZonedDateTime mytime = ZonedDateTime.of (tmp, ZoneId.of ("UTC"));
Is there a way I can parse it directly with ZonedDateTime?
I have tried this, but it was not working.
mytime = mytime.withZoneSameInstant(ZoneId.of("UTC")).parse(str,dtf);
You may specify a default time zone on the formatter:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmm")
.withZone(ZoneId.of("UTC"));
String tmstr = "201810110907";
ZonedDateTime mytime = ZonedDateTime.parse(tmstr, dtf);
System.out.println(mytime);
Output:
2018-10-11T09:07Z[UTC]
Bonus tip: Rather than ZoneId.of("UTC") it’s usually nicer to use ZoneOffset.UTC. If you accept the output being printed as 2018-10-11T09:07Z instead (Z meaning UTC).