Daylight Savings Time in Calendar

P

Philipp

Hello,
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below. What am
I doing wrong?

Thanks Phil

-- SSCCE --

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TestCalendar {
public static void main(String[] args) {
Date now = new Date(1214127677625L);
System.out.println(now);
Calendar cal = new
GregorianCalendar(TimeZone.getTimeZone("Europe/Zurich"));

cal.setTimeInMillis(now.getTime()); // setting both calendars to now

System.out.println("current DST: " + cal.get(Calendar.DST_OFFSET));
System.out.println(" With DST: " + cal.get(Calendar.HOUR_OF_DAY));

cal.set(Calendar.DST_OFFSET, 0); // putting DST to 0
System.out.println("new DST: " + cal.get(Calendar.DST_OFFSET));
System.out.println(" Without DST: " + cal.get(Calendar.HOUR_OF_DAY));
}
}


// Prints
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 11

// Expected
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 10
 
J

John B. Matthews

Philipp said:
Hello,
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below. What am
I doing wrong?
[...]

Setting DST_OFFSET has no effect because it's final; you might be able
to use add().

Instead, I think it helps to distinguish between the model (Calendar)
and the view (Format). Note how the time doesn't change, only the zone
of the view:
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class date5 {

private static GregorianCalendar gc = new GregorianCalendar();
private static final SimpleDateFormat f =
new SimpleDateFormat("'Zone: 'z' Hour: 'HH");

public static void main(String[] args) {

print(gc);

f.setTimeZone(TimeZone.getTimeZone("EST"));
print(gc);

f.setTimeZone(TimeZone.getTimeZone("UTC"));
print(gc);
}

private static void print(GregorianCalendar gc) {
System.out.println(f.format(gc.getTime())
+ " " + gc.getTimeInMillis());
}
}
Zone: EDT Hour: 09 1214140051344
Zone: EST Hour: 08 1214140051344
Zone: UTC Hour: 13 1214140051344
 
R

Roedy Green

n my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below. What am
I doing wrong?

Another approach is to use a TimeZone name that includes no DST. See
http://mindprod.com/jgloss/timezone.html
 
R

Roedy Green

// Prints
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 11

// Expected
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 10

Date and Calendar cause me to boil with anger at their goofy design
that subverts type checking. I suspect what might be happening is DST
is being ignored when you have done a setTimeZone.

There are some comments in the JavaDoc that suggest there is some
problem with changing the offset. Did you get any
IllegalArgumentExcepetions you ignored?
 
P

Philipp

John said:
Philipp said:
Hello,
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below. What am
I doing wrong?
[...]

Setting DST_OFFSET has no effect because it's final; you might be able
to use add().

Thanks for your answer.
In my example SSCCE the DST is actually changed (verified by the get()
and its printout). It isn't final, but it has no effect.

Instead, I think it helps to distinguish between the model (Calendar)
and the view (Format). Note how the time doesn't change, only the zone
of the view:

Yes absolutely, as the time in millis is a GMT timestamp (and not the
time in a given locale). That's what I want to use.
What you are suggesting is that I should find a local which matches mine
("Europe/Zurich") but which has no DST. I don't know if that exists,
but anyhow I want to be able to use the program in any local, and the
hour without DST should be calculated correctly. So I really want to
take any locale and remove the DST (only if there is one).

I know of a workaround which is to write:

cal.setTimeInMillis(now.getTime() - cal.get(Calendar.DST_OFFSET));

but this is ugly as I am actually changing the timestamp and not the
representation of the timestamp.

Phil
 
P

Philipp

Roedy said:
Date and Calendar cause me to boil with anger at their goofy design
that subverts type checking.

Absolutely. Also Date should be immutable.
I suspect what might be happening is DST
is being ignored when you have done a setTimeZone.

Well the DST rule is still applied correctly after the set, so the new
value is actually ignored.
There are some comments in the JavaDoc that suggest there is some
problem with changing the offset. Did you get any
IllegalArgumentExcepetions you ignored?

No Exception. But a modified test shows that the DST in the time zone
and the DST in the Calendar are two different values. The one which is
relevant for the Calendars output is the one in the TimeZone (which
can't be changed). :-(

Unless I missed something, I thus have to use the workaround then (see
my answer to John B. Mathews).

Phil
 
R

Roedy Green

No Exception. But a modified test shows that the DST in the time zone
and the DST in the Calendar are two different values. The one which is
relevant for the Calendars output is the one in the TimeZone (which
can't be changed). :-(

and no documentation GRRR!
 
J

John B. Matthews

Philipp said:
John said:
Philipp said:
Hello,
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below. What am
I doing wrong?
[...]

Setting DST_OFFSET has no effect because it's final; you might be able
to use add().

Thanks for your answer.
In my example SSCCE the DST is actually changed (verified by the get()
and its printout). It isn't final, but it has no effect.

Mine says "public static final int DST_OFFSET." Possibly, DST is
changing for some other reason.
Yes absolutely, as the time in millis is a GMT timestamp (and not the
time in a given locale). That's what I want to use. What you are
suggesting is that I should find a local which matches mine
("Europe/Zurich") but which has no DST. I don't know if that
exists, but anyhow I want to be able to use the program in any local,
and the hour without DST should be calculated correctly. So I really
want to take any locale and remove the DST (only if there is one).

I know of a workaround which is to write:

cal.setTimeInMillis(now.getTime() - cal.get(Calendar.DST_OFFSET));

but this is ugly as I am actually changing the timestamp and not the
representation of the timestamp.

IIUC, you want to know what hour a local clock would say in the absence
of daylight savings time for a given instant. I see what you mean about
finding a matching time zone without DST:)

Instead, you can change a copy of the instant. Use add() to subtract the
daylight savings for the TimeZone belonging to the Calendar instance;
it's zero for standard time. Here's a comparison:
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class date5 {

private static GregorianCalendar gc = new GregorianCalendar();
private static final SimpleDateFormat f1 =
new SimpleDateFormat("MMM dd, yyyy HH:mm:ss");
private static final SimpleDateFormat f2 =
new SimpleDateFormat("'gmt'Z'; hour: 'HH");

public static void main(String[] args) {
print(gc, TimeZone.getTimeZone("UTC"));
print(gc, TimeZone.getTimeZone("EST"));
print(gc, TimeZone.getDefault());

TimeZone tz = gc.getTimeZone();
gc.add(GregorianCalendar.MILLISECOND, -tz.getDSTSavings());
print(gc, tz);
}

private static void print(GregorianCalendar gc, TimeZone tz) {
f2.setTimeZone(tz);
long m = gc.getTimeInMillis();
System.out.println(
f1.format(gc.getTime())
+ "; ms: " + m
+ "; " + f2.format(gc.getTime())
+ "; dst: " + tz.inDaylightTime(gc.getTime()));
}
}
Jun 22, 2008 16:56:19; ms: 1214168179567; gmt+0000; hour: 20; dst: false
Jun 22, 2008 16:56:19; ms: 1214168179567; gmt-0500; hour: 15; dst: false
Jun 22, 2008 16:56:19; ms: 1214168179567; gmt-0400; hour: 16; dst: true
Jun 22, 2008 15:56:19; ms: 1214164579567; gmt-0400; hour: 15; dst: true
 
A

Arne Vajhøj

Philipp said:
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position). To do this I use Calendar and set the
DST_OFFSET to 0. But that doesn't work. See example code below.
Date now = new Date(1214127677625L);
System.out.println(now);
Calendar cal = new
GregorianCalendar(TimeZone.getTimeZone("Europe/Zurich"));

cal.setTimeInMillis(now.getTime()); // setting both calendars to now

System.out.println("current DST: " + cal.get(Calendar.DST_OFFSET));
System.out.println(" With DST: " + cal.get(Calendar.HOUR_OF_DAY));

cal.set(Calendar.DST_OFFSET, 0); // putting DST to 0
System.out.println("new DST: " + cal.get(Calendar.DST_OFFSET));
System.out.println(" Without DST: " + cal.get(Calendar.HOUR_OF_DAY));
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 11
Sun Jun 22 11:41:17 CEST 2008
current DST: 3600000
With DST: 11
new DST: 0
Without DST: 10

To me it makes perfectly sense that you can not change the DST
behavior of a time zone.

Because that is how the real world is.

You need to specify a time zone that matches your
requirements.

Example:

DateFormat df = new SimpleDateFormat("HH");
df.setTimeZone(TimeZone.getTimeZone("GMT+01:00"));
System.out.println(df.format(cal.getTime()));

(and do not call cal.set(Calendar.DST_OFFSET, 0) because
that messes things up)

Arne
 
J

John B. Matthews

Lew said:
That doesn't mean that the offset cannot change. It means that the integer
representing which field is the offset does not change.

So yes, DST_OFFSET is a final field. However, its value is not the value of
the offset.

You're right! My bad. Sadly, this occurred to me well _after_ I'd hit
send:) Thanks.
 
J

John B. Matthews

Philipp said:
Yes absolutely, as the time in millis is a GMT timestamp (and not the
time in a given locale). That's what I want to use.
What you are suggesting is that I should find a local which matches mine
("Europe/Zurich") but which has no DST. I don't know if that exists,
but anyhow I want to be able to use the program in any local, and the
hour without DST should be calculated correctly. So I really want to
take any locale and remove the DST (only if there is one).

I know of a workaround which is to write:

cal.setTimeInMillis(now.getTime() - cal.get(Calendar.DST_OFFSET));

but this is ugly as I am actually changing the timestamp and not the
representation of the timestamp.

I think you have to change one or the other, perhaps using a clone()?
Going back to your original example, here's what I was driving at:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TestCalendar {

private static final SimpleDateFormat f =
new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss 'GMT'Z");

public static void main(String[] args) {
TimeZone tz = TimeZone.getTimeZone("Europe/Zurich");
Calendar cal = new GregorianCalendar(tz); // now, with Zurich tz

System.out.println("Local: " + f.format(cal.getTime()));
f.setTimeZone(tz);
System.out.println("Zurich: " + f.format(cal.getTime()));
System.out.println("In DST: " + tz.inDaylightTime(cal.getTime()));
System.out.println("With DST: " + cal.get(Calendar.HOUR_OF_DAY));
cal.add(Calendar.MILLISECOND, -tz.getDSTSavings());
System.out.println("Sans DST: " + cal.get(Calendar.HOUR_OF_DAY));
}
}

Local: 22-Jun-2008 22:34:28 GMT-0400
Zurich: 23-Jun-2008 04:34:28 GMT+0200
In DST: true
With DST: 4
Sans DST: 3
 
D

Dr J R Stockton

In comp.lang.java.programmer message <[email protected]>,
In my Locale there is Daylight Savings Time (DST) in effect. I would
like to get the time of the day without the DST (ie, the hour as
indicated by the sun position).

I doubt it. In Europe we have Summer Time, variously translated. DST
is a linguistic aberration introduced by those who use the term
"English" to mean something noticeably different from the English
language.

If you can obtain the offset from GMT for the current local time, and
that for January 1st, and that from July 1st, then you can determine
from January & July what the Winter Offset is (assuming only that, if
there is Summer Time, the clocks change in the right direction in Spring
and Autumn; and maybe that the Rule does not make an adverse change
within the relevant half-year). You can then subtract the difference
between the winter and current offsets.

I do that in my JavaScript Web pages - <URL:http://www.merlyn.demon.co.u
k/js-dates.htm#DTN>.
 
R

RedGrittyBrick

Tim said:
American English is by far the most common form of English spoken today,
and since language correctness is determined by usage,

Darn tootin. Goddam city slickers n forrin varmints dont got no cents!
How come you aint speaking rite pardner?
 
N

Nigel Wade

Tim said:
American English is by far the most common form of English spoken today,
and since language correctness is determined by usage, that makes
American English the one that is *the* English language. Your quaint
regional variation is amusing to us, though, so keep it up.

Isn't it about time that you Americans actually came up with some original names
for things instead of just naming everything after something else? Don't you
have *any* originality? You can't even manage to give your largest city an
original name...

Whist we endorse you correctly honouring your linguistic roots by referring to
it as "English", it isn't actually English anymore. It has clearly mutated into
something (to paraphrase the great author himself) "almost, but not quite,
entirely unlike English". The qualification "English" is no longer warranted,
or even strictly valid.
 
P

Philipp

Philipp said:
John B. Matthews wrote:
So I really want to
take any locale and remove the DST (only if there is one).

I know of a workaround which is to write:

cal.setTimeInMillis(now.getTime() - cal.get(Calendar.DST_OFFSET));

but this is ugly as I am actually changing the timestamp and not the
representation of the timestamp.

Update: this workaround is actually wrong during one hour at the time
change period. So it's not a good solution. If anybody knows of a better
one, I'd be happy to use it.

Phil
 
N

Nigel Wade

Philipp said:
Update: this workaround is actually wrong during one hour at the time
change period. So it's not a good solution. If anybody knows of a better
one, I'd be happy to use it.

Phil

One has already been provided by Arne.

Use a "fixed" time zone i.e. one which does not use DST. For central Europe that
would be GMT+1:00, i.e. GMT (which does not use DST) plus one hour.


Try the code below and you will see that GMT+1:00 Calendar has:

dstSavings=0
useDaylight=false
HOUR_OF_DAY=15
ZONE_OFFSET=3600000
DST_OFFSET=0

whereas Europe/Zurich has:

dstSavings=3600000
useDaylight=true
HOUR_OF_DAY=16
ZONE_OFFSET=3600000
DST_OFFSET=3600000


import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TestTime {

public static void main(String[] args) {
Calendar fixedCal = new GregorianCalendar(TimeZone.getTimeZone("GMT+1:00"));
Calendar dstCal =
new GregorianCalendar(TimeZone.getTimeZone("Europe/Zurich"));

System.out.println(fixedCal);
System.out.println(dstCal);
}
}
 
A

Arne Vajhøj

Philipp said:
Update: this workaround is actually wrong during one hour at the time
change period. So it's not a good solution. If anybody knows of a better
one, I'd be happy to use it.

DateFormat df = new SimpleDateFormat("HH");
TimeZone tz = TimeZone.getTimeZone("GMT");
tz.setRawOffset(cal.getTimeZone().getRawOffset());
df.setTimeZone(tz);
System.out.println(df.format(cal.getTime()));

Arne
 
P

Philipp

Arne said:
DateFormat df = new SimpleDateFormat("HH");
TimeZone tz = TimeZone.getTimeZone("GMT");
tz.setRawOffset(cal.getTimeZone().getRawOffset());
df.setTimeZone(tz);
System.out.println(df.format(cal.getTime()));

Arne

Thank you Arne, this works perfect!
I somehow missed the setRawOffset() in TimeZone and thus thought that
TimeZones were immutable.

Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top