Convert Date ( Google Calendar api ) to Date with timezone - java

I am trying to convert a localdatetime to Date (which I use in Google Calendar api method)
Zone Id = "America/New_York"
I always, get this result :
2021-08-10T00:00:00.000+02:00
+02:00 is my local time zone
I want to get -04:00 America/New_York in same format as above
Here is the method
public static Date toDate(LocalDateTime startTime, String zoneId) {
ZoneId zonedId = ZoneId.of(zoneId);
return Date.from(Instant.from(startTime.atZone(zonedId)));
}
Please anyone can help?

java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
A sample solution using java.time, the modern Date-Time API: You can use ZonedDateTime#withZoneSameInstant for this purpose.
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZoneId sourceZone = ZoneId.of("Europe/Berlin");
ZonedDateTime zdtSource = ZonedDateTime.now(sourceZone);
System.out.println(zdtSource);
ZoneId targetZone = ZoneId.of("America/New_York");
ZonedDateTime zdtTarget = zdtSource.withZoneSameInstant(targetZone);
System.out.println(zdtTarget);
}
}
Output from a sample run:
2021-08-10T20:06:24.023038+02:00[Europe/Berlin]
2021-08-10T14:06:24.023038-04:00[America/New_York]
ONLINE DEMO
What if I need OffsetDateTime?
You can use ZonedDateTime#toOffsetDateTime to get OffsetDateTime out of a ZonedDateTime object e.g.
OffsetDateTime odtTarget = zdtTarget.toOffsetDateTime();
Note: For any reason, if you need to convert this object of ZonedDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(zdtTarget.toInstant());
Learn more about the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

It looks like you need to use a DateTimeFormatter.
If that is not sufficient,
try DateTimeFormatterBuilder.
Take a look at DateTimeFormatterBuilder usages in Java 8, specifically optionals for examples of using a DateTimeFormatterBuilder.

To get java.util.Date from with proper Zone conversion, first use ZonedDateTime and DateTimeFormatter from java.time and finally use SimpleDateFormat to get java.util.Date.
public static Date toDate(LocalDateTime startTime, String zoneId) throws ParseException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
ZonedDateTime source = startTime.atZone(ZoneId.of("Asia/Dhaka"));
ZonedDateTime result = source.withZoneSameInstant(ZoneId.of(zoneId));
String date = result.format(formatter);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
return format.parse(date);
}

Thank you for everyone , I read the comments and got the idea how to solve it from the comments then I ended up with the following code
import com.google.api.client.util.DateTime;
public static DateTime toGoogleDateTime(LocalDateTime startTime, String zoneId) {
ZonedDateTime zdtSource = startTime.atZone(ZoneId.of(zoneId));
Date date = Date.from(zdtSource.toInstant());
return new DateTime(date, TimeZone.getTimeZone(ZoneId.of(zoneId)));
}
the zoneId gets from
https://gist.github.com/adamgen/3f2c30361296bbb45ada43d83c1ac4e5

I was looking for this and found an easy solution, so I thought I should share it.
I just used a toString method:
date.toString() and then modify the String.
private static String getFormattedDate(DateTime date) {
String string = date.toString();
String result = StringUtils.substring(string, 0, string.length() - 5);
return result;
}

Related

Convert a timestamp to ISO format date string

I have a logic in python that I am converting into Java code.
The logic is I need to read from a timestamp attribute in JSON file and convert it into ISO date format.
Python query:
datetime.datetime.fromtimestamp(jsonMsg["time"]).isoformat(timespec='seconds')
Here is the code I wrote in Java
1627065646.444 is an example of the value I get from JSON script
long timestamp = (long) 1627065646.444 * 1000;
Timestamp time = new Timestamp(timestamp);
Date d = new Date(time.getTime());
DateFormat df = new SimpleDateFormat();
String dateToString = df.format(d);
LocalDateTime datetime = LocalDateTime.parse(dateToString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
ZoneOffset offset = ZoneOffset.UTC;
String formattedTimeStamp = datetime.atOffset(offset).toString();
When I run the code I get compile error "Text '7/23/21 11:40 AM' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0"
This exception occurs at LocalDateTime.parse(dateToString, DateTimeFormatter.ISO_LOCAL_DATE_TIME. Can someone please help me in understanding what I am doing wrong here.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
long timestamp = (long) (1627065646.444 * 1000);
Instant instant = Instant.ofEpochMilli(timestamp);
System.out.println(instant);
ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC);
LocalDateTime ldt = zdt.toLocalDateTime();
System.out.println(ldt);
// A custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u h:m:s a", Locale.ENGLISH);
String formatted = dtf.format(zdt);
System.out.println(formatted);
}
}
Output:
2021-07-23T18:40:46.444Z
2021-07-23T18:40:46.444
7/23/2021 6:40:46 PM
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API* from Trail: Date Time.
Apart from this, what else is wrong with your code?
You have done
long timestamp = (long) 1627065646.444 * 1000;
in which 1627065646.444 will be cast to long resulting in 1627065646 and thus the result of the multiplication will be 1627065646000, not 1627065646444 what you are expecting. You need to cast to long after performing the multiplication.
A valuable comment by Ole V.V.:
I’d use Math.round(1627065646.444 * 1000) to make sure that
floating-point inaccuracy is handled.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

parsing date from "06/25/2021 10:26:33.0" format to "2021-06-25T10:26:33.000-04:00" using java.time

I have to convert a date for the purpose of comparison using junit. I get a date from DB which is "06/25/2021 10:26:33.0" and I have to convert it to "2021-06-25T10:26:33.000-04:00" before I use it in the asserts.
I am trying not to use SimpleDate in java and use the the inbuilt java.time instead. However, I don't think I really understand everything in it. Here is the code snippet I have been playing around with. I have tried many things with this and I always get an error when the parse happens.
public String test() throws ParseException {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDateTime ldt = LocalDateTime.parse("06/25/2021 10:26:33.0", dtf);
//After the above line I have a date like: 2021-06-25T10:26:33.0
ZoneId zone = ZoneId.of("UTC-04:00");
ZonedDateTime zdt = ldt.atZone(zone);
Instant instant = zdt.toInstant();
return instant.toString();
}
In my mind, I think I have to first convert the date to an "acceptable" format because I feel like this format of the string - "yyyy-MM-dd HH:mm:ss.S" is not something that java.time can handle. it gives me an error such as "Text could not be parsed at index 19" and then probably in the second pass convert it to into this "2021-06-25T10:26:33.000-04:00".
I have consulted several articles regarding this on SO but haven't been able to find something that helps in converting custom formats. I am aware that "parse" and "format" are 2 API methods that have to be leveraged here but not sure how to go about it. Could someone pls nudge me in the right direction?
You can use LocalDateTime#atOffset to meet this requirement.
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String input = "06/25/2021 10:26:33.0";
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("M/d/u H:m:s.S", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(input, dtfInput);
OffsetDateTime odt = ldt.atOffset(ZoneOffset.of("-04:00"));
System.out.println(odt);
// Formatted output
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
String formatted = dtfOutput.format(odt);
System.out.println(formatted);
}
}
Output:
2021-06-25T10:26:33-04:00
2021-06-25T10:26:33.000-04:00
ONLINE DEMO
Notes:
If the fraction-of-second can be of zero to nine digits in the input, use the pattern, M/d/u H:m:s[.[SSSSSSSSS][SSSSSSSS][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]] where optional patterns have been specified using the square bracket.
OffsetDateTime#toString omits the second and the fraction-of-second part if they are zero. Use a DateTimeFormatter to get them in the formatted string.
Learn more about the modern Date-Time API* from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
convert it to into this "2021-06-25T10:26:33.000-04:00".
I think you'll need a custom formatter for that. Maybe the following:
public String test() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm:ss.S");
LocalDateTime ldt = LocalDateTime.parse("06/25/2021 10:26:33.0", dtf);
ZoneOffset zoff = ZoneOffset.ofHours(-4);
OffsetDateTime ldt2 = ldt.atOffset(zoff);
DateTimeFormatter tsf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
return tsf.format(ldt2);
}

Best way to compare given date with current date without time part in a given time zone

My requirement is to compare a given date in a particular format in a given timezone to the current date in the same time zone.
Also while comparing I have to ignore the timezone.
And the comparison result should be:
0 or 1 or -1
One way I have tried is
Set the required timezone
Get the current date using "new Date()" format it using "yyyy-MM-dd" and then parse it again to get the date object
Use the same formatter for supplied date string to be compared
Then compare both dates using compareTo which gives the desired result
public void compareDate(){
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
Date todayDate = dateFormatter.parse(dateFormatter.format(new Date()));
Date date = dateFormatter.parse("2021-02-28");
System.out.println(todayDate.compareTo(date));
}
But the above looks inefficient to me.
Other way could be to get both the dates like below and then compare?
public static Date getDateWithoutTimeUsingCalendar() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
Can someone please suggest a better alternative?
Just one thing, timezone and comparing without time has to be there.
The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.*
Demo using java.time API (modern date-time API):
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Tests
try {
System.out.println(compareWith("2021-02-28", "yyyy-MM-dd", "Asia/Calcutta"));
System.out.println(compareWith("2021/03/03", "yyyy/MM/dd", "Asia/Calcutta"));
} catch (DateTimeException e) {
System.out.println("Date string parsing error occured.");
}
}
static int compareWith(String strDate, String format, String timezone) throws DateTimeException {
ZoneId zoneId = ZoneId.of(timezone);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
ZonedDateTime today = ZonedDateTime.now(zoneId).with(LocalTime.MIDNIGHT);
ZonedDateTime date = LocalDate.parse(strDate, dtf).atStartOfDay(zoneId);
return today.compareTo(date);
}
}
Output:
1
-1
Learn more about the modern date-time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Conversion from UTC to IST returning same value in JAVA using Joda time library

I need to convert TimeZone in my project from UTC to IST and vice versa. For that purpose I am using Joda time jar in my project. But the problem occurs when I try to convert the string from UTC to IST, I am getting the same value instead of getting converted IST value. Kindly please mentor me in which part of code I am completely stuck up. My code is as follows:
public class JodaDemo {
public static final String DATE_PATTERN_SERVICE = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_PATTERN_SERVICE_NO_SECONDS = "yyyy-MM-dd HH:mm";
public static void main(String[] args) {
getDateFromUTCtoIST("2015-08-23 10:34:40");
}
private static void getDateFromUTCtoIST(String dateTime) {
DateTimeFormatter dtf = DateTimeFormat.forPattern(DATE_PATTERN_SERVICE);
DateTime jodatime = dtf.parseDateTime(dateTime);
DateTimeZone indianTimeZone = DateTimeZone.forID("Asia/Kolkata");
DateTime indianTime = jodatime.withZone(indianTimeZone);
System.out.println(indianTime);
}
OUTPUT:
2015-08-23T10:34:40.000+05:30
Expected output:
Converted TimeZone (+5:30 output) like in yyyy-MM-dd HH:mm:ss format
There are two problems here. Firstly, when you're parsing the value you're not specifying the time zone - so it's using your local time zone. Secondly, you're not using any formatter for the result - you're just calling DateTime.toString(), implicitly.
The simplest approach is actually to create two formatters for the same pattern, one in UTC and one in the relevant time zone - then you don't need to manually convert at all, as the formatter can do it for you:
import java.util.*;
import org.joda.time.*;
import org.joda.time.format.*;
public class Test {
public static final String DATE_PATTERN_SERVICE = "yyyy-MM-dd HH:mm:ss";
public static void main(String[] args) {
DateTimeFormatter utcFormatter = DateTimeFormat
.forPattern(DATE_PATTERN_SERVICE)
.withLocale(Locale.US)
.withZoneUTC();
DateTimeZone indianZone = DateTimeZone.forID("Asia/Kolkata");
DateTimeFormatter indianZoneFormatter = utcFormatter.withZone(indianZone);
String utcText = "2015-08-23 10:34:40";
DateTime parsed = utcFormatter.parseDateTime(utcText);
String indianText = indianZoneFormatter.print(parsed);
System.out.println(indianText); // 2015-08-23 16:04:40
}
}
java.time
Quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "2015-08-23 10:34:40";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(strDateTime, parser);
ZonedDateTime zdtUtc = ldt.atZone(ZoneId.of("Etc/UTC"));
ZonedDateTime zdtIndia = zdtUtc.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);
OffsetDateTime odt = zdtIndia.toOffsetDateTime();
System.out.println(odt);
}
}
Output:
2015-08-23T16:04:40+05:30[Asia/Kolkata]
2015-08-23T16:04:40+05:30
ONLINE DEMO
Some important notes:
If you are going to deal with JDBC, check this answer and this answer to learn how to use java.time API with JDBC.
For any reason, if you need to convert this object of OffsetDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(odt.toInstant());
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Custom String from ISO Compliant Date

I am getting a date string as 2014-01-11-T00:00:00Z
I want to convert this date to 20140111 i.e YYYYMMDD it should be a string.
Any standard method/function to achieve above?
java.time
Your date-time string, 2014-01-11-T00:00:00Z is a bit weird as I have never seen such a date-time string where there is a hyphen (-) before T. For this kind of string, the following pattern meets the parsing requirement:
yyyy-M-d-'T'H:m:sXXX
Also, with java.time API, I recommend you replace y with u as explained in this answer. For the output string, you do NOT need to define any pattern as there already exists an inbuilt DateTimeFormatter for this pattern: DateTimeFormatter.BASIC_ISO_DATE.
Demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("u-M-d-'T'H:m:sXXX", Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse("2014-01-11-T00:00:00Z", dtfInput);
System.out.println(odt);
String output = odt.toLocalDate().format(DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(output);
}
}
Output:
2014-01-11T00:00Z
20140111
Note:
Had your date-time string been ISO 8601 compliant, you would NOT have needed to use a DateTimeFormatter object explicitly for parsing i.e. you could have simply parsed it as
OffsetDateTime odt = OffsetDateTime.parse("2014-01-11T00:00:00Z");
The Z in the date-time stands for Zulu which specifies UTC time (that has a timezone offset of +00:00 hours) in ISO 8601 standard. Thus, this solution will also work for a date-time string like 2014-01-11-T00:00:00+02:00 which has a timezone offset of +02:00 hours.
In case, you need a java.util.Date object from this object of OffsetDateTime, you can do so as follows:
Date date = Date.from(odt.toInstant());
Learn more about the the modern date-time API* from Trail: Date Time.
Note that the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) are outdated and error-prone. It is recommended to stop using them completely and switch to java.time API. Just for the sake of completeness, I am providing you with a solution using the legacy API.
Using the legacy API:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String args[]) throws ParseException {
SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-M-d-'T'H:m:sXXX", Locale.ENGLISH);
SimpleDateFormat sdfOutput = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
sdfOutput.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));// Change it as required
Date date = sdfInput.parse("2014-01-11-T00:00:00Z");
String output = sdfOutput.format(date);
System.out.println(output);
}
}
Output:
20140111
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Take this
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormat {
public static void main(String[] args) throws ParseException {
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd-'T'HH:mm:ss'Z'");
Date inDate = inFormat.parse("2014-01-11-T00:00:00Z");
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMdd");
String output = outFormat.format(inDate);
System.out.println("Date: " + output);
}
}
Take a look at this thread for Date formatting in Java using Zoulou notation :
Converting ISO 8601-compliant String to java.util.Date
Then create a new SimpleDateFormat using the "yyyyMMdd" format string.
Here an improved version of given answer by #drkunibar:
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd-'T'HH:mm:ss'Z'");
inFormat.setTimeZone(TimeZone.getTimeZone("GMT")); // Z denotes UTC in ISO-8601
Date inDate = inFormat.parse("2014-01-11-T00:00:00Z");
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMdd");
outFormat.setTimeZone(TimeZone.getTimeZone("...")); // set your timezone explicitly!
String output = outFormat.format(inDate);
System.out.println("Date: " + output);
Note that the format YYYYMMDD is also ISO-8601-compliant (a so-called basic calendar date). The question you have to ask yourself is in which timezone you want to get your output. If in UTC you have to set "GMT", too. Without setting timezone it can happen that your output date differs from input UTC date by one day dependent where your default system timezone is (for example US is several hours behind UTC, in this case one calendar day before UTC midnight).
Update: This Answer is now obsolete. See the modern solution using java.time in the Answer by Avinash.
Joda-Time
This date-time work is much easier with the Joda-Time 2.3 library.
String input = "2014-01-11T00:00:00Z"; // In standard ISO 8601 format.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC ); // Parse string into date-time object.
DateTimeFormatter formatter = ISODateTimeFormat.basicDate(); // Factory to make a formatter.
String output = formatter.print( dateTime ); // Generate string from date-Time object.

Categories

Resources