1

I'm creating a Calendar object:

Calendar calendar = new GregorianCalendar(2014, 0, 1);

and calendar.getTime() returns Wed Jan 01 00:00:00 BRT 2014

that is2014-01-01T00:00:00.000-0300

How to create Calendar with specific date in UTC TimeZone?

When I try to do calendar.setTimeZone(TimeZone.getTimeZone("UTC"));

calendar.getTime() returns the same.

kostepanych
  • 2,229
  • 9
  • 32
  • 47

3 Answers3

6

Just reverse the order of "specify date, specify time zone" to "specify time zone, specify date":

Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.set(2014, 0, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);

I'd also recommend avoiding the Calendar/Date API entirely - use java.time for Java 8, and Joda Time for older versions of Java.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    @user1491537: Please define "not working". What are you seeing, and what did you expect? (Bear in mind that if you're using `Date.toString()`, that will *always* show your default time zone. That's just an artifact of `toString()`; the `Date` doesn't have a specific time zone.) – Jon Skeet Mar 09 '16 at 13:11
  • 1
    Do you mean the output still contains the string "BRT"? If so, that doesn't mean it's not working - it means you have inappropriate expectations of `Date.toString()`. The question is whether the `Date` still represents midnight on Jan 1st 2014 UTC. – Jon Skeet Mar 09 '16 at 13:19
1

In Java, Dates are internally represented in UTC milliseconds since the epoch (so timezones are not taken into account, that's why you get the same results, as getTime() gives you the mentioned milliseconds). In your solution:

Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
long gmtTime = cSchedStartCal.getTime().getTime();

long timezoneAlteredTime = gmtTime + TimeZone.getTimeZone("Asia/Calcutta").getRawOffset();
Calendar cSchedStartCal1 = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
cSchedStartCal1.setTimeInMillis(timezoneAlteredTime);

you just add the offset from GMT to the specified timezone ("Asia/Calcutta" in your example) in milliseconds, so this should work fine.

Another possible solution would be to utilise the static fields of the Calendar class:

//instantiates a calendar using the current time in the specified timezone
Calendar cSchedStartCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
//change the timezone
cSchedStartCal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
//get the current hour of the day in the new timezone
cSchedStartCal.get(Calendar.HOUR_OF_DAY);

Refer to stackoverflow.com/questions/7695859/ for a more in-depth explanation.

Community
  • 1
  • 1
Mohith P
  • 585
  • 5
  • 14
1

The other Answers are correct.

java.time

Both the Question and other Answers use old date-time classes now outmoded by the java.time framework built into Java 8 and later. The old classes have proven to be poorly designed, confusing, and troublesome.

In the new classes, LocalDate represents a date-only value without time-of-day and without time zone.

LocalDate localDate = LocalDate.of( 2014 , 0 , 1 );

We can apply a time zone while asking for the first moment of the day. That first moment is not always the time 00:00:00.0 so we should ask rather than assume.

The resulting ZonedDateTime is an actual moment on the timeline.

ZoneId zoneId = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );

You can adjust to yet another time zone.

ZoneId zoneIdSaoPaulo = ZoneId.of( "America/Sao_Paulo" );
ZonedDateTime zdtSaoPaulo = zdt.withZoneSameInstant( zoneIdSaoPaulo );

Converting between legacy and modern classes

Best to avoid the legacy classes if possible. But if you must have an object of that class to interoperate with old code not yet updated for java.time, you can convert.

Calendar c = GregorianCalendar.from( zdtSaoPaulo ) ;

Going the other direction.

if( myCalendar instanceof GregorianCalendar ) 
{
    ZonedDateTime zdt = ( ( GregorianCalendar ) myCalendar ).toZonedDateTime() ;
}

Similarly, you can go between legacy java.util.Date and modern Instant. And java.sql.Date and LocalDate.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 1
    @OviTrif The legacy date-time classes are *terribly* designed, a masterclass in how to *not* do OOP. They were obviously written by people who did not understand date-time handling. As for existing codebases, you can *easily* convert between legacy classes and modern classes; see the new conversion methods added to the old classes. So you can write all new code in *java.time* while converting at the points you interact with the old code. Sun, Oracle, and the JCP community all gave up on `Date`, `Calendar`, etc. when they unanimously adopted JSR 310 *eight* years ago. I suggest you do the same. – Basil Bourque Apr 07 '22 at 18:15
  • @basil-borque Thanks, though that'll take some time to convince the tens of people commiting to the same github repos as me; I'm not the only owner of those codebases, so that's not always easy — which is the reason for my previous rant of which I'm sorry. P.S. I totally agree with you and never used the legacy date-time classes when I had the freedom to choose how to manage date-times. Now it's a bit more difficult working on repos with hundreds of contributors.. – Ovi Trif Apr 07 '22 at 21:36
  • 1
    @OviTrif I added code to the Answer to show converting from modern class to legacy – Basil Bourque Apr 07 '22 at 23:50
  • Awesome @Basil! Thank you for improving the answer to make it more useful for everyone! – Ovi Trif Apr 09 '22 at 01:44