2

I am passing date from front end which is IST(date of indian timezone). And in java code i am converting date to calendar using the following code(This is happening in the server which is there in US PST timezone).

Calendar cal = Calendar.getInstance();
int offset = date.getTimezoneOffset();
logger.info("Calendar Instance - " + cal);
cal.setTime(date);
logger.info("Calendar Instance after setting date - " + cal);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
logger.info("Calendar Instance after setting zeros - " + cal);
return cal;

so when i see the last log the day of the month will be one day less than what i passed.eg. if i pass 22/06/2015 IST it shifts to 21/06/2015. so after processing finally it displays 21/06/2015 in the list of data which is in another UI page.

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
bharath kumar
  • 21
  • 1
  • 1
  • 4
  • Where is `date` set? – Ryan J Jun 24 '15 at 17:15
  • Don’use Calendar in general. That library is a mess. Use java.time instead – gurghet Jun 24 '15 at 17:18
  • @gurghet: Could you please elaborate. The api in java code accepts calendar only. how to use java.time with that. – bharath kumar Jun 24 '15 at 17:29
  • @Ryan: date is passed from UI. – bharath kumar Jun 24 '15 at 17:30
  • @bharathkumar It would be pertinent to see where/how the UI is creating the `Date` object, since there could be some field value math errors. The `DAY_OF_MONTH` field's first value starts at 1, not 0. Are you doing any number manipulation anywhere? – Ryan J Jun 24 '15 at 17:39
  • @Ryan J No i am not doing any number manupulation. private static Calendar getDateWithoutTime(Date date) { ----} in this when i debug i get date 22/06/2015 which is IST date and once i convert to calendar DAY_OF_MONTH would be 21. And after getting response from API finally it would be 21 only. – bharath kumar Jun 24 '15 at 17:43

2 Answers2

8

This happens because JVM on server side and JVM on client side use different time zones by default Java TimeZone:

Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time.

As we can see, Pacific Time Zone on server has UTC−8:00 and Indian Standard Time on client has UTC+05:30. They differ by 13.30 and Indian date X converts to US as X-13.30 what may yield a day before on server side for certain X.

Several workarounds are possible depending on how you can influence/modify your server and client application. For example, you may work with dates in UTC+00:00 time zone on both server and client sides. If you need to show a date to the user you may convert it to Indian time zone when needed.

// Set default GMT+0:00 time zone
TimeZone timeZone;
timeZone = TimeZone.getTimeZone("GMT+0:00");
TimeZone.setDefault(timeZone);

Instead of simply using Calendar cal = Calendar.getInstance(); you may create "clear" calendar which you will user later on to set day, month and year

public static Calendar createClearedCalendar() {
    Calendar cal = Calendar.getInstance();

    cal.setTimeZone(timeZone);

    cal.set(1970, 0, 1, 0, 0, 0);
    cal.set(Calendar.HOUR_OF_DAY, 0);

    cal.clear(Calendar.MILLISECOND);

    return cal;
}

By the way, if you manipulate date-time in Java you may consider Joda Time which has more extended options and optimized performance.

Antonio
  • 756
  • 7
  • 26
  • Dont’use Joda Time, it’s not portable, use java.time instead. – gurghet Jun 24 '15 at 18:03
  • You may decide whether to use Joda Time in your own project referring to [this discussion as an example](http://stackoverflow.com/questions/375544/are-there-any-cons-to-using-joda-time) – Antonio Jun 24 '15 at 18:36
  • that’s pretty old, java.time is much better – gurghet Jun 24 '15 at 19:24
  • Please note, java.time is available since JDK1.8 – Antonio Jun 24 '15 at 19:30
  • Joda-Time inspired java.time, with the same people designing and building both. Each has features the other lacks, such as `Interval` in Joda-Time but not (yet?) in java.time. Joda-Time continues as an active project, running in multiple versions of Java and in Android too. So, Yes, one should start with java.time where possible but otherwise use Joda-Time. Also, look at [ThreeTen-Extra](http://www.threeten.org/threeten-extra/) project for adding features to java.time. – Basil Bourque Jun 24 '15 at 20:39
0

The Answer by Antonio is correct and should be accepted (click the big empty check mark).

This Answer adds some thoughts and example code.

Avoid 3-Letter Time Zone Codes

Avoid using, or even thinking about, those 3 or 4 letter codes such as IST or PST. They are not standardized, they are not unique, and they further confuse issues around Daylight Saving Time (DST). For example, IST means "India Standard Time", "Irish Standard Time", and more.

Use proper time zone names. Most of these are in a "continent" + "/" + "city/region" pattern. The city/region name is not meant specifically for that town, but rather as an easily identifiable name for as wide an area as possible that shares the same set of past, present, and future rules for time zone rules and anomalies (including DST).

Use UTC

Generally you should be using UTC time zone for all your business logic, data storage, and data exchange. Adjust to a particular time zone only for presentation when expected by the user.

Use A Decent Date-Time Framework

The old java.util.Date/.Calendar classes were a bold attempt at handling date-time work, but ultimately they failed. They are notoriously troublesome, flawed in both design and implementation. Avoid them.

The 3rd-party Joda-Time library is one solution. It works in many versions of Java and also in Android. Joda-Time inspired the other solution, the java.time package found in Java 8 and later (Tutorial).

Solution

The Question seems to have a goal of taking a java.util.Date object, assign desired time zone, and produce a java.util.Calendar object.

Fortunately the java.time framework has conversion methods. See this Tutorial page.

Example code follows, using java.time from Java 8 Update 45.

You may want imports such as:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

Let's simulate getting a java.util.Date passed in. We'll instantiate a Date based on "now".

Date inputDate = new Date( );  // Simulate getting a java.util.Date object.

Then we define the desired time zones, using proper time zone names. Let’s throw in Montréal just for fun as well as the pacific United States and India time zones mentioned in the Question.

ZoneId zoneLosAngeles = ZoneId.of( "America/Los_Angeles" );
ZoneId zoneMontréal = ZoneId.of( "America/Montreal" );
ZoneId zoneKolkata = ZoneId.of( "Asia/Kolkata" );

Then we convert that to an Instant, a point on the timeline without regard to time zone.

Instant instant = inputDate.toInstant( );

Then we assign various time zones to create ZonedDateTime instances. See how we can instantiate a ZonedDateTime in either of two ways: [a] from an Instant, or [b] from another ZonedDateTime via the withZoneSameInstant method. Both ways are shown below.

Note that java.time (and Joda-Time) uses immutable objects, a design pattern where we create new instances based on the old instance rather than alter ("mutate") the old instance. Thread-safety is one of the major benefits.

ZonedDateTime zdtLosAngeles = ZonedDateTime.ofInstant( instant, zoneLosAngeles );
ZonedDateTime zdtMontréal = ZonedDateTime.ofInstant( instant, zoneMontréal );
ZonedDateTime zdtKolkata = ZonedDateTime.ofInstant( instant, zoneKolkata );
ZonedDateTime zdtUtc = zdtKolkata.withZoneSameInstant( ZoneOffset.UTC );

Lastly, we convert one of those to a GregorianCalendar object which is a subclass of java.util.Calendar.

GregorianCalendar calendarKolkata = GregorianCalendar.from( zdtKolkata );

Dump to console.

System.out.println( "inputDate: " + inputDate );
System.out.println( "zdtLosAngeles: " + zdtLosAngeles );
System.out.println( "zdtMontréal: " + zdtMontréal );
System.out.println( "zdtKolkata: " + zdtKolkata );
System.out.println( "zdtUtc: " + zdtUtc );
System.out.println( "calendarKolkata: " + calendarKolkata );

When run.

inputDate: Wed Jun 24 15:12:12 PDT 2015
zdtLosAngeles: 2015-06-24T15:12:12.153-07:00[America/Los_Angeles]
zdtMontréal: 2015-06-24T18:12:12.153-04:00[America/Montreal]
zdtKolkata: 2015-06-25T03:42:12.153+05:30[Asia/Kolkata]
zdtUtc: 2015-06-24T22:12:12.153Z
calendarKolkata: java.util.GregorianCalendar[time=1435183932153,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2015,MONTH=5,WEEK_OF_YEAR=26,WEEK_OF_MONTH=4,DAY_OF_MONTH=25,DAY_OF_YEAR=176,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=3,HOUR_OF_DAY=3,MINUTE=42,SECOND=12,MILLISECOND=153,ZONE_OFFSET=19800000,DST_OFFSET=0]
Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • The timezone changes dynamically i cant take particularly like "asia/kolkata". user might access from any time zone. i tried getting timezone from date using dateobject.getTimeZoneOffset() dynamically and add it to the calendar but this is deprecated more over for marshalling they have used some jars which takes server timezone only for converting calendar to xmlgreagoriancalendar i cannot set the timezone for it. – bharath kumar Jun 25 '15 at 05:07
  • Effectively, a java.util.Date has no time zone. Basically it is just a wrapper around a count of milliseconds from epoch of 1970 in UTC. There actually is a time zone deep in the source code, used internally for some things but of no use to you. The j.u.Date object gives you the key piece you need: a date-time value in UTC. Simply specify your desired/expected time zone as I showed. – Basil Bourque Jun 25 '15 at 07:00
  • There is no specific timezone i can stick. i need to get the client zone dynamically and set it. but they have used GWT for front end i am not sure how to get client zone dynamically. – bharath kumar Jun 25 '15 at 11:22
  • Search StackOverflow for that issue, getting time zone from web client. Ultimately, the only sure way is to ask the user, have the user select a [proper time zone name](https://en.m.wikipedia.org/wiki/List_of_tz_database_time_zones). – Basil Bourque Jun 25 '15 at 15:37
  • There is no option for user to select timezone. They can select only date from GWT date picker. – bharath kumar Jun 28 '15 at 05:53