Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #18568 > unrolled thread

Date/Calendar confusion

Started byUlrich Scholz <d7@thispla.net>
First post2012-09-06 01:03 -0700
Last post2012-09-08 16:51 -0700
Articles 9 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Date/Calendar confusion Ulrich Scholz <d7@thispla.net> - 2012-09-06 01:03 -0700
    Re: Date/Calendar confusion nogales <nogales.manuel@gmail.com> - 2012-09-06 02:29 -0700
    Re: Date/Calendar confusion Lew <lewbloch@gmail.com> - 2012-09-06 10:21 -0700
    Re: Date/Calendar confusion "John B. Matthews" <nospam@nospam.invalid> - 2012-09-06 20:53 -0400
      Re: Date/Calendar confusion Lew <lewbloch@gmail.com> - 2012-09-07 11:01 -0700
        Re: Date/Calendar confusion "John B. Matthews" <nospam@nospam.invalid> - 2012-09-07 21:02 -0400
          Re: Date/Calendar confusion Lew <lewbloch@gmail.com> - 2012-09-07 18:44 -0700
            Re: Date/Calendar confusion "John B. Matthews" <nospam@nospam.invalid> - 2012-09-08 09:12 -0400
              Re: Date/Calendar confusion Lew <lewbloch@gmail.com> - 2012-09-08 16:51 -0700

#18568 — Date/Calendar confusion

FromUlrich Scholz <d7@thispla.net>
Date2012-09-06 01:03 -0700
SubjectDate/Calendar confusion
Message-ID<3a69eb4a-f3c0-4b56-9a67-6833ccb2a1c8@googlegroups.com>
Dear all,

have a look at the function below (Java 5).  The first result is 0 as expected. But why is the second one different?

Thanks, Ulrich
 

private static void testDate() throws ParseException
    {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        TimeZone timeZone = TimeZone.getTimeZone("GMT");
        timeZone.setRawOffset(0); // get GMT time zone for sure
        dateFormat.setTimeZone(timeZone);

        Calendar calendar1 = Calendar.getInstance(timeZone, Locale.US);
        Date date1 = dateFormat.parse("1970-01-01T00:00:00.000");
        calendar1.setTime(date1);
        System.out.println(calendar1.getTimeInMillis()); // is 0

        Calendar calendar2 = Calendar.getInstance(timeZone, Locale.US);
        Date date2 = dateFormat.parse("0000-00-00T00:00:00.000");
        calendar2.setTime(date2);

        // adjust for the epoch 01.01.1970
        //
        calendar2.set(Calendar.YEAR, calendar2.get(Calendar.YEAR) + 1970);
        calendar2.set(Calendar.MONTH, calendar2.get(Calendar.MONTH) + 1);
        calendar2.set(Calendar.DAY_OF_MONTH, calendar2.get(Calendar.DAY_OF_MONTH) + 1);

        System.out.println(calendar2.getTimeInMillis()); // should be 0 but is -124335907200000
    }

[toc] | [next] | [standalone]


#18569

Fromnogales <nogales.manuel@gmail.com>
Date2012-09-06 02:29 -0700
Message-ID<1619c434-6b01-4c16-8cf5-de6cdf8615fd@googlegroups.com>
In reply to#18568
Try this:


package snippet;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Snippet {
	public static void main(String[] args) throws ParseException {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 
        TimeZone timeZone = TimeZone.getTimeZone("GMT"); 
        timeZone.setRawOffset(0); // get GMT time zone for sure 
        dateFormat.setTimeZone(timeZone); 

        Calendar calendar1 = Calendar.getInstance(timeZone, Locale.US); 
        Date date1 = dateFormat.parse("1970-01-01T00:00:00.000"); 
        System.out.println(date1);
        calendar1.setTime(date1); 
        System.out.println(calendar1.getTimeInMillis()); // is 0 
        System.out.println(calendar1);

        Calendar calendar2 = Calendar.getInstance(timeZone, Locale.US); 
        Date date2 = dateFormat.parse("0001-01-01T00:00:00.000");
        System.out.println(date2);
        calendar2.setTime(date2); 

        // adjust for the epoch 01.01.1970 
        // 
        calendar2.set(Calendar.YEAR, calendar2.get(Calendar.YEAR) + 1969); 
        calendar2.set(Calendar.MONTH, calendar2.get(Calendar.MONTH)); 
        calendar2.set(Calendar.DAY_OF_MONTH, calendar2.get(Calendar.DAY_OF_MONTH)); 
        System.out.println(calendar2);

        System.out.println(calendar2.getTimeInMillis()); // should be 0 but is -124335907200000 
		
	}
}

[toc] | [prev] | [next] | [standalone]


#18573

FromLew <lewbloch@gmail.com>
Date2012-09-06 10:21 -0700
Message-ID<da8b641c-6030-4681-81be-4ddc9ef795c7@googlegroups.com>
In reply to#18568
Ulrich Scholz wrote:
> have a look at the function below (Java 5).  The first result is 0 as expected. But why is the second one different?
> 
> private static void testDate() throws ParseException
>     {
>         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

It's lenient by default.
http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#setLenient(boolean)
http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#isLenient()
"The default is lenient."

Check the docs when you have a question like this.

>         TimeZone timeZone = TimeZone.getTimeZone("GMT");
>         timeZone.setRawOffset(0); // get GMT time zone for sure

WTF?

>         dateFormat.setTimeZone(timeZone);
> 
>         Calendar calendar1 = Calendar.getInstance(timeZone, Locale.US);
>         Date date1 = dateFormat.parse("1970-01-01T00:00:00.000");
>         calendar1.setTime(date1);
>         System.out.println(calendar1.getTimeInMillis()); // is 0
> 
>         Calendar calendar2 = Calendar.getInstance(timeZone, Locale.US);
>         Date date2 = dateFormat.parse("0000-00-00T00:00:00.000");

What date is that, really?

>         calendar2.setTime(date2);
>         // adjust for the epoch 01.01.1970
>         calendar2.set(Calendar.YEAR, calendar2.get(Calendar.YEAR) + 1970);
>         calendar2.set(Calendar.MONTH, calendar2.get(Calendar.MONTH) + 1);

By this time, 'get(Calendar.MONTH)' is probably not what you think.

>         calendar2.set(Calendar.DAY_OF_MONTH, calendar2.get(Calendar.DAY_OF_MONTH) + 1);

" As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class."
http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html

>         System.out.println(calendar2.getTimeInMillis()); // should be 0 but is -124335907200000
>     }

When you set the 'Calendar' to the invalid date, it readjusted its internal values so those 
'00' values were made into valid values.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#18577

From"John B. Matthews" <nospam@nospam.invalid>
Date2012-09-06 20:53 -0400
Message-ID<nospam-D06BA0.20534806092012@news.aioe.org>
In reply to#18568
In article <3a69eb4a-f3c0-4b56-9a67-6833ccb2a1c8@googlegroups.com>,
 Ulrich Scholz <d7@thispla.net> wrote:

> calendar2.set(Calendar.YEAR, calendar2.get(Calendar.YEAR) + 1970);
> calendar2.set(Calendar.MONTH, calendar2.get(Calendar.MONTH) + 1);
> calendar2.set(Calendar.DAY_OF_MONTH,
>      calendar2.get(Calendar.DAY_OF_MONTH) + 1);

Note that Calendar.JANUARY is not 1. Use clear() to set some or all 
fields to a known (undefined, !isSet()) state.

public static void main(String[] args) {
    TimeZone timeZone = TimeZone.getTimeZone("GMT");
    SimpleDateFormat f = new SimpleDateFormat(
        "yyyy-MMM-dd HH:mm:ss.SSS Z");

    Calendar calendar1 = Calendar.getInstance(timeZone);
    System.out.println(f.format(calendar1.getTime()));
    calendar1.clear();
    System.out.println(calendar1.getTimeInMillis()); // 0

    Calendar calendar2 = Calendar.getInstance(timeZone);
    System.out.println(f.format(calendar2.getTime()));
    calendar2.set(Calendar.YEAR, 1970);
    calendar2.set(Calendar.MONTH, Calendar.JANUARY);
    calendar2.set(Calendar.DAY_OF_MONTH, 1);
    calendar2.clear(Calendar.HOUR);
    calendar2.clear(Calendar.MINUTE);
    calendar2.clear(Calendar.SECOND);
    calendar2.clear(Calendar.MILLISECOND);
    System.out.println(calendar2.getTimeInMillis()); // 0
}

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

[toc] | [prev] | [next] | [standalone]


#18594

FromLew <lewbloch@gmail.com>
Date2012-09-07 11:01 -0700
Message-ID<3931f4ca-a41a-489a-8521-545eaed21742@googlegroups.com>
In reply to#18577
 John B. Matthews wrote:
> Ulrich Scholz  wrote:
>> calendar2.set(Calendar.YEAR, calendar2.get(Calendar.YEAR) + 1970);
>> calendar2.set(Calendar.MONTH, calendar2.get(Calendar.MONTH) + 1);
>> calendar2.set(Calendar.DAY_OF_MONTH,
>>      calendar2.get(Calendar.DAY_OF_MONTH) + 1);
> 
> Note that Calendar.JANUARY is not 1. Use clear() to set some or all 
> fields to a known (undefined, !isSet()) state.

DANGER!
http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear()
"Sets all the calendar field values and the time value (millisecond offset from 
the Epoch) of this Calendar undefined."

http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear(int)
"Sets the given calendar field value and the time value (millisecond offset from 
the Epoch) of this Calendar undefined."

These set the fields to *undefined* - not zero-equivalents.

I have seen bugs in production caused by a programmer confusing 'clear()' 
with 'set(field, 0)'.
 
> public static void main(String[] args) {
>     TimeZone timeZone = TimeZone.getTimeZone("GMT");
>     SimpleDateFormat f = new SimpleDateFormat(
>         "yyyy-MMM-dd HH:mm:ss.SSS Z");
> 
>     Calendar calendar1 = Calendar.getInstance(timeZone);
> 
>     System.out.println(f.format(calendar1.getTime()));
> 
>     calendar1.clear();

Dangerous. You need to do something to set that 'Calendar' instance
to a consistent state now.

>     System.out.println(calendar1.getTimeInMillis()); // 0
> 
>     Calendar calendar2 = Calendar.getInstance(timeZone);
> 
>     System.out.println(f.format(calendar2.getTime()));
> 
>     calendar2.set(Calendar.YEAR, 1970);
>     calendar2.set(Calendar.MONTH, Calendar.JANUARY);
>     calendar2.set(Calendar.DAY_OF_MONTH, 1);
> 
>     calendar2.clear(Calendar.HOUR);

Better: 'calendar2.set(Calendar.HOUR, 0);'

>     calendar2.clear(Calendar.MINUTE);
>     calendar2.clear(Calendar.SECOND);
>     calendar2.clear(Calendar.MILLISECOND);
> 
>     System.out.println(calendar2.getTimeInMillis()); // 0
> }

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#18599

From"John B. Matthews" <nospam@nospam.invalid>
Date2012-09-07 21:02 -0400
Message-ID<nospam-64D325.21022107092012@news.aioe.org>
In reply to#18594
In article <3931f4ca-a41a-489a-8521-545eaed21742@googlegroups.com>,
 Lew <lewbloch@gmail.com> wrote:

>  John B. Matthews wrote:
> > Ulrich Scholz  wrote:

[Valuable clarifications elided.]

> >     calendar2.set(Calendar.YEAR, 1970);
> >     calendar2.set(Calendar.MONTH, Calendar.JANUARY);
> >     calendar2.set(Calendar.DAY_OF_MONTH, 1);
> > 
> >     calendar2.clear(Calendar.HOUR);
> 
> Better: 'calendar2.set(Calendar.HOUR, 0);'

Can I impose on you to amplify further? Is this related to "the 
resolution rule for the time of day," mentioned in clear(int)?

<http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#time_resolution>
<http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear(int)>

> >     calendar2.clear(Calendar.MINUTE);
> >     calendar2.clear(Calendar.SECOND);
> >     calendar2.clear(Calendar.MILLISECOND);
> > 
> >     System.out.println(calendar2.getTimeInMillis()); // 0
> > }

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

[toc] | [prev] | [next] | [standalone]


#18601

FromLew <lewbloch@gmail.com>
Date2012-09-07 18:44 -0700
Message-ID<816d0737-3c2e-476a-9a56-41a13964fe5a@googlegroups.com>
In reply to#18599
John B. Matthews wrote:
> Lew wrote:
>>  John B. Matthews wrote:
>>> Ulrich Scholz  wrote:
> 
> [Valuable clarifications elided.]
> 
>>>     calendar2.set(Calendar.YEAR, 1970);
>>>     calendar2.set(Calendar.MONTH, Calendar.JANUARY);
>>>     calendar2.set(Calendar.DAY_OF_MONTH, 1);
>>> 
>>>     calendar2.clear(Calendar.HOUR);
>> 
>> Better: 'calendar2.set(Calendar.HOUR, 0);'
> 
> Can I impose on you to amplify further? Is this related to "the 
> resolution rule for the time of day," mentioned in clear(int)?
> 
> <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#time_resolution>
> <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear(int)>

I guess, but that's not my focus. My focus is on the fact that when you 'clear(int)', as opposed
to 'set(int,int)', the 'Calendar' instance does no reconciliation, nor can you rely on any specific 
field value such as '0'. 'clear()' sets fields to *undefined*, not a specific value. It makes no 
attempt to reconcile field values, e.g., to set a day to a valid value based on the month value
or vice versa.

So you have no promise as to what the values are after a 'clear()'. What comes out might well
surprise, as it did on that project some years ago where I encountered this situation.

-- 
Lew

[toc] | [prev] | [next] | [standalone]


#18606

From"John B. Matthews" <nospam@nospam.invalid>
Date2012-09-08 09:12 -0400
Message-ID<nospam-F9122E.09121908092012@news.aioe.org>
In reply to#18601
In article <816d0737-3c2e-476a-9a56-41a13964fe5a@googlegroups.com>,
 Lew <lewbloch@gmail.com> wrote:

> John B. Matthews wrote:
> > Lew wrote:
> >>  John B. Matthews wrote:
> >>> Ulrich Scholz  wrote:
> > 
> > [Valuable clarifications elided.]
> > 
> >>>   calendar2.set(Calendar.YEAR, 1970);
> >>>   calendar2.set(Calendar.MONTH, Calendar.JANUARY);
> >>>   calendar2.set(Calendar.DAY_OF_MONTH, 1);
> >>>
> >>>   calendar2.clear(Calendar.HOUR);
> >> 
> >> Better: 'calendar2.set(Calendar.HOUR, 0);'
> > 
> > Can I impose on you to amplify further? Is this related to "the 
> > resolution rule for the time of day," mentioned in clear(int)?
> > 
> > <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#time_resolution>
> > <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear(int)> > >
> 
> I guess, but that's not my focus. My focus is on the fact that when 
> you 'clear(int)', as opposed to 'set(int,int)', the 'Calendar' 
> instance does no reconciliation, nor can you rely on any specific 
> field value such as '0'. 'clear()' sets fields to *undefined*, not a 
> specific value. It makes no attempt to reconcile field values, e.g., 
> to set a day to a valid value based on the month value or vice versa.
> 
> So you have no promise as to what the values are after a 'clear()'. 
> What comes out might well surprise, as it did on that project some 
> years ago where I encountered this situation.

Hard fought, well remembered; thanks for elaborating.

Looking closer, I see that the resulting default value is reliable for 
a particular concrete Calendar. For example, GregorianCalendar, Default 
Fields Values:

<http://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html>

A potential problem is that Calendar.getInstance(TimeZone zone, 
Locale aLocale) may return an instance of a class with different 
defaults.

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>

[toc] | [prev] | [next] | [standalone]


#18607

FromLew <lewbloch@gmail.com>
Date2012-09-08 16:51 -0700
Message-ID<9840a88b-f9e3-410a-881a-63181f6887ac@googlegroups.com>
In reply to#18606
John B. Matthews wrote:
>  Lew wrote:
>> John B. Matthews wrote:
>>> Lew wrote:
>>>>  John B. Matthews wrote:
>>>>> Ulrich Scholz  wrote:
>>> [Valuable clarifications elided.]
> 
>>>>>   calendar2.set(Calendar.YEAR, 1970);
>>>>>   calendar2.set(Calendar.MONTH, Calendar.JANUARY);
>>>>>   calendar2.set(Calendar.DAY_OF_MONTH, 1);
>>>>>
>>>>>   calendar2.clear(Calendar.HOUR);
>>>> 
>>>> Better: 'calendar2.set(Calendar.HOUR, 0);'
>>> 
>>> Can I impose on you to amplify further? Is this related to "the 
>>> resolution rule for the time of day," mentioned in clear(int)?
> <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#time_resolution>
> <http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#clear(int)> > 
>> I guess, but that's not my focus. My focus is on the fact that when 
>> you 'clear(int)', as opposed to 'set(int,int)', the 'Calendar' 
>> instance does no reconciliation, nor can you rely on any specific 
>> field value such as '0'. 'clear()' sets fields to *undefined*, not a 
>> specific value. It makes no attempt to reconcile field values, e.g., 
>> to set a day to a valid value based on the month value or vice versa.
>> 
>> So you have no promise as to what the values are after a 'clear()'. 
>> What comes out might well surprise, as it did on that project some 
>> years ago where I encountered this situation.
> 
> Hard fought, well remembered; thanks for elaborating.
> 
> Looking closer, I see that the resulting default value is reliable for 
> a particular concrete Calendar. For example, GregorianCalendar, Default 
> Fields Values:
> 
> <http://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html>
> 
> A potential problem is that Calendar.getInstance(TimeZone zone, 
> Locale aLocale) may return an instance of a class with different 
> defaults.

'GregorianCalendar' was the concrete class that had problems in the 
real-world system where I encountered the risks of 'clear()'.

It's not enough that the class returns default values for undefined 
fields. 'clear()' does not invoke the reconciliation of different 
fields with each other that lenient instances seek. So if you 'clear()' 
some of the fields, you might end up with, say, a 'DAY_OF_WEEK' not 
consistent with the 'DAY_OF_MONTH'. 

I don't recall the exact details of the bug I saw, but it was along 
those lines. It might have messed up a Daylight Saving calculation, 
or maybe it was the consistency between fields - it's been about six 
years and I don't remember. I do distinctly remember the "Eureka" that 
the problem was the use of 'clear()' instead of 'set(field, 0)'.

-- 
Lew

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web