ObjectDB ObjectDB

Wrong data stored in time only fields

#1

This may be related to the fix for the problem described in this thread: Wrong data stored in date only fields.

The object and its date and time fields are the same as in the referenced thread. Except we are using ObjectDB 2.6.4_08, the system time zone is set to EST and both the OS and JVM are using the 2015g time zone data.

While we cannot see a problem with date only fields (more testing pending) now it appears that there is a problem with time only fields. The issue appears at random and in 100K records it will show up in about 1.5K records with no obvious pattern. Also it appears that it happens for some time zones only - we provide example with the EST time zone.

The attached DB has 9 records and as you can see the startTime parameter is set to "31 Dec 1969 hh:mm:ss" when it should be set to "01 Jan 1970 hh:mm:ss". Usually the value is wrong by 24 hours, but see further explanation of some odd values below.

Here is the data used to create the 9 records:

2015-12-19 18:12:53,000 INFO [Thread-26] - ---
2015-12-19 18:12:53,015 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 20:46:28 EST 2015
2015-12-19 18:12:53,016 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,016 INFO [Thread-26] - RMD.startTime=Thu Jan 01 20:46:28 EST 1970
2015-12-19 18:12:53,029 INFO [Thread-26] - ---
2015-12-19 18:12:53,030 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 20:50:05 EST 2015
2015-12-19 18:12:53,031 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,031 INFO [Thread-26] - RMD.startTime=Thu Jan 01 20:50:05 EST 1970
2015-12-19 18:12:53,033 INFO [Thread-26] - ---
2015-12-19 18:12:53,033 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 20:41:37 EST 2015
2015-12-19 18:12:53,034 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,035 INFO [Thread-26] - RMD.startTime=Thu Jan 01 20:41:37 EST 1970
2015-12-19 18:12:53,036 INFO [Thread-26] - ---
2015-12-19 18:12:53,037 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 18:59:58 EST 2015
2015-12-19 18:12:53,037 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,038 INFO [Thread-26] - RMD.startTime=Thu Jan 01 18:59:58 EST 1970
2015-12-19 18:12:53,040 INFO [Thread-26] - ---
2015-12-19 18:12:53,040 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 21:24:58 EST 2015
2015-12-19 18:12:53,041 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,042 INFO [Thread-26] - RMD.startTime=Thu Jan 01 21:24:58 EST 1970
2015-12-19 18:12:53,043 INFO [Thread-26] - ---
2015-12-19 18:12:53,044 INFO [Thread-26] - RMD.startDateTime=Wed Dec 09 21:26:19 EST 2015
2015-12-19 18:12:53,045 INFO [Thread-26] - RMD.startDate=Wed Dec 09 12:00:00 EST 2015
2015-12-19 18:12:53,046 INFO [Thread-26] - RMD.startTime=Thu Jan 01 21:26:19 EST 1970
2015-12-19 18:12:53,047 INFO [Thread-26] - ---
2015-12-19 18:12:53,048 INFO [Thread-26] - RMD.startDateTime=Fri Dec 11 23:55:07 EST 2015
2015-12-19 18:12:53,049 INFO [Thread-26] - RMD.startDate=Fri Dec 11 12:00:00 EST 2015
2015-12-19 18:12:53,050 INFO [Thread-26] - RMD.startTime=Thu Jan 01 23:55:07 EST 1970
2015-12-19 18:12:53,051 INFO [Thread-26] - ---
2015-12-19 18:12:53,052 INFO [Thread-26] - RMD.startDateTime=Tue Dec 08 18:59:57 EST 2015
2015-12-19 18:12:53,052 INFO [Thread-26] - RMD.startDate=Tue Dec 08 12:00:00 EST 2015
2015-12-19 18:12:53,053 INFO [Thread-26] - RMD.startTime=Thu Jan 01 18:59:57 EST 1970
2015-12-19 18:12:53,055 INFO [Thread-26] - ---
2015-12-19 18:12:53,055 INFO [Thread-26] - RMD.startDateTime=Fri Oct 30 18:18:14 EDT 2015
2015-12-19 18:12:53,056 INFO [Thread-26] - RMD.startDate=Fri Oct 30 12:00:00 EDT 2015
2015-12-19 18:12:53,057 INFO [Thread-26] - RMD.startTime=Thu Jan 01 18:18:14 EST 1970


We can reproduce the problem reliably with the above data.

Also, note the difference in the value of startTime in record 0 and 8. For 0 the input is "Thu Jan 01 20:46:28 EST 1970" while the data in the DB is "Wed Dec 31 20:46:28 EST 1969", i.e the error is exactly 1 day behind.

For record 8 the input is "Thu Jan 01 18:18:14 EST 1970" while the data in the DB is "Wed Dec 31 19:42:01 EST 1969", which is a very odd value.

 

Emil

edit
delete
#2

An update, we did a quick test with 2.6.4_10. It has the same problem.

edit
delete
#3

If you can reproduce the issue it would help if you could post a small console test application that persists an entity with a time only field and then retrieves it in an unexpected state.

ObjectDB Support
edit
delete
#4

Here it is:

package test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

public class DateTimeTest {
   
    public static void main(String[] args)  {
        //TimeZone.setDefault(TimeZone.getTimeZone("EST"));
        // Run this test case on a system with the EST time zone
        // both OS and JVM
       
        SimpleDateFormat dtf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
       
        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(
                "objectdb:$objectdb/deleteme/test.tmp;drop");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();
        // Add records that are a problem
        DateTime dt = null;
        try {
            dt = new DateTime(dtf.parse("2015.10.30 18:18:14"));
            em.persist(dt);
        }
        catch (ParseException e) {
            e.printStackTrace();
        }
       
        try {
            dt = new DateTime(dtf.parse("2015.12.09 21:26:19"));
            em.persist(dt);
        }
        catch (ParseException e) {
            e.printStackTrace();
        }

        // Add some good records
        try {
            dt = new DateTime(dtf.parse("2015.12.09 00:29:02"));
            em.persist(dt);
        }
        catch (ParseException e) {
            e.printStackTrace();
        }

        try {
            dt = new DateTime(dtf.parse("2015.12.16 17:24:09"));
            em.persist(dt);
        }
        catch (ParseException e) {
            e.printStackTrace();
        }

        em.getTransaction().commit();

        Query q = em.createQuery("SELECT COUNT(r) FROM DateTime AS r");
        Long r = (Long) q.getSingleResult();
       
        System.out.println("TOTAL RECORDS: " + r.longValue());
       
        q = em.createQuery("SELECT r from DateTime AS r  WHERE  (r.startTime < {t '00:00:00'})");
        List resultList = q.getResultList();
        if (resultList.size() > 0) {
            System.out.println("FAILED records " + resultList.size());
            System.out.println(resultList);
        }
       
        System.out.println("LIST OF RECORDS IN REVERESE TIME ORDER - WRONG (note 2015.12.09)");

        q = em.createQuery("SELECT r from DateTime AS r ORDER BY r.startDate DESC, r.startTime DESC");
        resultList = q.getResultList();
        Iterator itr = resultList.iterator();
        while (itr.hasNext()) {
            dt = (DateTime) itr.next();
            System.out.println(dt.getStartDateTime());
        }

        System.out.println("LIST OF RECORDS IN REVERESE TIME ORDER - CORRECT");

        q = em.createQuery("SELECT r from DateTime AS r ORDER BY r.startDateTime DESC");
        resultList = q.getResultList();
        itr = resultList.iterator();
        while (itr.hasNext()) {
            dt = (DateTime) itr.next();
            System.out.println(dt.getStartDateTime());
        }

        em.close();
        emf.close();
    }

    public static Date getTimeOf(Date date) {
        Date rondedDate = roundDownDateTime(date);
       
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(rondedDate);
       
        calendar.set(Calendar.YEAR, 1970);
        calendar.set(Calendar.MONTH, Calendar.JANUARY);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
       
        return calendar.getTime();
    }

    public static Date getDateOf(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
       
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR, 0);
       
        return calendar.getTime();
    }

    public static Date roundDownDateTime(Date dateTime) {
        long dateTimeMs = dateTime.getTime();
        long reminderMs  = dateTimeMs % 1000;
        dateTimeMs -= reminderMs;
        return new Date(dateTimeMs);
    }

    @Entity(name="DateTime")
    @SequenceGenerator(
        name="DateTime_sequence",
        sequenceName="DateTime_sequence",
        allocationSize=1
    )
    public static class DateTime {
        private Long id;
        private Long version;

        private Date startDateTime;     // Time stamp: start of recording in local time zone
        private Date startDate;         // Date: date part of startDateTime
        private Date startTime;         // Time: time part of startDateTime

        public DateTime(Date d) {
            setStartDateTime(new Date(d.getTime()));
            setStartDate(getDateOf(d));
            setStartTime(getTimeOf(d));
         }
       
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if ((o == null) || !(o instanceof DateTime)) {
                return false;
            }
            if (id == null) {
                return false;
            }

            DateTime other = (DateTime)o;
            return id.equals(other.getId()) && version.equals(other.getVersion());
        }

        public int hashCode() {
            if (id != null) {
                return id.hashCode();
            }
            else {
                return super.hashCode();
            }
        }
       
        @Id
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DateTime_sequence")
        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        @Version
        public Long getVersion() {
            return version;
        }

        public void setVersion(Long version) {
            this.version = version;
        }

        @Basic(optional = false)
        @Temporal(TemporalType.TIMESTAMP)
        public Date getStartDateTime() {
            return startDateTime;
        }

        public void setStartDateTime(Date startDateTime) {
            this.startDateTime = startDateTime;
        }

        @Basic(optional = false)
        @Temporal(TemporalType.DATE)
        public Date getStartDate() {
            return startDate;
        }

        public void setStartDate(Date startDate) {
            this.startDate = startDate;
        }

        @Basic(optional = false)
        @Temporal(TemporalType.TIME)
        public Date getStartTime() {
            return startTime;
        }

        public void setStartTime(Date startTime) {
            this.startTime = startTime;
        }
       
        @Override
        public String toString() {
            StringBuffer b = new StringBuffer();
            b.append("startDateTime=" + getStartDateTime() + "\n");
            b.append("startDate=" + getStartDate() + "\n");
            b.append("startTime=" + getStartTime() + "\n");
            return b.toString();
        }
    }

}

Emil

edit
delete
#5

Thank you for the test case. Please review build 2.6.4_12.

ObjectDB Support
edit
delete
#6

The issue is not present in 2.6.4_12.

Is the fix included in 2.6.5?

Emil

edit
delete
#7

Yes, it is included.

ObjectDB Support
edit
delete

Reply

To post on this website please sign in.