Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4290274
Votes 62
Synopsis (timer) java.util.Timer.scheduleAtFixedRate() fails if the system time is changed
Category java:classes_util
Reported Against 1.3.1 , kestrel , 1.4.2_01
Release Fixed
State 6-Fix Understood, bug
Priority: 3-Medium
Related Bugs 6502508 , 6779573 , 5056533
Submit Date 11-NOV-1999
Description
==per the spec of scheduleAtFixedRate():

"It is also appropriate for for recurring activities where the total 
time to perform a fixed number of executions is important, such as 
a countdown timer that ticks once every second for ten seconds."

This breaks if the system time is changed.

For example, 

- a timer task is scheduled to repeat every 30 seconds 

        final long PERIOD = 30 * 1000;    // milliseconds
        Timer tm =  new Timer();
        Date current_date = new Date() ;
        tm.scheduleAtFixedRate(task1, 
			       current_date,
			       PERIOD) ;
        
- then the system clock is changed (let's say, it's set back 1 minute)

Expected: task1 is fired every 30 seconds

Actual  : task1 is not fired for 1 minute.
	  (while the system clock is < current_date).
	  Two executions are missed.

Similarly, two extra executions are fired (unexpectedly) when the system clock
is set ahead one minute after the task is scheduled using scheduleAtFixedRate().







C:\JBuilder4\jdk1.3\bin>java -version
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

After a swing timer is started and before that timer is expired, a software
tester changes the system time of the local host, say, delay the current system
time by one day.  The timer also delays its expiration time for a day.

We dont expect the timer be delayed eventhough the current system time is
delayed by a significant amount of time.  We also do not expect the timer
behave different if the current system time is set forward.

I have looked at the swing Timer.java and TimerQueue.java classes, and the
TimerQueue.java has a run() method and that calls postExpiredTimers() method.
The postExpiredTimers() method calls the System.currentTimeMillis() to update
the timeToWaitvariable, that is the problem.  Because TimerQueue has default
access modifier, I cannot extend it and hence I cannot override the above
two methods.  I would appreciate if you could fix this problem so that
the Timer always fires ActionEvent as long as the predefined timeout comes
to an end.  Don't let the system time change to affect the timer's behavior.

Regards,
Lee Zhou
Waterford Institute
  xxxxx@xxxxx  
(Review ID: 126004)
======================================================================




D:\>java -version
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)

This behavior also happens in JDK1.4beta3.

/**
 * class TimerTest
 *
 * Class used to demonstrate failure of the javax.swing.Timer after the system
 * clock has been set back.
 *
 * Steps to demonstrate bug:
 *
 * 1. Start this program running by calling its main( )
 * 2. A Frame will come up that shows the current time in a JLabel.
 *    Note that the text of the JLabel is updated every second by
 *    a swing timer.
 * 3. While the program is up and running, set the system clock back, for
 *    example set the computer's clock back by one hour. Now notice that
 *    the time is no longer being updated. That is, the op sys clock continues
 *    to run and update itself, but the time read out in the java JLabel
 *    is no longer updating.
 *
 * NOTE: I have also tried 1.4beta3 and still the same results.
 *
 * @author hill
 * Date: Nov 15, 2001
 * Time: 1:52:06 PM
 */
package timertest;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Calendar;

public class TimerTest extends JLabel
{
    private       SimpleDateFormat dateFormat      = null;
    private       TimeZone         defaultTimeZone = null;
    private       Calendar         calendar        = null;
    private final String           EMPTY_STRING     = "  ";
    private       Timer            timer           = null;

    TimerTest( )
    {
        super( );
        setHorizontalAlignment(SwingConstants.CENTER);
        setText(EMPTY_STRING);
        setPreferredSize(new Dimension(400, 200));
        setMinimumSize(new Dimension(400, 200));
        defaultTimeZone = TimeZone.getDefault( );
        timer = new TimerTest.TimeLabelTimer( );
        timer.start( );
    }

    /**
     * Timer class that is called back at intervals to adjust the
     * seconds in time display
     */
    private class TimeLabelTimer extends Timer implements ActionListener
    {
        private final String           TIME_FORMAT     = " HH:mm:ss ";
        private       SimpleDateFormat timeFormat      = null;

        TimeLabelTimer( )
        {
            // first param is callback interval in milliseconds
            super(1000, null);   // call back every second
            addActionListener(this);

            timeFormat      = new SimpleDateFormat(TIME_FORMAT);
            timeFormat.setTimeZone(defaultTimeZone);
        }

        /**
         * update the time display
         */
        public void actionPerformed(ActionEvent e)
        {
            calendar = Calendar.getInstance(defaultTimeZone);
            setText(timeFormat.format(calendar.getTime( )));
        }
    }

    public static void main(String[ ] args)
    {
        JFrame frame = new JFrame("Test Timer");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane( ).add(new TimerTest( ), BorderLayout.CENTER);
        frame.setSize(400, 200);
        frame.pack( );
        frame.setVisible(true);
    }
}
(Review ID: 135746)
==========================================================================================================================================



Remove SQE-lib-0121


======================================================================




(Review ID: 126004)
======================================================================




Webbugs Review <--------------------------

The users test case shows his error as expected. When changing the 
system clock, the java application froze. I have tested this test case
on Win NT and Win 2k using 1.3.1, 1.3.1,  1.4beta3 and 1.4-rc-b87

  xxxxx@xxxxx    2001-11-30
(Review ID: 135746)
======================================================================
JPE modified 

Add  xxxxx  in Customer Call section

  xxxxx@xxxxx   2003-10-07
=====================================================================
JPE Modified 

Add Yokogawa another entry. thi occurs in Tiger.

java version "1.5.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta-b22)
Java HotSpot(TM) Client VM (build 1.5.0-beta-b22, mixed mode)

The licensee's Java product is to monitor the status of product line
in Factory and display clock.
To synchronize the monitor(clientPC) clock with the machine in the line, 
the system clock is adjusted periodically. 
After this synchronization, the clock seems to stop by this bug.

They want us to fix in Tiger and backport the fix into 1.4.X.

  xxxxx@xxxxx   2003-10-08
=====================================================================
  xxxxx@xxxxx   11/1/04 23:01 GMT
Work Around
N/A
Evaluation
Thanks to JSR-166, it is now practical to fix this bug on most (if not all) platforms.  The new System.nanoTime() method provides precisely the required  functionality. It is not, however, sufficient to use a single queue based on relative time (as returned by System.nanoTime):  This approach does not provide accurate absolute-time events.  It is currently possible to use Timer to write a "personal information manager" that schedules events far in the future.  If we switched to a single queue based on relative time, such an application would break.

Simply put, it is required that:
 - Absolute times must track changes to the system clock.
 - Relative times must be impervious to changes in the system clock.

The solution is to maintain two priority queues, one indexed by "absolute time" (currentTimeMillis), the other indexed by nanoTime.  When an event is scheduled with an absolute time, put it in the former queue; when it's scheduled without an absolute time put it in the latter queue.  Whenever a periodic event is scheduled for its second or subsequent execution, put it into the latter queue.  (The intuition is that all such events are scheduled by relative time, even if the first event in the sequence was scheduled by absolute time.)  A single thread monitors both queues.  When it waits, it waits for the minimum time indicated by the head element of both queues.  This dual-queue approach provides reliable periodic events and absolute-time events.

To answer scheduledExecutionTime queries, it must be possible to tell by looking at a TimerTask which queue it is on (to properly interpret the long nextExecutionTime field.  (Recall that timer tasks have no link back to their timers.)  This means that we have to steal a bit somewhere.  Luckily TimerTask has a 32-bit state field, of which two bits are currently in use.

A minor deficiency of this implementation is that if the "absolute time" clock is set far backwards and the previous wait of the timer thread was for an event on the former (currentTimeMillis) queue, the Timer thread will oversleep and execute the event late by the amount that the clock was set back.  The solution to this (which I'm not sure is worth implementing) is to use a slightly more complex algorithm to calculate the wait timeout. Instead of min(currentTimeMillis - head of  absolute time queue, nanoTime - head of relative time queue), wait for min(min(currentTimeMillis - head of absolute time queue, SOME_CONSTANT), nanoTime - head of relative time queue).  In other words, never wait longer than SOME_CONSTANT for an "absolute time" event.  This bounds the tardiness in the face of arbitrary clock setbacks.  (The bound need not be applied if there are no tasks on the absolute time queue.)

Unfortunately, this fix requires a slight change to the semantics of certain methods.  The current API specifies what constitutes legal delays and periods in terms of System.currentTimeMillis.  This would have to be changed in order to adopt the above implementation strategy.  It wouldn't break any real applications (which tend not to schedule events 200 years in the future), but might break some test code.

  xxxxx@xxxxx   2004-04-13
Posted Date : 2006-07-12 20:29:34.0
Comments
  
  Include a link with my name & email   

Submitted On 01-MAR-2001
ldlowe
This is far worse than &quot;suboptimal&quot; if we are going to 
provide industrial apps written in Java. I'm 26,000 lines 
into an application, only to find that updates via an NTP 
client to my OS clock are stopping my application's clock 
from updating. The best I can figure is that I'm going to 
have to provide my clock timer through native code. This is 
an ugly solution to what should never have been a problem.


Submitted On 02-MAR-2001
ldlowe
Please ignore the prior comment. When the hour is late, the 
midnight oil well and truly burned, the deadlines looming, 
and the last two hours were spent chasing why your app 
just &quot;unexplicably&quot; stops for no reason, the tempers do 
flare. After a well needed rest, the unsolvable turns 
trivial, as it nearly always does. For those of you trapped 
in a fatigue-induced delirium as I was, your problem is 
solved by the Thread.sleep() method. It would still be nice 
to have this fixed, however.


Submitted On 26-OCT-2001
IBeaumont
So when clocks change back from Summer time (BST) and move 
back an hour - my application will stop scheduling tasks 
correctly.
Hardly a solution for industrial strength software.


Submitted On 16-APR-2002
jlscott3
I agree with IBeaumont - daylight savings time breaks the 
intended (or at least my desired) functionality of the 
Timer class. There's no way to schedule a task to execute 
at a specific time each day using Timer. Going to or from 
DST will result in execution at the wrong time.


Submitted On 16-MAY-2002
manihss
Can a System.elapsedTimeMillis () be made available ??


Submitted On 22-NOV-2002
georgvs
It's truly unelegant. I would assume that many programmers 
have had an issue with this. Elegant solutions are needed, 
whether they be custom monitors or listeners on the threads 
or other API. 


Submitted On 22-SEP-2003
kuehmel
I am using <code>scheduleAtFixedRate(TimerTask task, Date 
firstTime, long period)</code> for a recurrent task once a day 
(jdk 1.3.0). 

It works very vell, if <code>firstTime</code> is in future 
when invoking <code>scheduleAtFixedRate</code>. The run-
methode of the task is called once a day at 9 o'clock.

But when it happens that <code>firstTime</code> lays in the 
past, when scheduling the task, then the run-method of the 
task is called again and again (about 2 times a second).

My workaround is to check the date. If it is in the past, set 
the day one day ahead.  So it works fine.


Submitted On 02-SEP-2004
langfors
We are developing an 'appliance' type product which uses an appserver and has a gui.  One of the features of this appliance is the ability to set the time and timezone of the device via the gui.  Needless to say this causes all kinds of havoc as timers are used everywhere, in our code and in the application server's code.   We're looking forward to this fix.


Submitted On 20-JUN-2005
CypherJF
This appears to still exist in 

java version "1.5.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode, sharing)

Windows platform.


Submitted On 03-MAY-2006
g8julieh
This appears to still exist in 
JDK1.5.0_06


Submitted On 16-MAR-2007
yovn
Here is a way to fix it:http://yovn.spaces.live.com/blog/cns!D38F6783B957A08A!164.entry


Submitted On 25-MAY-2007
Can we have another method to cater  for system change time; for example if the summar time starts and the clock is moved back one hour, there should be  an interface which gets a call back from the JVM to inform about new dates and any running timer  which implement this interface will get notified to take appropriate actions.  There should be a spec changes 


Submitted On 25-MAY-2007
Can we have another method to cater  for system time change; for example if the summar time starts and the clock is moved back one hour, there should be  an interface which gets a call back from the JVM to inform about new datetime so that any running timer  which implements this interface will get notified to take appropriate actions.  There should be a spec changes   to take into consideration the system time change in relation to the scheduled activities on the sytem.

Regards,
Alan Mehio
London, UK


Submitted On 11-AUG-2007
Since anything based on System.currentTimeMillis() is subject to such issues and System.nanoTime() is substantively more expensive, it would seem like there are grounds for simply using a different API if this is a concern.

To that end, do ScheduledExecutorService implementations have this issue?  If not, why not use them instead?


Submitted On 21-AUG-2007
backstabb
Date starting_date = new Date() ;
...
Date current_date = new Date() ;
if (current_date.before( starting_date_)
  setSomethingIsWrongFlag(true);


Submitted On 01-OCT-2007
daylight saving has nothing to do with the bug.


Submitted On 06-APR-2008
desd1012
We too have an appliance that can let the user set time. Let me tell you this: there is so many loops, timer and code that is absolute-time dependant, that we decided to stop all of them when a user (or NTP) changes the time by more than X seconds. This is an application-wide constraint, and the entire design has to factor in time shifts.

Guy, not only timers are affected. Think about your rolling data, the timestamps in it, and how you have to react to gaps of time (shifting in future) or overlapping system time (shifting in past).... This nightmare is my life since 2003...

It usually ends up in release notes as a limitation of the software. All we can do is have a consistent, coherent, homogen behavior when facing time shifts. Good luck.

We even though of putting some new concept of 'age' provider API; a method that would guaranty a monotonically ascending long value, like the above suggested System.elapsedTime(). That's a start. But we wanted more than the 'age' of the JVM, we wanted the 'age' of the computer, or at least the age of the software installation.



PLEASE NOTE: JDK6 is formerly known as Project Mustang