Datefield value changes on it's own

I am currenly using version 7.2.4 of the Vaadin framework and I am having an interesting problem with the date field.

I have two date fields on the screen, basically a start date and end date. The resolution for both fields are set to Month and the format for both fields is “MMM yyyy”, just in case that make a difference. The code below is setup to first set the start date to a default value and then based on the value of the start fields, if necessary change the value of the end date. It also set the date start range and end range.

    private void setBaseDates() {
        if (this.df_BaseStart.getValue() == null) {
            Calendar now = Calendar.getInstance();
            
            Date start = SMSUtilities.genDate(now.get(Calendar.YEAR), (now.get(Calendar.MONTH)), 1);
            
            this.df_BaseStart.setValue(start);            
        }
        
        Date min = SMSUtilities.incrementDate(this.df_BaseStart.getValue(), TU.MONTH,1);
        Date max = SMSUtilities.incrementDate(this.df_BaseStart.getValue(), TU.MONTH, 13);
        
        if (this.df_BaseEnd.getValue() == null || this.df_BaseEnd.getValue().compareTo(min) < 0 || this.df_BaseEnd.getValue().compareTo(max) > 0) {
            this.df_BaseEnd.setValue(min);
        }
        
        this.df_BaseEnd.setRangeStart(min);
        this.df_BaseEnd.setRangeEnd(max);        
    }

But a few seconds after my code runs, the end date value is changed by something outside of my code. Below is the stack trace that I captured by putting a change trigger on the end date field. It seem to be set to todays date from what I can tell. Below is the stack trace I captured when the value change.

ProdSalesAnalysis$8.valueChange(Property$ValueChangeEvent) line: 321    
GeneratedMethodAccessor36.invoke(Object, Object[]) line: not available    
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available    
Method.invoke(Object, Object...) line: not available    
ListenerMethod.receiveEvent(EventObject) line: 508    
EventRouter.fireEvent(EventObject, ErrorHandler) line: 198    
EventRouter.fireEvent(EventObject) line: 161    
PopupDateField(AbstractClientConnector).fireEvent(EventObject) line: 984    
PopupDateField(AbstractField<T>).fireValueChange(boolean) line: 1131    
PopupDateField(AbstractField<T>).setValue(T, boolean) line: 542    
PopupDateField(DateField).setValue(Date, boolean) line: 678    
PopupDateField(DateField).changeVariables(Object, Map<String,Object>) line: 587    
ServerRpcHandler.changeVariables(Object, VariableOwner, Map<String,Object>) line: 471    
ServerRpcHandler.handleInvocations(UI, int, JSONArray) line: 289    
ServerRpcHandler.handleRpc(UI, Reader, VaadinRequest) line: 168    
UidlRequestHandler.synchronizedHandleRequest(VaadinSession, VaadinRequest, VaadinResponse) line: 93    
UidlRequestHandler(SynchronizedRequestHandler).handleRequest(VaadinSession, VaadinRequest, VaadinResponse) line: 41    
VaadinServletService(VaadinService).handleRequest(VaadinRequest, VaadinResponse) line: 1405    
VaadinServlet.service(HttpServletRequest, HttpServletResponse) line: 237    
VaadinServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 728    
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 305    
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210    
StandardWrapperValve.invoke(Request, Response) line: 222    
StandardContextValve.invoke(Request, Response) line: 123    
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472    
StandardHostValve.invoke(Request, Response) line: 171    
ErrorReportValve.invoke(Request, Response) line: 99    
AccessLogValve.invoke(Request, Response) line: 953    
StandardEngineValve.invoke(Request, Response) line: 118    
CoyoteAdapter.service(Request, Response) line: 408    
Http11Processor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1023    
Http11Protocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 589    
JIoEndpoint$SocketProcessor.run() line: 312    
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: not available    
ThreadPoolExecutor$Worker.run() line: not available    
TaskThread(Thread).run() line: not available   

Can any one point me to what might be going on and how I can resolve the problem?

“It seem to be set to todays date from what I can tell.” - So the resolution is changed back to “Day”? If not, and you mean it is set to current month and year, as long as df_BaseStart is null i think it is correct that df_BaseEnd is set to current month and year (unless SMSUtilities does something different what i think…)

Because you use a third party lib i can’t try your code but following code runs without a problem for me:

DateField start = new DateField("Start");
DateField end = new DateField("End");

start.setResolution(Resolution.MONTH);
end.setResolution(Resolution.MONTH);

start.setValue(new Date(System.currentTimeMillis()));
        
Date min = new Date(System.currentTimeMillis());
Date max = new Date(System.currentTimeMillis() + 9876543210l);
        
end.setValue(min);
        
end.setRangeStart(min);
end.setRangeEnd(max);

If you need more help, you have to remove SMSUtilities from your code (and verify that the problem still exists) so that i can test it and give me further information, eg when is setBaseDates() called.

The code in the SMSUtilities that is being called is below: As you propullay surmised it is just creating a new date value based on the inputted parameters and is not effecting the date field directly.

    /**
     * Creates a date at midnight
     * @param year
     * @param month
     * @param day
     * @return
     */
    public static Date genDate(Integer year, Integer month, Integer day) {
        return genDate(year,month,day,0,0,0);
    }
    /**
     * Creates a date with the specified values and returns it
     * @param year
     * @param month
     * @param day
     * @param hour
     * @param min
     * @param sec
     * @return
     */
    public static Date genDate(Integer year, Integer month, Integer day, Integer hour, Integer min, Integer sec) {
        Calendar cal = new GregorianCalendar(year, month, day, hour, min, sec);
        return cal.getTime();
    }

    /**
     * Increments the supplied date value by the unit and amount
     *     specified.
     *
     * @param date
     * @param unit
     * @param amount
     * @return
     */
    public static Date incrementDate(Date date,TU unit, Integer amount) {
        Calendar workDate = Calendar.getInstance();
        workDate.setTime(date);
        
        switch (unit) {
            case YEAR:
                workDate.add(Calendar.YEAR, amount);
                break;
            case MONTH:
                workDate.add(Calendar.MONTH, amount);
                break;
            case DAY:
                workDate.add(Calendar.DATE, amount);
                break;
            case HOUR:
                workDate.add(Calendar.HOUR, amount);
                break;
            case MINUTE:
                workDate.add(Calendar.MINUTE, amount);
                break;
            case SECOND:
                workDate.add(Calendar.SECOND, amount);
                break;
            case MILLISECOND:
                workDate.add(Calendar.MILLISECOND, amount);
                break;
                
        }
        
        return workDate.getTime();

For some reason after the ValueChangeListener on the “df_BaseStart” calls setBaseDate(), about 30 seconds later something in the background resets the value of “df_BaseEnd”. Basically the flow that happens is as follows:

  1. User inputs a date into “df_BaseEnd”
  2. The ValueChangeListener on “df_BaseEnd” calls “setBaseDate”
  3. “setBaseDate” reset the value of “df_BaseEnd” and the correct value is shown on the screen.
  4. “setBaseDate” exits and about 30 seconds later the value in “df_BaseEnd” is reset to “May 01 2015”

I removed the calls to SMSUtilities and now the “setBaseDate” section of code looks like the following:

    private void setBaseDates() {
        if (this.df_BaseStart.getValue() == null) {
            Calendar now = Calendar.getInstance();
            
//            Date start = SMSUtilities.genDate(now.get(Calendar.YEAR), (now.get(Calendar.MONTH)), 1);
    
            Date start = new Date();
            
            this.df_BaseStart.setValue(start);            
        }
        
//        Date min = SMSUtilities.incrementDate(this.df_BaseStart.getValue(), TU.MONTH,1);
//        Date max = SMSUtilities.incrementDate(this.df_BaseStart.getValue(), TU.MONTH, 13);
        
        Date min = new Date(this.df_BaseStart.getValue().getTime() + 4938271605l);
        Date max = new Date(min.getTime() + 9876543210l);
        
        if (this.df_BaseEnd.getValue() == null || this.df_BaseEnd.getValue().compareTo(min) < 0 || this.df_BaseEnd.getValue().compareTo(max) > 0) {
            this.df_BaseEnd.setValue(min);
        }
        
        this.df_BaseEnd.setRangeStart(min);
        this.df_BaseEnd.setRangeEnd(max);        
   

From what I can tell something in the background is being triggered after the ValueChangeEvent on “df_BaseDate” end that is reseting the value of “df_EndDate”, and it is only being triggered when the user inputts a value in “df_BaseDate”. It does not happen when I set the value to initilize the screen, like you are showing in your code sample.

Is the Listener on BaseStart or BaseEnd (or both)?

Do you mean df_BaseStart with df_BaseDate?

Assuming the listener is on df-BaseStart and df_BaseDate is df_BaseStart i tried the following code:

[code]
public class DateRangeTestUI extends UI {

private DateField start;
private DateField end;

@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = DateRangeTestUI.class)
public static class Servlet extends VaadinServlet {
}

@Override
protected void init(VaadinRequest request) {
    
    start = new DateField("Start");
    end = new DateField("End");
    
    start.setResolution(Resolution.MONTH);
    end.setResolution(Resolution.MONTH);
    
    start.setImmediate(true);
    end.setImmediate(true);
    
    start.addValueChangeListener(new ValueChangeListener() {
        
        @Override
        public void valueChange(ValueChangeEvent event) {
            setBaseDates();
        }
    });
    
    setContent(new VerticalLayout(start,end));
}

private void setBaseDates() {
    if (this.start.getValue() == null) {
        Date start = new Date();
        this.start.setValue(start);            
    }
    
    Date min = new Date(this.start.getValue().getTime() + 4938271605l);
    Date max = new Date(min.getTime() + 9876543210l);
    
    if (this.end.getValue() == null || this.end.getValue().compareTo(min) < 0 || this.end.getValue().compareTo(max) > 0) {
        this.end.setValue(min);
    }
    
    // prevent IllegalStateException if 'start' is changed to something after 'end'
    this.end.setRangeEnd(null);
    this.end.setRangeStart(null);
    
    this.end.setRangeStart(min);
    this.end.setRangeEnd(max);
}

}
[/code]Works like expected. I don’t have the problem you are describing.
So i think the error is somewhere in your environment. Try the UI (in a fesh clean Vaadin project without any addons etc…) i posted and look if the problem still occurs.

I found the issue. Because of other functions in my application, in my UI file I set the polling interval. That seems to be what is causing the date field to update it’s value. Attached is a project that duplicates the problem.
19217.zip (12.4 KB)

Nope, your test-project works without any problems for me… I changed the end date and nothing changes it in the background. What Application-Server are you using? Wich JVM?

Also, if i only change start date, end date is adjusted and stays as it is…

I am using Java 7 update 45, but the project compiler compliance level is set to 1.6. I am not sure what you mean by Application-Server, but it is running on Tomcat 7.0.

Ok i was able to reproduce your problem, it only occurs when you change start date and did not change end date before (as i did in my previous test). I will have a look at it now

Thank you.

Congratulations, you found a bug :slight_smile: In fact it only occurs when you set the Resolution of end date to month, if set to day, the problem does not occur. It is a client side bug as i can tell.


Please fill out a bug report, so the developers can fix it!

I have not found a quick workaround other than leave end date at day resolution (you can leave the MM YYYY pattern so it will at least look the same, allthough the date chooser will be at day resolution) but maybe using server push instead of client poll will help…
You can also set a debug breakpoint in changeVariables in DateField, then you will see, that on client poll, a wrong/the current date comes from the client.
The problem does not occur if the user just opened and closed the date chooser of end date (without choosing a date). So it looks like some client side initialization problem of the date field component.

If i have some more time tomorrow i will give it another look, im quite tired atm :wink: Maybe i’ll find another workaround.

Thank you for the help. Here is the ticket for the bug, in case you want to add any further comments.
https://dev.vaadin.com/ticket/17908

Thank you again.

You’r welcome

Just found out, that the date range is also necessary to cause the bug. I updated your ticket.