Calendar Returns Date in Wrong Time Zone

Calendar returns date in wrong time zone

because Date object doesn't have timezone as part of its state, You need SimpleDateFormat to format and print the date in your required timezone

Why is Calendar returning the wrong hour with the correct time-zone?

1) Set the TimeZone in SimpleDateFormat

2) Either use UTC, or a "real" Time Zone like ("Austria/Vienna");

(Country name, and biggest city in TimeZone look it up to be sure)

EST (=UTC-5) is not a time zone very suitable for computational purpose, because it is the time without daylight saving.

One more example from central europe:

In Winter we use MEZ (CET), in Summer (Daylight savings) we use (MESZ = CEST).

But you want that your computer caluclates that for you, so don't use that:

TimeZones are geo poilitical, therfore the name of the country is needed.

Each country can decide to change its time zone when they want (e.g russia some time ago, and spain is discussing now.)

Calendar.getInstance().getTime() returning date in GMT instead of Default TimeZone

The second output in your question is the correct and expected behaviour on a JVM running Irish time (Europe/Dublin). On September 12, 2017 Ireland is on summer time (DST). While it is not clearly documented, Date.toString() (which you invoke implicitly when printing the Date you get from c.getTime()) prints the date and time in the JVM’s time zone, which in September is rendered as IST for Irish Summer Time.

When you set the date on the Calendar object also using Irish time, the hour of day is preserved; in your case you get Jan 01 2007 12:36:24 Irish standard time. Now imagine the confusion if both Irish Summer Time and Irish Standard Time were rendered as IST. You would not be able to distinguish. Instead, since Irish standard time coincides with GMT, this is what Date.toString() prints when the date is not in the summer time part of the year (which January isn’t).

My guess is that your first output is from a JVM running India time. It too is rendered as IST, and since India doesn’t use summer time, the same abbreviation is given summer and winter.

java.time

Before understanding the explanation for the behaviour you observed, I posted a comment about the outdated and the modern Java date and time classes. I still don’t think the comment is way off, though. This is the modern equivalent of your code:

    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
System.out.println(zdt);
zdt = zdt.with(LocalDate.of(2007, Month.JANUARY, 1));
System.out.println(zdt);

It prints

2017-09-12T11:45:33.921+01:00[Europe/Dublin]
2007-01-01T11:45:33.921Z[Europe/Dublin]

If you want to use the JVM’s time zone setting, use ZoneId.systemDefault() instead of ZoneId.of("Europe/Dublin"). As the name states, contrary to Date, ZonedDateTime does include a time zone. It corresponds more to the old Calendar class. As you can see, its toString method prints the offset from UTC (Z meaning zero offset) and the time zone name in the unambiguous region/city format. I believe that this leaves a lot less room for confusion. If you want to print the date in a specific format, use a DateTimeFormatter.

Appendix: sample output from your code

For the sake of completeness, here are the outputs from your code when running different time zones that may be rendered as IST:

  • Europe/Dublin (agrees with your second output)

    Tue Sep 12 11:19:28 IST 2017
    Mon Jan 01 11:19:28 GMT 2007
  • Asia/Tel_Aviv

    Tue Sep 12 13:19:28 IDT 2017
    Mon Jan 01 13:19:28 IST 2007
  • Asia/Kolkata (agrees with your first output)

    Tue Sep 12 15:49:28 IST 2017
    Mon Jan 01 15:49:28 IST 2007

Java Calendar returns wrong hour in MS Windows for `America/Santiago` zone

Summary

The authorities in Chile changed this year’s (2016) time zone rules at the last minute. The tz database in Java is not yet updated.

Details follow.

java.time

You are using the old date-time classes bundled with early Java that have proven to be troublesome. In Java 8 and later those classes were supplanted by the java.time framework (inspired by the Joda-Time library). Avoid the old classes.

Focus on UTC

Programmers should think first in UTC. Always verify the current time in UTC to be sure the computer even has the correct time. Flipping around time zones and Daylight Saving Time (DST) changes will make your brain hurt, and UTC is your aspirin.

In Java 8 and later, the Instant class represents a moment on the timeline in UTC with a resolution in nanoseconds.

Instant now = Instant.now();
System.out.println( "Instant.now(): " + now );

Always include the UTC value in a post such as this Question.

Time zone of host OS does not matter

The JVM holds it own representation of its current default time zone. By default in most implementations that zone is picked up from the host OS’ time zone setting. But Java launch configurations can override that default. And any Java code in any thread of any app within the JVM can change the JVM’s current default time zone during runtime with a call to TimeZone.setDefault.

So the current time zone setting of the host OS is irrelevant. What matters is the current setting in your JVM.

The part of your host OS that does matter is if its hardware clock knows the current moment correctly. In most JVM implementations, the current moment is determined from the host hardware clock, and then the JVM applies its own current default time zone.

Time Zone redefined for Chile in early 2016

Politicians enjoy fiddling with time zones and Daylight Saving Time (DST). Chile is no exception. See the Wikipedia article, Time in Chile.

From what I could discern… Last year, 2015, Chile stayed on DST permanently at -03:00 and deciding to never revert back to the standard time of -04:00. Then they changed their minds again, announcing in March 2016 that they would re-introduce standard time for their winter (southern hemisphere, winter being now, late May, June, July). On 2016-05-15 midnight (a couple weeks ago), the old standard offset of -04:00 kicked in. That standard/winter time will endure until 2016-08-14 (or until they change their minds again). [Take all that with a grain of salt. Please verify that I got the facts correct.]

These frequent changes wreak havoc with computers which need to have their tz time zone database files updated in order to reflect the latest fiddling.

Your operating system has its own copy of the time zone definitions. Java has its own copy. And other software such as your database engine may have its own copy.

Current Java 8 Update 92 lacks recent Chile changes

So let's run a test in Java 8 Update 92 to see if the Java copy of tz is up-to-date.

long millis = 1464645007120L;
Instant instant = Instant.ofEpochMilli ( millis ); // UTC, always.

ZoneId zoneId = ZoneId.of ( "America/Santiago" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );

Dump to console.

System.out.println ( "millis: " + millis + "  | instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt );

millis: 1464645007120 | instant: 2016-05-30T21:50:07.120Z | zoneId: America/Santiago | zdt: 2016-05-30T18:50:07.120-03:00[America/Santiago]

You can see the offset in the last part is -03:00. So it seems to me that the current version of Java released mid-April is unfortunately not up-to-date with the Chile changes announced in March.

From my readings it seems that today’s (2016-05-30) correct offset for America/Santiago should be -04:00 as seen here on time.is/Santiago.

Usually I would suggest using the Java tzupdater tool. But the current download is labeled with the word 2015 so I presume it is not up-to-date either.

I suggest filing a bug report at the Java team at Oracle.

Workaround

It may be a while before you can obtain a corrected version of the tz database (though perhaps you could hack your own update -- I do not know). Until then, as a workaround, perhaps you could specify your own offset in Java code using the ZoneOffset class, a subclass of ZoneId that represents only the offset-from-UTC without any rules for adjusting for anomalies such as DST. I’ve not thought through the implications; be wary.

ZoneOffset zoneOffset = ZoneOffset.of( -4 ); // Negative four hours for '-04:00'.

How to set time zone of a java.util.Date?

Use DateFormat. For example,

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");

Gregorian Calendar Wrong Hour

tl;dr

Problem: You are mistakenly changing the date, not just the time-of-day. On top of that, a time zone is implicitly being applied.

Solution: Instead use the modern java.time classes.

LocalDate
.now() // Better to explicitly pass the desired/expected time zone as a `ZoneId` object.
.atStartOfDay() // Again, better to explicitly pass the desired/expected time zone as a `ZoneId` object.

Returns a LocalDateTime (BEWARE: Not a moment, not a point on the timeline).

2018-11-01T00:00

Much better to specify time zone.

LocalDate
.now(
ZoneId.of( "Pacific/Auckland" )
)
.atStartOfDay(
ZoneId.of( "Pacific/Auckland" )
)

Returns a ZonedDateTime. This is a moment, is a point on the timeline.

2018-11-02T00:00+13:00[Pacific/Auckland]

GregorianCalendar::setTimeInMillis is not setting time-of-day

Apparently you mistakenly thought the GregorianCalendar::setTimeInMillis would set the time-of-day without affecting the date. Among the many flaws in these legacy date-time classes is some very poor choices in naming classes and methods.

But, no, that method redefines the moment as a count of milliseconds since epoch reference date of 1970-01-01T00:00Z.

Add in the time zone implicitly assigned to GregorianCalendar, and you have unexpected results.

I started to test around a bit with the Java-GregorianCalendar

Don’t.

Those old date-time classes bundled with the earliest versions of Java are terrible. They were supplanted years ago by the java.time classes defined in JSR 310.

Specifically, to track a moment in UTC, use Instant.

initializing the Object with milliseconds

Don’t.

Tracking time as a count-from-epoch-reference is prone to error. There are many different epoch reference dates in use in the industry. There are different granularities in use in the industry (whole seconds, milliseconds, microseconds, nanoseconds).

So a count-from-epoch is ambiguous. Also prone to confusing and missed errors because humans cannot read the meaning of the values.

When exchanging date-time values, use strings in standard ISO 8601 format instead.

When handed a count of milliseconds from the Unix epoch of first moment of 1970 in UTC, parse as an Instant.

Instant instant = Instant.ofEpochMilli( … ) ;

java.time

The modern solution uses java.time classes instead.

Get your date.

LocalDate

The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.

Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.

LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;

ZonedDateTime

Apparently you want the first moment of the day. By the way, do not think of this as “midnight” as that term is ambiguous.

The first moment of the day may not be 00:00. Anomalies such as Daylight Saving Time (DST) mean that the first moment on some dates in some zones may be another time such as 01:00. Let java.time determine the first moment.

Specify a time zone.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = localDate.atStartOfDay( z ) ;

If you want to see that same moment in UTC, extract a Instant.

Instant instant = zdt.toInstant() ;

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.

    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Java: Fix incorrect timezone in date object

tl;dr ⇒ use ZonedDateTime for conversion

public static void main(String[] args) {
// use your date here, this is just "now"
Date date = new Date();
// parse it to an object that is aware of the (currently wrong) time zone
ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
// print it to see the result
System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));

// extract the information that should stay (only date and time, NOT zone or offset)
LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
// print it, too
System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

// then take the object without zone information and simply add a zone
ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
// print the result
System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}

Output:

2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]

Explanation:

The reason why your approach did not just correct the zone but also adjusted the time accordingly (which is good when desired) is your use of a LocalDateTime created from an Instant. An Instant represents a moment in time which could have different representations in different zones but it stays the same moment. If you create a LocalDateTime from it and put another zone, the date and time are getting converted to the target zone's. This is not just replacing the zone while keeping the date and time as they are.

If you use a LocalDateTime from a ZonedDateTime, you extract the date and time representation ignoring the zone, which enables you to add a different zone afterwards and keep the date and time as it was.

Edit: If the code is running in the same JVM as the faulty code, you can use ZoneId.systemDefault() to get the same time zone as the faulty code is using. And depending on taste you may use ZoneOffset.UTC instead of ZoneId.of("GMT").

Java Date gives wrong time

This can be caused by one of two things:

  • The date in the underlying operating system is incorrect (but you may accidentally have configured it so you cannot tell).
  • The timezone determined by the JVM is incorrect (including that daylight savings information may be outdated).

Perhaps you could add the output of your new Date() along with information about what you were expecting and where you are?



Related Topics



Leave a reply



Submit