HOWTO: OleDate: Conversion Between DATE and java.util.Date

ID: Q169795


The information in this article applies to:


SUMMARY

OLE data type DATE is used in OLE to specify a date. It is typedefed as double in Visual C++. You can expose properties of type DATE from an automation object. When you create a wrapper class for the OLE object in Java using JavaTlb, DATE types are mapped to double. Java has a class that is used for specifying dates. It is lang.util.Date. However, these two types are not the same and there is no conversion function between them in Java. You can use the code in the MORE INFORMATION section to convert them.


MORE INFORMATION

The following code is copied from the Microsoft Foundation Classes included with Visual C++ version 4.21 and modified to work with Java and lang.util.Date. Copy the code to a file named OleDate.java and add it to your project. Include the following line to all your source files that use OleDate:


import OleDate; 
NOTE: The file name has to have the correct capitalization.

Sample Code


   // OleDate.java
   // 
   // Written by Sridhar S Madhugiri
   // of Microsoft Technical Support, Developer Support
   // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
   // 
   // this class extends Date to convert support Conversion from/to
   // OLE Data type DATE
   // 
   // OleData type DATE is actually represented as a double.
   // 
   // To convert from DATE to Date call the setDate(double) member.
   // This function does not do a lot of error checking about valid ranges.
   // It converts the value passed in to year, month, date, hour,
   // minute, second and calls the Date functions to set the values in
   // the object.
   // 
   // To convert from Date to DATE call toDouble() member. This returns
   // a double that has the date value in the correct format.
   // 

   import java.util.Date;
   import java.lang.Math;
   public class OleDate extends java.util.Date
   {

      public OleDate()
      {
         super();
      }
      public OleDate(int year, int month, int date)
      {
         super(year, month, date);
      }
      public OleDate(int year, int month, int date,
         int hrs, int min, int sec)
      {
         super(year, month, date, hrs, min, sec);
      }
      public OleDate(long date)
      {
         super(date);
      }

      public OleDate(String s)
      {
         super(s);
      }

      public OleDate(double date)
      {
         super();
         setDate(date);
      }

      // Source code copied from MFC 4.21 and modified

      // Half a second, expressed in days
      static double HALF_SECOND = (1.0/172800.0);
      public void setDate(double dtSrc)
      {

         // source code copied from MFC 4.21 and modified

         long nDays;         // Number of days since Dec. 30, 1899
         long nDaysAbsolute; // Number of days since 1/1/0
         long nSecsInDay;    // Time in seconds since midnight
         long nMinutesInDay; // Minutes in day
         long n400Years;     // Number of 400 year increments since 1/1/0
         long n400Century;   // Century within 400 year block (0,1,2 or 3)
         long n4Years;       // Number of 4 year increments since 1/1/0
         long n4Day;         // Day within 4 year block
                             //  (0 is 1/1/yr1, 1460 is 12/31/yr4)
         long n4Yr;          // Year within 4 year block (0,1,2 or 3)
         boolean bLeap4 = true; // TRUE if 4 year block includes leap year

         // values in terms of year month date.
         int tm_sec;
         int tm_min;
         int tm_hour;
         int tm_mday;
         int tm_mon;
         int tm_year;
         int tm_wday;
         int tm_yday;

         double dblDate = dtSrc; // temporary serial date

         // If a valid date, then this conversion should not overflow
         nDays = (long)dblDate;

         // Round to the second
         dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);

         // Add days from 1/1/0 to 12/30/1899
         nDaysAbsolute = (long)dblDate + 693959L;
         dblDate = Math.abs(dblDate);
         nSecsInDay = (long)((dblDate - Math.floor(dblDate)) * 86400.);

         // Leap years every 4 yrs except centuries not multiples of 400.
         n400Years = (long)(nDaysAbsolute / 146097L);
         // Set nDaysAbsolute to day within 400-year block

         nDaysAbsolute %= 146097L;
         // -1 because first century has extra day
         n400Century = (long)((nDaysAbsolute - 1) / 36524L);
         // Non-leap century


         if (n400Century != 0)
         {

            // Set nDaysAbsolute to day within centurY
            nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;

            // +1 because 1st 4 year increment has 1460 days
            n4Years = (long)((nDaysAbsolute + 1) / 1461L);

            if (n4Years != 0)
               n4Day = (long)((nDaysAbsolute + 1) % 1461L);
            else
            {
               bLeap4 = false;
               n4Day = (long)nDaysAbsolute;
            }
         }
         else
         {
            // Leap century - not special case!
            n4Years = (long)(nDaysAbsolute / 1461L);
            n4Day = (long)(nDaysAbsolute % 1461L);
         }

         if (bLeap4)
         {
            // -1 because first year has 366 days
            n4Yr = (n4Day - 1) / 365;

            if (n4Yr != 0)
               n4Day = (n4Day - 1) % 365;
         }
         else
         {
            n4Yr = n4Day / 365;
            n4Day %= 365;
         }

         tm_year = (int)(n400Years * 400 + n400Century * 100 +
            n4Years * 4 + n4Yr);

         // Handle leap year: before, on, and after Feb. 29.
         if (n4Yr == 0 && bLeap4 && n4Day == 59)
         {
            /* Feb. 29 */ 
            tm_mon = 2;
            tm_mday = 29;
         }
         else
         {
            if (n4Yr == 0 && bLeap4 && n4Day >= 59)
               --n4Day;

            // Make n4DaY a 1-based day of non-leap year and compute

            //  month/day for everything but Feb. 29.
            ++n4Day;

            // Month number always >= n/32, so save some loop time */ 
            for (tm_mon = (int)((n4Day <> 5) + 1);
               n4Day > rgMonthDays[tm_mon]; tm_mon++);

            tm_mday = (int)(n4Day - rgMonthDays[tm_mon-1]);
         }

         if (nSecsInDay == 0)
            tm_hour = tm_min = tm_sec = 0;
         else
         {
            tm_sec = (int)(nSecsInDay % 60L);
            nMinutesInDay = nSecsInDay / 60L;
            tm_min = (int)(nMinutesInDay % 60);
            tm_hour = (int)(nMinutesInDay / 60);
         }

         setYear(tm_year - 1900);
         setMonth(tm_mon - 1);
         super.setDate(tm_mday); // resolves ambiguity
                                 // between OleDate.setDate and
                                 // java.util.Date.setDate
         setHours(tm_hour);
         setMinutes(tm_min);
         setSeconds(tm_sec);

      }

      // source code copied from MFC 4.21 and modified
      static int rgMonthDays[] =
         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};

      public double toDouble()
      {
         // source code copied from MFC 4.21 and modified.

         int wYear = getYear() + 1900;
         int wMonth = getMonth() + 1;
         int wDay = getDate();
         int wHour = getHours();
         int wMinute = getMinutes();
         int wSecond = getSeconds();

         //  Check for leap year and set the number of days in the month
         boolean bLeapYear = ((wYear & 3) == 0) &&
            ((wYear % 100) != 0 || (wYear % 400) == 0);

         int nDaysInMonth =
            rgMonthDays[wMonth] - rgMonthDays[wMonth-1] +
            ((bLeapYear && wDay == 29 && wMonth == 2) ? 1 : 0);

         // Cache the date in days and time in fractional days
         long nDate;
         double dblTime;

         //It is a valid date; make Jan 1, 1AD be 1
         nDate = wYear*365L + wYear/4 - wYear/100 + wYear/400 +
            rgMonthDays[wMonth-1] + wDay;

         //  If leap year and it's before March, subtract 1:
         if (wMonth >= 2 && bLeapYear)
            --nDate;

         //  Offset so that 12/30/1899 is 0
         nDate -= 693959L;

         dblTime = (((long)wHour * 3600L) +  // hrs in seconds
            ((long)wMinute * 60L) +  // mins in seconds
            ((long)wSecond)) / 86400.;

         double dtDest = (double) nDate +
            ((nDate >= 0) ? dblTime : -dblTime);

         return dtDest;
      }

   } 
The class OleDate has two public member functions that convert between DATE and java.util.Date:

public void setDate(double date) 
takes valid OLE DATE values and sets the Date object with the values specified in DATE.

public double toDouble() 
returns a double that contains the value in the object, converted to OLE DATE type.

The following code illustrates how to use these functions:

m_autoObject is a valid Automation object. The automation object exposes a Property named "today" of type DATE:

   ...
   import OleDate;
   class testoledate
   {

      ...
      public void testDate
      {
         OleDate date = new OleDate(m_autoObject.gettoday());
    date.setDate(date.getDate() + 1);
    m_autoObject.puttoday(date.toDouble());

      }
      ...

   } 
Once you run the code above, the automation objects property will be set to the next day.


REFERENCES

Win32 SDK Documentation

MFC source file OleVar.cpp

For the latest Knowledge Base articles and other support information on Visual J++ and the SDK for Java, see the following page on the Microsoft Technical Support site:

http://support.microsoft.com/support/visualj/

http://support.microsoft.com/support/java/

© Microsoft Corporation 1999, All Rights Reserved.
Contributions by Sridhar S. Madhugiri, Microsoft Corporation

Additional query words:


Keywords          : kbcode kbole kbCOMt kbJava kbJavaVM 
Version           : WINDOWS:1.0,1.1
Platform          : WINDOWS 
Issue type        : kbhowto 

Last Reviewed: May 25, 1999