Parsing UTC time to CET/CEST - java

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

Related

Wrong value while converting UTC date to a given timezone

I am trying to convert a UTC date String of the format 2020-06-09T06:30:00Z to a Timezone like Asia/Calcutta.
The time offset between UTC and Asia/Calcutta is +5:30, so the expected result on converting 2020-06-09T06:30:00Z to Asia/Calcutta is 2020-06-09T12:00:00Z but I am getting 2020-06-09T01:00:00Z
String utcDate = "2020-06-09T06:30:00Z";
String timezone = "Asia/Calcutta";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
LocalDateTime date = LocalDateTime.parse(utcDate, formatter); //2020-06-09T06:30
ZonedDateTime zonedDate = ZonedDateTime.of(date, ZoneId.of(timezone)); //2020-06-09T06:30+05:30[Asia/Calcutta]
Date dateConverted = Date.from( zonedDate.toInstant()); //Tue Jun 09 01:00:00 UTC 2020
I think zonedDate.toInstant() is converting subtracting 5:30 instead of adding 5:30 to 2020-06-09T06:30. My machine is in UTC timezone. may be its converting to local time don't know what is the issue. Also tried below method, still same issue.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone(timezone));
sdf.parse(dateString);
java.time
I agree with you, you should strongly prefer to use java.time, the modern Java date and time API. It’s not complicated when you know how.
String utcDate = "2020-06-09T06:30:00Z";
String timezone = "Asia/Calcutta";
ZoneId zone = ZoneId.of(timezone);
ZonedDateTime zdt = Instant.parse(utcDate).atZone(zone);
System.out.println("zdt: " + zdt);
Output is:
zdt: 2020-06-09T12:00+05:30[Asia/Calcutta]
You notice that the time of day in the ZonedDateTime is 12:00 as you had expected. The trailing Z that you also said you expected is wrong, though. Z means an offset of 0 from UTC, so since the offset is +05:30, we are very happy not to have the Z there.
If what you needed was an old-fashioned Date object, presumably for a legacy API that you don’t want to upgrade just now, there’s no reason to convert to your time zone first. This works:
Date oldfashionedDate = Date.from(Instant.parse(utcDate));
System.out.println("oldfashionedDate: " + oldfashionedDate);
Output in my time zone is:
oldfashionedDate: Tue Jun 09 08:30:00 CEST 2020
You may be in doubt whether the Date is right. It is. Since I am in Europe/Copenhagen time zone, currently at offset +02:00, the Date prints in this time zone, so the time of day is 8:30 (the Date doesn’t hold a time zone or offset). If instead I run in Asia/Calcutta time zone:
oldfashionedDate: Tue Jun 09 12:00:00 IST 2020
You notice IST for India Standard Time instead of CEST for Central European Summer Time. And the time is 12:00 as expected.
Points for you to take with you
Never hardcode Z as a literal in a format pattern string. As I said, it’s an offset, so it needs to be parsed as an offset.
For the same reason don’t parse into a LocalDateTime. A LocalDateTime. hasn’t got any offset, so you are losing information.
In this case use no formatter at all. Your format is ISO 8601, and Instant parses it as its default, that is, without any explicit formatter (OffsetDateTime and ZonedDateTime do too).
Make the conversion from UTC to Asia/Calcutta. It seems to me that you were doing the opposite conversion.
Link
Wikipedia article: ISO 8601
Got it work using SimpleDateFormat as shown below. But anyone coming across this issue should probably use ZonedDateTime.
String utcDate = "2020-06-09T06:30:00Z";
String timezone = "Asia/Calcutta";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf1.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = sdf1.parse(utcDate); // Tue Jun 09 06:30:00 UTC 2020
SimpleDateFormat sdf2 = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
sdf2.setTimeZone(TimeZone.getTimeZone(timezone));
String sDateInZone = sdf2.format(date); // 09-6-2020 12:00:00 PM
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
Date dateInZone = formatter.parse(sDateInZone); // Tue Jun 09 12:00:00 UTC 2020
EDIT: Got it to work using ZonedDateTime also as shown below:
String utcDate = "2020-06-09T06:30:00Z";
String timezone = "Asia/Calcutta";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
LocalDateTime dateUtc = LocalDateTime.parse(utcDate, formatter);
ZonedDateTime utcZonedDateTime = dateUtc.atZone(ZoneId.systemDefault());
ZoneId zoneId = ZoneId.of(timezone);
ZonedDateTime zonedDateTime = utcZonedDateTime.withZoneSameInstant(zoneId);
String zoneDateString = formatter.format(zonedDateTime);
Date date = Date.from(LocalDateTime.parse(zoneDateString, formatter).atZone(ZoneId.systemDefault()).toInstant());

Format ZonedDateTime and Instant to different string format

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

converting time from BST to American timeZones CST MST EST PST

I am converting time from GMT to different USA time-zones. For that, I have written a method which is returning the 1-hour prior time. if the time is 2:00 clock it's returning 1:00 clock
private static Date timeFormat(String timeZone) throws ParseException {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat gmtFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
gmtFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()));
Date date = null;
try {
date = gmtFormat.parse(sdfDate.format(new Date()));
LOG.info("GMT format time and date ==>> "+date);
} catch (ParseException e) {
e.printStackTrace();
}
DateFormat pstFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
pstFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
String timedd = pstFormat.format(date);
LOG.info("Return the new time based on timezone : "+pstFormat.format(date));
return gmtFormat.parse(timedd);
}
Can anybody help me out what exactly is the issue, because a few months back the same method was working fine? Is it happening because of daylight saving time?
This can be done in a much simpler way using java.time APIs. Use Instant to represent the time in UTC. It can be converted to time at any zone, and formatted to a particular pattern.
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Instant now = Instant.now();
ZonedDateTime dt = now.atZone(ZoneId.of("UTC-05:00"));
System.out.println(dt.format(format)); //2017-05-24 04:51:03
ZonedDateTime pstDate = now.atZone(ZoneId.of("UTC-07:00"));
System.out.println(pstDate.format(format)); //2017-05-24 02:51:03
After so much of digging i have found that TimeZone won't give correct result on basis of time-zone
(EST, CST, MST, PST)
so in my method the param which i have passed as timeZone was coming as a
(EST, CST, MST, PST)
Instead of EST, CST, MST, PST i have passed US/Eastern US/Pacific US/Mountain US/Central, and it worked fine for me

Not able to convert EST to IST time in Java

Hi i am currently work on creating Desktop application using Swing.I was able to convert IST to EST time using Date class in java but not able to convert EST to IST time and it gives same EST time as IST time. Please find the below code .
ChangetoEST function is giving correct EST time from IST time.
ChangetoIST function is not giving correct IST time from EST time and showing given EST time as IST time.
public String changetoEST(String date) throws ParseException
{
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String dateInString = date;
Date d=formatter.parse(dateInString);
TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York");
formatter.setTimeZone(tzInAmerica);
String sDateInAmerica = formatter.format(d);
Date dateInAmerica = formatter.parse(sDateInAmerica);
String a=formatter.format(dateInAmerica);
return a;
}
public String changetoIST(String date) throws ParseException
{
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String dateInString = date;
Date d=formatter.parse(dateInString);
TimeZone tzInIndian = TimeZone.getTimeZone("Asia/Calcutta");
formatter.setTimeZone(tzInIndian);
String sDateInAmerica = formatter.format(d);
Date dateInAmerica = formatter.parse(sDateInAmerica);
String a=formatter.format(dateInAmerica);
return a;
}
The parse calls are done without you explicitly setting a time zone, which means that parsing is done using your default time zone.
Set the source time zone before parsing, parse, set time zone to target time zone, and format result.
E.g.
public static String istToEst(String dateInput) throws ParseException {
return changeTimeZone(dateInput, TimeZone.getTimeZone("Asia/Calcutta"),
TimeZone.getTimeZone("America/New_York"));
}
public static String estToIst(String dateInput) throws ParseException {
return changeTimeZone(dateInput, TimeZone.getTimeZone("America/New_York"),
TimeZone.getTimeZone("Asia/Calcutta"));
}
private static String changeTimeZone(String dateInput, TimeZone sourceTimeZone,
TimeZone targetTimeZone) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
formatter.setTimeZone(sourceTimeZone);
Date date = formatter.parse(dateInput);
formatter.setTimeZone(targetTimeZone);
return formatter.format(date);
}
Test
String dateInput = "08/22/2016 02:21 AM";
System.out.println(dateInput);
System.out.println(istToEst("08/22/2016 02:21 AM"));
System.out.println(estToIst("08/22/2016 02:21 AM"));
Output
08/22/2016 02:21 AM
08/21/2016 04:51 PM
08/22/2016 11:51 AM
Set formatter to the source timezone before parsing (this is the step you are missing), then set it to the destination timezone before formatting, otherwise it parses it using the local timezone, which is IST for you.
Also you should just be able to return sDateInAmerica directly, you don't need to re-parse then re-format it a second time.
java.time
You are using troublesome old legacy date-time classes, now supplanted by the java.time classes.
We parse the input string as a LocalDateTime as it lacks any info about offset-from-UTC or time zone (offset plus rules for anomalies such as DST).
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/yyyy hh:mm a" );
LocalDateTime ldt = LocalDateTime.parse( input , f );
Apply a time zone to get an actual moment on the timeline, a ZonedDateTime object.
ZoneId zNewYork = ZoneId.of( "America/New_York" );
ZonedDateTime zdtNewYork = ldt.atZone( zNewYork );
To see the same moment through the lens of another time zone, another wall-clock time, adjust into another ZoneId. Notice that we are not going through another LocalDateTime as the purpose of that class is to forget any information about offset or time zone. We want the opposite, to use the info about time zone to adjust wisely between zones. So while New York is behind UTC by four hours, India is ahead of UTC by five and a half hours. So we need a total of nine and a half hour adjustment, which may include a change in date.
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdtKolkata = zdtNewYork.withZoneSameInstant( zKolkata ); // Same simultaneous moments on the timeline.
Generate String
You can generate a String in any format you desire to represent the date-time value.
String output = zdtKolkata.format( f );
Generally better to let java.time automatically localize for you.
Locale l = Locale.CANADA_FRENCH; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
String output = zdtKolkata.format( f );

Java 8 Convert given time and time zone to UTC time

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

Categories

Resources