How does Java's date work?
Hi I have a following code below:
public Date convertFromGMTToLocal(Date date) {
return new Date(date.getTimezoneOffset() + newOffset*60*1000);
}
public Date convertFromLocalToGMT(Date date) {
return new Date(date.getTime() - date.getTimezoneOffset()*60*1000);
}
convertFromLocalToGMT is supposed to strip off timezone information and convertFromGMTToLocal is supposed to put the timezone information back. I understand java.util.Date is representing the time in epoch and always in GMT 开发者_运维问答however when displaying the date it is defaulted to JVM's default timezone.
Explanation I got was that if your timezone is CST and it is 10:00AM CST you are changing timezone to GMT with convertFromLocalToGMT so you're essentially adding the offset to get GMT so you get 4:00AM CST (offset is -6) and using convertFromGMTToLocal will convert this Date object back to 10:00AM regardless of your timezones (the most confusing part how?). How does above work? I am confused...
Thanks.
You should pretty much never add an offset to a Date
to create another Date
- you'd only ever do that if you received broken data to start with.
You should not use this code. It is bad code which tries to treat java.util.Date
in a way it was not designed for. If you want to represent a date in a particular time zone, either use Calendar
(urgh) or the far better Joda Time API.
In particular, the code you've got will not work around time zone transitions - because the offset at date.getTimeZoneOffset()
still considers date
to be UTC (because that's what it's defined as) even you're treating it as a local date/time.
Ignore the value that's displayed by Date.toString()
- avoid using that method. Either display using SimpleDateFormat
with appropriate settings for the time zone you're interested in, or (better, again) use Joda's DateTimeFormat
class.
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.
You can solve it using the following functions in java.time
, the modern Date-Time API :
LocalDateTime#atZone(ZoneId)
ZonedDateTime#withZoneSameInstant(ZoneId)
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/*
* Change the JVM's ZoneId, ZoneId.systemDefault() to the required ZoneId e.g. ZoneId.of("America/New_York")
*/
public class Main {
public static void main(String[] args) {
// Test
ZoneId zoneId = ZoneId.of("Etc/UTC");
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.of(2021, 5, 10), LocalTime.of(15, 20), zoneId);
System.out.println(zdt + " is " + convertFromZdtToLdt(zdt) + " at " + ZoneId.systemDefault().getId());
LocalDateTime ldt = LocalDateTime.of(LocalDate.of(2021, 5, 10), LocalTime.of(15, 20));
System.out
.println(ldt + " at " + ZoneId.systemDefault().getId() + " is " + convertFromLdtZdtToZdt(ldt, zoneId));
}
public static LocalDateTime convertFromZdtToLdt(ZonedDateTime zdt) {
return zdt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
}
public static ZonedDateTime convertFromLdtZdtToZdt(LocalDateTime ldt, ZoneId targetZoneId) {
return ldt.atZone(ZoneId.systemDefault()).withZoneSameInstant(targetZoneId);
}
}
Output on my system in Europe/London timezone:
2021-05-10T15:20Z[Etc/UTC] is 2021-05-10T16:20 at Europe/London
2021-05-10T15:20 at Europe/London is 2021-05-10T14:20Z[Etc/UTC]
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).
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.
As you said, the Date object doesn't care about timezone. It stores an instant in time. The timezone is only meaningful when you want to display a date. Use a DateFormat
with the specific timezone you want to use to display a date (using setTimeZone)
精彩评论