Java 8 has a completely new API for date and time. One of the most useful classes in this API is LocalDateTime, for holding a timezone-independent date-with-time value.
There are probably millions of lines of code using the legacy class java.util.Date for this purpose. As such, when interfacing old and new code there will be a need for converting between the two. As there seems to be no direct methods for accomplishing this, how can it be done?
Short answer:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Explanation:
(based on this question about LocalDate)
Despite its name, java.util.Date represents an instant on the time-line, not a "date". The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
The equivalent class to java.util.Date in JSR-310 is Instant, thus there are convenient methods to provide the conversion to and fro:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
A java.util.Date instance has no concept of time-zone. This might seem strange if you call toString() on a java.util.Date, because the toString is relative to a time-zone. However that method actually uses Java's default time-zone on the fly to provide the string. The time-zone is not part of the actual state of java.util.Date.
An Instant also does not contain any information about the time-zone. Thus, to convert from an Instant to a local date-time it is necessary to specify a time-zone. This might be the default zone - ZoneId.systemDefault() - or it might be a time-zone that your application controls, such as a time-zone from user preferences. LocalDateTime has a convenient factory method that takes both the instant and time-zone:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
In reverse, the LocalDateTime the time-zone is specified by calling the atZone(ZoneId) method. The ZonedDateTime can then be converted directly to an Instant:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Note that the conversion from LocalDateTime to ZonedDateTime has the potential to introduce unexpected behaviour. This is because not every local date-time exists due to Daylight Saving Time. In autumn/fall, there is an overlap in the local time-line where the same local date-time occurs twice. In spring, there is a gap, where an hour disappears. See the Javadoc of atZone(ZoneId) for more the definition of what the conversion will do.
Summary, if you round-trip a java.util.Date to a LocalDateTime and back to a java.util.Date you may end up with a different instant due to Daylight Saving Time.
Additional info: There is another difference that will affect very old dates. java.util.Date uses a calendar that changes at October 15, 1582, with dates before that using the Julian calendar instead of the Gregorian one. By contrast, java.time.* uses the ISO calendar system (equivalent to the Gregorian) for all time. In most use cases, the ISO calendar system is what you want, but you may see odd effects when comparing dates before year 1582.
Here is what I came up with ( and like all Date Time conundrums it is probably going to be disproved based on some weird timezone-leapyear-daylight adjustment :D )
Round-tripping: Date <<->> LocalDateTime
Given: Date date = [some date]
(1) LocalDateTime << Instant<< Date
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
(2) Date << Instant << LocalDateTime
Instant instant = ldt.toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
Example:
Given:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
(1) LocalDateTime << Instant<< Date:
Create Instant from Date:
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);
Create Date from Instant (not necessary,but for illustration):
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
Create LocalDateTime from Instant
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);
(2) Date << Instant << LocalDateTime
Create Instant from LocalDateTime:
instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);
Create Date from Instant:
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
The output is:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Instant from Date:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
LocalDateTime from Instant:
2013-11-01T14:13:04.574
Instant from LocalDateTime:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Much more convenient way if you are sure you need a default timezone :
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
The fastest way for LocalDateTime -> Date is:
Date.from(ldt.toInstant(ZoneOffset.UTC))
Everything is here : http://blog.progs.be/542/date-to-java-time
The answer with "round-tripping" is not exact : when you do
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
if your system timezone is not UTC/GMT, you change the time !
the following seems to work when converting from new API LocalDateTime into java.util.date:
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
the reverse conversion can be (hopefully) achieved similar way...
hope it helps...
If you are on android and using threetenbp you can use DateTimeUtils instead.
ex:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
you can't use Date.from since it's only supported on api 26+
I'm not sure if this is the simplest or best way, or if there are any pitfalls, but it works:
static public LocalDateTime toLdt(Date date) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
ZonedDateTime zdt = cal.toZonedDateTime();
return zdt.toLocalDateTime();
}
static public Date fromLdt(LocalDateTime ldt) {
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
GregorianCalendar cal = GregorianCalendar.from(zdt);
return cal.getTime();
}
I think below approach will solve the conversion without taking time-zone into consideration.
Please comment if it has any pitfalls.
LocalDateTime datetime //input
public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output
Related
My current date:
Date utc: 2018-06-06T16:30:00Z (ISO 8601 in UTC)
OR
Date iso: 2018-06-06T11:30:00-05:00 (ISO 8601)
OR
Date epoch: 1528302600000 (Epoch/Unix Timestamp)
I wish to convert the above DateTime to some another time zone areas (like GMT+5:30). And I'm not sure which time format I'll receive from above three. So can I've a generic method which can convert above to some another time zone returning java.util.Date in Java 8?
I did Something like this, But it didn't worked out
public Date convertDateToLocalTZ(Date iso8601, ZoneId toZoneId) {
Date dateTime = null;
if (iso8601 != null && toZoneId != null) {
Instant instant = iso8601.toInstant();
LocalDateTime localDateTime = instant.atZone(toZoneId).toLocalDateTime();
dateTime = Date.from(localDateTime.atZone(toZoneId).toInstant());
return dateTime;
}
return dateTime;
}
Since question is tagged java-8 use java.time API.
UPDATE: For version 4 of question where 2018-06-06T11:30:00-05:00 was added.
To parse 1528302600000, you parse it into a long, then use Instant.ofEpochMilli().
To parse a format like 2018-06-06T11:30:00-05:00, you can using OffsetDateTime or ZonedDateTime. Both can also parse 2018-06-06T16:30:00Z.
To change the time zone specifically to a particular offset like GMT+5:30, use ZoneOffset, e.g. ZoneOffset.of("+05:30"), or ZoneId, e.g. ZoneId.of("GMT+05:30").
Note 1: GMT+5:30 is not valid.
Note 2: To change to the time zone of a region, honoring Daylight Savings Time, use e.g. ZoneId.of("Asia/Kolkata").
To parse all 3 input formats, and even support the extended format like 2018-06-06T11:30-05:00[America/Chicago], use ZonedDateTime, with special handling for the epoch number.
public static ZonedDateTime parseToZone(String text, ZoneId zone) {
if (text.indexOf('-') == -1)
return Instant.ofEpochMilli(Long.parseLong(text)).atZone(zone);
return ZonedDateTime.parse(text).withZoneSameInstant(zone);
}
The caller can then decide if only the offset, not the full time zone, should be used, by converting it to OffsetDateTime using toOffsetDateTime().
Test
ZoneId india = ZoneId.of("Asia/Kolkata");
System.out.println(parseToZone("2018-06-06T16:30:00Z", india));
System.out.println(parseToZone("2018-06-06T11:30:00-05:00", india));
System.out.println(parseToZone("1528302600000", india));
System.out.println(parseToZone("1528302600000", india).toOffsetDateTime());
Output
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30
Original Answer
Use the parse() method with 2018-06-06T16:30:00Z.
Use the ofEpochMilli() method with 1528302600000.
Then use atZone() to convert to your desired time zone.
Demo
Instant instant1 = Instant.parse("2018-06-06T16:30:00Z");
Instant instant2 = Instant.ofEpochMilli(1528302600000L);
ZoneId india = ZoneId.of("Asia/Kolkata");
ZonedDateTime date1 = instant1.atZone(india);
ZonedDateTime date2 = instant2.atZone(india);
System.out.println(instant1);
System.out.println(instant2);
System.out.println(date1);
System.out.println(date2);
Output
2018-06-06T16:30:00Z
2018-06-06T16:30:00Z
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
To print the result in human format, use a DateTimeFormatter.
DateTimeFormatter indiaFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.forLanguageTag("en-IN"));
DateTimeFormatter hindiFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.forLanguageTag("hi-IN"));
System.out.println(date1.format(indiaFormatter));
System.out.println(date1.format(hindiFormatter));
Output
6 June 2018 at 10:00:00 PM IST
6 जून 2018 को 10:00:00 अपराह्न IST
In Java 8+, you should use the new java.time API.
Your initial UTC time must be modelized as an Instant. Use DateTimeFormatter to parse from a string like 2018-06-07T22:21:00Z if needed, or get the current Instant with Instant.now.
Then you can use Instant.atZone or Instant.withOffset to convert to a ZonedDateTime resp. OffsetDateTime with the desired time shift. ZonedDateTime helps you get the date/time at a given region/country, while OffsetDateTime makes a purely numerical time shift independent from location and daylight saving time.
I have a requirement where i have to store different date and time with time zones.
I have used ZonedDateTime of java 8 .
ZoneId zoneId = ZoneId.of("US/Eastern");
ZonedDateTime zt = ZonedDateTime.now(zoneId);
System.out.println(zt.toString());
My problem is I want to store this in java.util.Date format.
I used DateTimeFormatter
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
dtf.format(zt);
Until here it works fine this gives me the required date in string format now when i try to convert this to java.util.Date using simple date format
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
System.out.println(sdf.parse(dtf.format(zt)));
I get output as Sat Mar 12 00:44:10 IST 2016 but i want output as 2016-03-11T14:14:10-05:00 in java.util.Date type. Can somebody suggest where am i going wrong?
You are using a wrong way this is the corrected code
sdf.format(sdf.parse(val)) this the right way.
ZoneId zoneId = ZoneId.of("US/Eastern");
ZonedDateTime zt = ZonedDateTime.now(zoneId);
System.out.println(zt.toString());
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
String val = dtf.format(zt);
System.out.println(val);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
//String dateStr = zt.format(sdf);
System.out.println(sdf.format(sdf.parse(val)));
ZonedDateTime > Instant > Date
Best to avoid the old date-time classes including java.util.Date. But if you must, you can convert. Call the new from method on the old java.util.Date class.
For that you need an Instant a moment on the timeline in UTC.
Instant instant = myZonedDateTime.toInstant();
java.util.Date juDate = java.util.Date.from( instant );
To go the other direction:
Instant instant = juDate.toInstant();
I have a datetime as 2011-01-11 01:51:10 and timezone as America/Los_Angeles
I want to get a localised date time for this value. This is what I do
val formatter1: DateTimeFormatter = DateTimeFormatter.ofPattern("y-M-d H:m:s");
val m1: LocalDateTime = LocalDateTime.parse("2011-01-11 01:51:10", formatter1);
println("DateTime: " + m1.atZone(ZoneId.of("America/Los_Angeles")))
The value that I get is
DateTime: 2011-01-11T01:51:10-08:00[America/Los_Angeles]
How do I convert it into localized datetime with -08:00 offset applied to it and no [America/Los_Angeles]?
You first have to specify which timezone that the time which you have parsed is in. Then specify an other one to convert into.
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("y-M-d H:m:s");
LocalDateTime m1 = LocalDateTime.parse("2011-01-11 01:51:10", formatter1);
ZonedDateTime z1 = m1.atZone(ZoneId.of("UTC"));
ZonedDateTime z2 = z1.withZoneSameInstant(ZoneId.of("America/Los_Angeles"));
System.out.println(z2.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
Looks like you are using java.time API which has a ZonedDateTime. You should probably use it instead of LocalDateTime, since that LocalDateTime does not have a time zone. From the docs:
A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03.
This class does not store or represent a time or time-zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
And then, ZonedDateTime docs states that:
A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.
This class handles conversion from the local time-line of LocalDateTime to the instant time-line of Instant. The difference between the two time-lines is the offset from UTC/Greenwich, represented by a ZoneOffset.
Using a ZonedDateTime, your code would be like:
import java.time._
import java.time.format._
val zoneId = ZoneId.of("America/Los_Angeles")
val formatter = DateTimeFormatter.ofPattern("y-M-d H:m:s").withZone(zoneId)
val zdt = ZonedDateTime.parse("2011-01-11 01:51:10", formatter)
The result you will see at the console will be:
zdt: java.time.ZonedDateTime = 2011-01-11T01:51:10-08:00[America/Los_Angeles]
That happens because you are using the default toString method of ZonedDateTime and looks like the DateTimeFormatter.ISO_OFFSET_DATE_TIME is exactly what you want. So your code should be:
import java.time._
import java.time.format._
val zoneId = ZoneId.of("America/Los_Angeles")
val formatter = DateTimeFormatter.ofPattern("y-M-d H:m:s").withZone(zoneId)
val zdt = ZonedDateTime.parse("2011-01-11 01:51:10", formatter)
val formatted: String = zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
Please look into my complete answer for this. Answer
String dateTime = "MM/dd/yyyy HH:mm:ss";
String date = "09/17/2017 20:53:31";
Integer gmtPSTOffset = -8;
ZoneOffset offset = ZoneOffset.ofHours(gmtPSTOffset);
// String to LocalDateTime
LocalDateTime ldt = LocalDateTime.parse(date, DateTimeFormatter.ofPattern(dateTime));
// Set the generated LocalDateTime's TimeZone. In this case I set it to UTC
ZonedDateTime ldtUTC = ldt.atZone(ZoneOffset.UTC);
System.out.println("UTC time with Timezone : "+ldtUTC);
// Convert above UTC to PST. You can pass ZoneOffset or ZoneId for 2nd parameter
LocalDateTime ldtPST = LocalDateTime.ofInstant(ldtUTC.toInstant(), offset);
System.out.println("PST time without offset : "+ldtPST);
// If you want UTC time with timezone
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdtPST = ldtUTC.toLocalDateTime().atZone(zoneId);
System.out.println("PST time with Offset and TimeZone : "+zdtPST);
probably what you want is to get UTC time and then apply timezone offset to it.
It's quite easy to do with Joda time. For example:
DateTime.now().minus(timezoneOffset)
where timezoneOffset is int that will represent time shift at your location. Correct me if I'm wrong.
Can anybody tell me how to convert date to epoch in java.
e.g. 2011-05-01 13:12:20 IST or 2011-05-01 14:11:10 PST to epoch.
I am able to convert using 2011-05-01 13:12:20 format but when I use timezone alongwith it I am not getting correct result.
Construct a SimpleDateFormat with a string pattern that matches the date format you have. The "Date and Time" section and the "Examples" section should give you more than enough help on how to construct your date format string
Then simply do the following to get your date (with the appropriate date format string).
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date date = sdf.parse("15/01/2012");
java.time
Using the java.time classes.
String input = "2011-05-01 13:12:20".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );
ZonedDateTime zdt = ldt.atZone( ZoneId.of( "Asia/Kolkata" ) );
If by “epoch”, you mean a count of whole seconds or milliseconds from the epoch reference date of first moment of 1970 in UTC (often referred to as Unix Time), then interrogate the ZonedDateTime object via an extracted Instant object.
long wholeSecondsSinceEpoch = zdt.toInstant().getEpochSecond();
long millisecondsSinceEpoch = zdt.toInstant().toEpochMilli();
I managed to convert a valid date string in a different timezone to UTC as follows.
String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
DateTimeFormatter DATETIME_FORMATTER = DateTimeFormat.forPattern(DATE_FORMAT);
DateTimeZone dateTimeZone = DateTimeZone.forID("-03:00");
//date is 2000-01-01 00:00:00 -03:00
DateTime date = DATETIME_FORMATTER.withZone(dateTimeZone).parseDateTime("2000-01-01 00:00:00"));
System.out.println("Current date is: " + date.toString());
//now convert to UTC
DateTime convertedDate = date.toDateTime(DateTimeZone.UTC);
System.out.println("Converted date: " + date.toString());
The result is
Current date is: 2000-01-01T00:00:00.000-03:00
Converted date: 2000-01-01T03:00:00.000Z
Is there a shorter/better way of doing this? I want the final date to be a Joda-Time DateTime object.
You can convert the time zone of any DateTime using withZone(). If the input string doesn't specify the time-zone offset then you have to add it as you are doing, so your code is fairly optimal.
One improvement over your example code might be replacing the hard-coded "-3:00" offset with a time zone name. That would allow Joda-Time to make adjustments for any possible Daylight Saving Time (DST). See doc for DateTimeZone.forID().
This:
DateTimeZone dateTimeZone = DateTimeZone.forID("America/Sao_Paulo");
instead of this:
DateTimeZone dateTimeZone = DateTimeZone.forID("-03:00");
Time Zone list (possibly outdated, read note):
http://joda-time.sourceforge.net/timezones.html