64

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.

TT.
  • 14,883
  • 6
  • 41
  • 77
Surya Chandra
  • 1,503
  • 5
  • 23
  • 41
  • 1
    Could you extend your example code, showing exactly what you are trying to do? – sebastian May 11 '12 at 05:39
  • There is nothing much im doing with it except that im printing the date. But when i see the hour in the output, its showing wrong(1 hour less) when daylight savings are being followed in EST. How to take care of daylight savings is my question – Surya Chandra May 11 '12 at 05:45
  • Please edit your question with that information. It might get missed in the comments, but probably not in your question. Also, please edit and clarify this statement `PS: I tried setting the timezone to EDT, but it solve the problem` – David May 11 '12 at 05:47
  • Daylight savings time advances clocks by an hour at the start of the Daylight Saving period, and retards clocks by the same amount at the end of it. The behaviour you see is, in my opinion, perfectly normal. Please go through http://en.wikipedia.org/wiki/Daylight_saving_time – Everyone May 11 '12 at 05:52
  • 4
    "when daylight savings are being followed in EST" - you mean "when daylight savings are being followed in Eastern time". EST is Eastern *standard* time - where *standard* is the opposite of *daylight*. – Jon Skeet May 11 '12 at 05:54
  • @JonSkeet: I am from the east side of globe. So im not much aware of Daylight savings. Thanks for the info. I got the concept now. – Surya Chandra May 11 '12 at 06:00
  • Similar: http://stackoverflow.com/questions/9863625/difference-between-est-and-america-new-york-time-zones – Matt Johnson-Pint May 03 '17 at 20:31

8 Answers8

114

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()));
Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • Thanks @Jon, is it possible to then alter the format with something like `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*". – Ian Campbell Oct 11 '13 at 13:36
  • 1
    @IanCampbell: It's not at all clear what you'd expect that to do - it's a static method, so you'd normally just use `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. – Jon Skeet Oct 11 '13 at 14:39
  • Ok thanks @Jon, I'm just wondering how to change the output format to "`HH:mm:ss:ms MM/dd/yyyy`". – Ian Campbell Oct 11 '13 at 16:11
  • @IanCampbell: What do you mean by *change* the output format? Why not just *create* a new `SimpleDateFormat` with that format? Or are you talking about changing the default date/time format? You're not being very clear. – Jon Skeet Oct 11 '13 at 20:17
  • 1
    Sorry for the confusion @Jon, I just did what you suggested: `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. – Ian Campbell Oct 11 '13 at 21:32
  • @JonSkeet What if I rely on system timezone and just use the date as: new Date(); and refer to it. When daylight saving happens would it lead to one hour difference? And what is the way to avoid it? – maximus Mar 14 '16 at 11:59
  • 1
    @maximus: I'm not sure what you mean by that. The result of `new Date()` does not rely on the system time zone. If you mean you'd use `SimpleDateFormat` with the system time zone, then yes, calling `sdf.format(new Date());` and then immediately `sdf.format(new Date());` a few milliseconds later can lead to string representations which appear to be an hour apart. – Jon Skeet Mar 14 '16 at 12:04
  • @JonSkeet got it, my mistake. Thank you! – maximus Mar 14 '16 at 12:13
  • @JonSkeet how can i get zone id from this data `(UTC-08:00) Pacific Time (US & Canada)` through server side. ex the result is like `America/Dawson`. – Salman S Aug 27 '18 at 10:37
  • @SalmanS I suggest that as a new question, with more context about what's producing the value. – Jon Skeet Aug 27 '18 at 14:03
22

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" ) ) ;

Table of date-time types in Java, both modern and legacy.

Basil Bourque
  • 218,480
  • 72
  • 657
  • 915
  • An `Instant` is not the same thing as a time in UTC. The latter can have leap-seconds, for example. – OrangeDog Apr 13 '17 at 10:17
  • @OrangeDog When an `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. – Basil Bourque Apr 13 '17 at 15:44
  • Uh, no. A UTC leap second does not "stop the clock", it adds another second (2016-12-24T23:23:60Z being the most recent). The Java time represented by `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`. – OrangeDog Apr 13 '17 at 15:47
  • Fortunately the conversion is easy - `Instant.now().atZone(ZoneOffset.UTC)` – OrangeDog Apr 13 '17 at 15:52
  • 2
    Adding a second does indeed stop the clock in terms of the date and time of day. We take an extra moment before moving on to the next date in the calendar. And so a leap second is absorbed by our calendar. As I said, that is the whole point of leap seconds: Slow our clocks to slow our calendar tracking. While your point about ignoring leap seconds is technically correct in terms of the internal representation of the java.time classes, in practical terms your point is irrelevant, pedantic, and needlessly confusing to the many programmers struggling to learn how to represent dates and times. – Basil Bourque Apr 13 '17 at 15:59
  • These misconceptions and imprecisions are exactly why people have trouble correctly dealing with time in applications, and exactly why Java is trying to make it easy to do it right. If you want an instant in the continuum of time use `Instant`. If you want a date and time in the UTC timezone, use `ZonedDateTime`. – OrangeDog Apr 13 '17 at 16:04
  • @OrangeDog Incorrect, `ZonedDateTime` is exactly what you do *not* need for a UTC value. It's very title with the word ‘zoned’, as well as its class doc and the existence of `OffsetDateTime` and `Instant` all point to that fact. A `ZonedDateTime` is for assigning a time zone to a UTC value. While you can indeed assign UTC as that time zone, that is not at all the purpose of that class. – Basil Bourque Apr 13 '17 at 16:16
  • Fine, use `OffsetDateTime` then. But if you use `Instant` there are a large number of cases where it will throw and a small number of cases where it will do the wrong thing. – OrangeDog Apr 13 '17 at 16:17
  • I have just discovered that Java still doesn't handle leap seconds as they are defined. `OffsetDateTime.parse("2016-12-31T23:59:59Z").plusSeconds(1).toString()` gives 2017-01-01T00:00Z. So if you want to avoid the occasional wrong thing, you'll need to find another library. – OrangeDog Apr 13 '17 at 16:37
  • @OrangeDog You are not understanding the purpose of the Leap Second: to sync our time-of-day (rotation of the earth on its axis) with our calendar (the orbit of the earth around the sun). For nearly any practical purpose, we need not actually count the extra 61st second of a Leap Second. Ignoring the leap lets us absorb it into our calendar. For example, Google chooses use a [*Leap Smear*](https://developers.google.com/time/smear) to move the clock on many of their computers a fraction of a second over hours to imperceptibly stop their clocks for the delay. – Basil Bourque Oct 19 '18 at 20:00
  • @OrangeDog If you *really* need to track the Leap Second, I have good news for you: the [`UtcInstant`](https://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/scale/UtcInstant.html) and [`UtcRules`](https://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/scale/UtcRules.html) classes found in the [*ThreeTen-Extra*](https://www.threeten.org/threeten-extra/) project for *java.time*. The first is an instantaneous point on the time-line measured in the UTC time-scale with leap seconds. The second provides rules defining the UTC time-scale, notably when leap seconds occur. – Basil Bourque Oct 19 '18 at 20:02
  • that’s exactly what Java Instant does, which is exactly why it’s not the same thing as UTC. – OrangeDog Oct 19 '18 at 20:02
4

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"));
Vadim Kotov
  • 7,103
  • 8
  • 44
  • 57
Brian N
  • 41
  • 3
1

As per this answer:

TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
Community
  • 1
  • 1
Daniil Shevelev
  • 10,633
  • 11
  • 43
  • 63
1
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;
}
fartwhif
  • 192
  • 1
  • 10
  • These terrible old date-time classes were supplanted years ago by the *java.time* classes with the adoption of JSR 310. These legacy classes should no longer be used at all. – Basil Bourque Oct 15 '18 at 16:40
  • Sometimes a developer is forced into a terrible old legacy situation, but good to know, thank you. – fartwhif Oct 24 '18 at 15:01
  • For Java 6 & Java 7, most of the *java.time* functionality is back-ported with nearly identical API in the [*ThreeTen-Backport*](https://www.threeten.org/threetenbp/) project. So there really is no need to ever use the awful legacy date-time classes such as `Date`, `Calendar`, `SimpleDateFormat`. – Basil Bourque Oct 24 '18 at 15:50
  • Sometimes a developer is forced into a terrible old legacy situation without backport, and so has no choice but to use the awful legacy date-time classes, but good to know, thank you! – fartwhif Oct 25 '18 at 17:06
0
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;
}
Jayesh Kalkani
  • 191
  • 3
  • 8
-1

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
  }
Sunil Garg
  • 146
  • 2
  • 6
  • This was actually helpful - I needed to "un-daylight savings" a date and I was unaware of the "inDayLightTime" function. Thanks! – Dave May 22 '20 at 13:26
-3

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);
Radnerus
  • 20
  • 2
  • 3
    is `TimeZoneIDProvider` a custom Class? in that case you need to provide its implementation. – asgs Sep 06 '14 at 17:53