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.
Related
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);
}
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;
}
How do i convert ZonedDateTime to java.util.Date without changing the timezone.
In my below method when i call Date.from(datetime.toInstant()) it convert it to local time zone in my case SGT.
public static void printDate(ZonedDateTime datetime) {
System.out.println("---> " + datetime.format(DateTimeFormatter.ofPattern(API_TIME_STAMP_PATTERN)));
System.out.println(Date.from(datetime.toInstant()));
System.out.println("\n");
}
Output
---> 2019-03-13_08:46:26.593
Wed Mar 13 16:46:26 SGT 2019
You can add offset millis by yourself. See the example using java.util.Date:
long offsetMillis = ZoneOffset.from(dateTime).getTotalSeconds() * 1000;
long isoMillis = dateTime.toInstant().toEpochMilli();
Date date = new Date(isoMillis + offsetMillis);
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*. However, for any reason, if you want to change java.time.ZonedDateTime to java.util.Date, I recommend you avoid any kind of manual calculations when you already have an inbuilt API to meet the requirement.
All you need to do is to add the offset to the input datetime which you can do by using ZonedDateTime#plusSeconds as shown below:
datetime = datetime.plusSeconds(datetime.getOffset().getTotalSeconds());
Date date = Date.from(datetime.toInstant());
Demo:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
// Test
printDate(ZonedDateTime.now(ZoneId.of("Asia/Singapore")));
}
public static void printDate(ZonedDateTime datetime) {
datetime = datetime.plusSeconds(datetime.getOffset().getTotalSeconds());
Date date = Date.from(datetime.toInstant());
// Showing date-time in Singapore timezone
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Singapore"));
System.out.println(sdf.format(date));
}
}
Output:
2021-10-03T05:11:57
ONLINE DEMO
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.
I would do as ETO states on his answer with the exception of using TimeUnit for getting the seconds converted into milliseconds:
long offsetMillis = TimeUnit.SECONDS.toMillis(ZoneOffset.from(dateTime).getTotalSeconds());
long isoMillis = dateTime.toInstant().toEpochMilli();
Date date = new Date(isoMillis + offsetMillis);
or the other option would be:
var localDate = LocalDateTime.now();
final long offSetHours = ChronoUnit.HOURS.between(localDate.atZone(ZoneId.of("YOUR_TIME_ZONE_ID")),
localDate.atZone(ZoneId.of("UTC")));
return Date.from(Instant.parse(dateAsStringISO8601).plus(offSetHours, ChronoUnit.HOURS));
Stick to ZonedDateTime
To preserve the time zone simply preserve your ZonedDateTime. It can be formatted directly to the output your require. Don’t involve the outdated and poorly designed Date class.
private static final String API_TIME_STAMP_PATTERN = "yyyy-MM-dd_HH:mm:ss.SSS";
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz y", Locale.ROOT);
public static void printDate(ZonedDateTime datetime) {
System.out.println("---> " + datetime.format(DateTimeFormatter.ofPattern(API_TIME_STAMP_PATTERN)));
System.out.println(datetime.format(FORMATTER));
System.out.println("\n");
}
Try it out:
ZonedDateTime zdt = ZonedDateTime.of(
2019, 3, 13, 8, 46, 26, 593_000_000, ZoneId.of("Etc/UTC"));
printDate(zdt);
Output:
---> 2019-03-13_08:46:26.593
Wed Mar 13 08:46:26 UTC 2019
Your conversion is not changing the time zone
A Date falsely pretends to have a time zone. It hasn’t got any. So there is no change of time zone going on. toInstant() discards the time zone because an Instant hasn’t got a time zone either. Date.from() performs the conversion withut any regard to time zone. System.out.println() implicitly calls Date.toString(). The toString() method uses the JVM’s default time zone for rendering the string. It’s pretty confusing alright.
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.
there are two string
String date = "9/13/2012";
String time = "5:48pm";
the time is GMT+0, I wanna change it to GMT+8,what is the simplest way to change a time to particular timezone
Parse it using a SimpleDateFormat set to the UTC time zone
Format the parsed Date value using a SimpleDateFormat set to the time zone you're interested in. (It's likely to be something other than just "UTC+8" - you should find out which TZDB time zone ID you really want.
For example:
SimpleDateFormat inputFormat = new SimpleDateFormat("MM/dd/yyyy h:mma", Locale.US);
inputFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC");
Date date = inputFormat.parse(date + " " + time);
// Or whatever format you want...
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
outputFormat.setTimeZone(targetTimeZone);
String outputText = outputFormat.format(date);
(If you can use Joda Time instead, that'd be great - but I understand that it's pretty big for an Android app.)
The Joda-Time library provides a good set of objects for working with dates/times in multiple time zones. http://joda-time.sourceforge.net/
Something like this for example:
String date = "9/13/2012";
String time = "5:48pm";
String[] dateParts = date.split("/");
Integer month = Integer.parseInt(dateParts[0]);
Integer day = Integer.parseInt(dateParts[1]);
Integer year = Integer.parseInt(dateParts[2]);
String[] timeParts = time.split(":");
Integer hour = Integer.parseInt(timeParts[0]);
Integer minutes = Integer.parseInt(timeParts[1].substring(0,timeParts[1].lastIndexOf("p")));
DateTime dateTime = new DateTime(year, month, day, hour, minutes, DateTimeZone.forID("Etc/GMT"));
dateTime.withZone(DateTimeZone.forID("Etc/GMT+8"));
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*.
Also, 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.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String date = "9/13/2012";
String time = "5:48pm";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u h:ma", Locale.UK);
LocalDateTime ldtSource = LocalDateTime.parse(date + " " + time, dtf);
OffsetDateTime odtSource = ldtSource.atOffset(ZoneOffset.UTC);
OffsetDateTime odtTarget = odtSource.withOffsetSameInstant(ZoneOffset.of("+08:00"));
System.out.println(odtTarget);
// In a custom format
System.out.println(odtTarget.format(dtf));
}
}
Output:
2012-09-14T01:48+08:00
9/14/2012 1:48am
ONLINE DEMO
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.