I have to print the EST time in my Java application. I had set the time zone to EST using:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
But when the daylight savings is being followed in this timezone, my code does not print the correct time (it prints 1 hour less).
How to make the code work to read the correct time always, irrespective of whether the daylight savings are being observed or not?
PS: I tried setting the timezone to EDT, but it doesn't solve the problem.
PS: I tried setting the timezone to EDT, but it solve the problem
This is the problem to start with:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
The 3-letter abbreviations should be wholeheartedly avoided in favour of TZDB zone IDs. EST is Eastern Standard Time - and Standard time never observes DST; it's not really a full time zone name. It's the name used for part of a time zone. (Unfortunately I haven't come across a good term for this "half time zone" concept.)
You want a full time zone name. For example, America/New_York
is in the Eastern time zone:
TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);
System.out.println(format.format(new Date()));
Other answers are correct, especially the one by Jon Skeet, but outdated.
java.time
These old date-time classes have been supplanted by the java.time framework built into Java 8 and later.
If you simply want the current time in UTC, use the Instant
class.
Instant now = Instant.now();
EST
is not a time zone, as explained in the correct Answer by Jon Skeet. Such 3-4 letter codes are neither standardized nor unique, and further the confusion over Daylight Saving Time (DST). Use a proper time zone name in the "continent/region" format.
Perhaps you meant Eastern Standard Time in east coast of north America? Or Egypt Standard Time? Or European Standard Time?
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZoneId zoneId = ZoneId.of( "Africa/Cairo" );
ZoneId zoneId = ZoneId.of( "Europe/Lisbon" );
Use any such ZoneId
object to get the current moment adjusted to a particular time zone to produce a ZonedDateTime
object.
ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;
Adjust that ZonedDateTime into a different time zone by producing another ZonedDateTime object from the first. The java.time framework uses immutable objects rather than changing (mutating) existing objects.
ZonedDateTime zdtGuam = zdt.withZoneSameInstant( ZoneId.of( "Pacific/Guam" ) ) ;
https://i.stack.imgur.com/V7t6V.png
Instant
is not the same thing as a time in UTC. The latter can have leap-seconds, for example.
Instant
is perceived as a date and time-of-day then leap seconds become irrelevant. That is the whole point of leap seconds, to stop our clocks a moment to let our calendar sync with the earth’s generally slowing astronomical position. While it is true the internal representation of Instant
is short by the number of leap seconds that have so far been declared (one every couple of years or so), that distinction is moot when discussing date and time-of-day. This minutiae is discussed in the class doc for those that care. Upshot: practically speaking, Instant
is UTC.
Instant
doesn't stop the clock either - it has the same number of milliseconds that day but they were all slightly longer. Even if you don't want to think about it like that, that's still how it's been implemented, which is why e.g. you cannot format an Instant
using ISO_DATE_TIME
.
Instant.now().atZone(ZoneOffset.UTC)
Instead of entering "EST" for the timezone you can enter "EST5EDT" as such. As you noted, just "EDT" does not work. This will account for the daylight savings time issue. The code line looks like this:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));
As per this answer:
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
private static Long DateTimeNowTicks(){
long TICKS_AT_EPOCH = 621355968000000000L;
TimeZone timeZone = Calendar.getInstance().getTimeZone();
int offs = timeZone.getRawOffset();
if (timeZone.inDaylightTime(new Date()))
offs += 60 * 60 * 1000;
return (System.currentTimeMillis() + offs) * 10000 + TICKS_AT_EPOCH;
}
Date
, Calendar
, SimpleDateFormat
.
public static float calculateTimeZone(String deviceTimeZone) {
float ONE_HOUR_MILLIS = 60 * 60 * 1000;
// Current timezone and date
TimeZone timeZone = TimeZone.getTimeZone(deviceTimeZone);
Date nowDate = new Date();
float offsetFromUtc = timeZone.getOffset(nowDate.getTime()) / ONE_HOUR_MILLIS;
// Daylight Saving time
if (timeZone.useDaylightTime()) {
// DST is used
// I'm saving this is preferences for later use
// save the offset value to use it later
float dstOffset = timeZone.getDSTSavings() / ONE_HOUR_MILLIS;
// DstOffsetValue = dstOffset
// I'm saving this is preferences for later use
// save that now we are in DST mode
if (timeZone.inDaylightTime(nowDate)) {
Log.e(Utility.class.getName(), "in Daylight Time");
return -(ONE_HOUR_MILLIS * dstOffset);
} else {
Log.e(Utility.class.getName(), "not in Daylight Time");
return 0;
}
} else
return 0;
}
In java, DateFormatter by default uses DST,To avoid day Light saving (DST) you need to manually do a trick, first you have to get the DST offset i.e. for how many millisecond DST applied, for ex somewhere DST is also for 45 minutes and for some places it is for 30 min but in most cases DST is of 1 hour you have to use Timezone object and check with the date whether it is falling under DST or not and then you have to manually add offset of DST into it. for eg:
TimeZone tz = TimeZone.getTimeZone("EST");
boolean isDST = tz.inDaylightTime(yourDateObj);
if(isDST){
int sec= tz.getDSTSavings()/1000;// for no. of seconds
Calendar cal= Calendar.getInstance();
cal.setTime(yourDateObj);
cal.add(Calendar.Seconds,sec);
System.out.println(cal.getTime());// your Date with DST neglected
}
Implementing the TimeZone class to set the timezone to the Calendar takes care of the daylight savings.
java.util.TimeZone represents a time zone offset, and also figures out daylight savings.
sample code:
TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);
TimeZoneIDProvider
a custom Class? in that case you need to provide its implementation.
Success story sharing
DateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy").getDateTimeInstance()
? My example generates the warning "The static method getDateTimeInstance() from the type DateFormat should be accessed in a static way".DateFormat format = DateFormat.getDateTimeInstance()
. It's a static method, so it has nothing to do with an existing instance. It's really unclear what you're trying to do, but you should probably ask a new question.HH:mm:ss:ms MM/dd/yyyy
".SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy");
System.out.println(format.format(new Date()));
...replacing the last line of code from the answer to get the desired output. Thank you for the help.new Date()
does not rely on the system time zone. If you mean you'd useSimpleDateFormat
with the system time zone, then yes, callingsdf.format(new Date());
and then immediatelysdf.format(new Date());
a few milliseconds later can lead to string representations which appear to be an hour apart.