Daylight Savings Time in Calendar

Discussion in 'Java' started by Philipp, Jun 22, 2008.

  1. Philipp

    Philipp Guest

    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
     
    Philipp, Jun 22, 2008
    #1
    1. Advertisements

  2. [...]

    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
     
    John B. Matthews, Jun 22, 2008
    #2
    1. Advertisements

  3. Philipp

    Roedy Green Guest

    Another approach is to use a TimeZone name that includes no DST. See
    http://mindprod.com/jgloss/timezone.html
     
    Roedy Green, Jun 22, 2008
    #3
  4. Philipp

    Roedy Green Guest

    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?
     
    Roedy Green, Jun 22, 2008
    #4
  5. Philipp

    Philipp Guest

    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.

    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
     
    Philipp, Jun 22, 2008
    #5
  6. Philipp

    Philipp Guest

    Absolutely. Also Date should be immutable.
    Well the DST rule is still applied correctly after the set, so the new
    value is actually 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
     
    Philipp, Jun 22, 2008
    #6
  7. Philipp

    Roedy Green Guest

    and no documentation GRRR!
     
    Roedy Green, Jun 22, 2008
    #7
  8. Mine says "public static final int DST_OFFSET." Possibly, DST is
    changing for some other reason.
    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
     
    John B. Matthews, Jun 22, 2008
    #8
  9. Philipp

    Arne Vajhøj Guest

    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
     
    Arne Vajhøj, Jun 22, 2008
    #9
  10. You're right! My bad. Sadly, this occurred to me well _after_ I'd hit
    send:) Thanks.
     
    John B. Matthews, Jun 23, 2008
    #10
  11. 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
     
    John B. Matthews, Jun 23, 2008
    #11
  12. In comp.lang.java.programmer message <485e1efe$>,
    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>.
     
    Dr J R Stockton, Jun 23, 2008
    #12
  13. Darn tootin. Goddam city slickers n forrin varmints dont got no cents!
    How come you aint speaking rite pardner?
     
    RedGrittyBrick, Jun 24, 2008
    #13
  14. Philipp

    Nigel Wade Guest

    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.
     
    Nigel Wade, Jun 24, 2008
    #14
  15. Philipp

    Philipp Guest

    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
     
    Philipp, Jun 25, 2008
    #15
  16. Philipp

    Nigel Wade Guest

    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);
    }
    }
     
    Nigel Wade, Jun 25, 2008
    #16
  17. Philipp

    Arne Vajhøj Guest

    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
     
    Arne Vajhøj, Jun 26, 2008
    #17
  18. Philipp

    Philipp Guest

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

    Phil
     
    Philipp, Jun 26, 2008
    #18
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.