Opened 12 years ago

Last modified 11 years ago

#5428 new Bugs

No <ctime> function in Windows CE 6.0

Reported by: Akira Takahashi <faithandbrave@…> Owned by: az_sw_dude
Milestone: To Be Determined Component: date_time
Version: Boost 1.46.1 Severity: Problem
Keywords: wince Cc: ulrich.eckhardt@…

Description

Windows CE platform is nothing <ctime> function. example std::localtime, std::gmtime, etc...

boost/date_time/c_time.hpp is direct use "std::localtime", "std::gmtime". this problem solution is make alternative implementation.

Windows CE platform <ctime> sample implementation is there: OpenTimeCE. (I cant paste URL, as spam...)

Attachments (2)

boost central time wrapper.patch (3.3 KB ) - added by Ulrich Eckhardt <ulrich.eckhardt@…> 11 years ago.
add central point for time() workarounds
boost time functions for CE.patch (7.0 KB ) - added by Ulrich Eckhardt <ulrich.eckhardt@…> 11 years ago.
implementations of time(), localtime(), gmtime() for CE

Download all attachments as: .zip

Change History (9)

comment:1 by zerhud@…, 11 years ago

SQLite3 do this (#if SQLITE_OS_WINCE)

struct tm *__cdecl localtime(const time_t *t)
{
  static struct tm y;
  FILETIME uTm, lTm;
  SYSTEMTIME pTm;
  sqlite3_int64 t64;
  t64 = *t;
  t64 = (t64 + 11644473600)*10000000;
  uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
  uTm.dwHighDateTime= (DWORD)(t64 >> 32);
  FileTimeToLocalFileTime(&uTm,&lTm);
  FileTimeToSystemTime(&lTm,&pTm);
  y.tm_year = pTm.wYear - 1900;
  y.tm_mon = pTm.wMonth - 1;
  y.tm_wday = pTm.wDayOfWeek;
  y.tm_mday = pTm.wDay;
  y.tm_hour = pTm.wHour;
  y.tm_min = pTm.wMinute;
  y.tm_sec = pTm.wSecond;
  return &y;
}

comment:2 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

Cc: ulrich.eckhardt@… added
Keywords: wince added

Instead of providing a thread-unsafe localtime() implementation, the above could be modified to provide a thread-safe one that could be used for all win32 implementations. Since I'm pondering the same problems for my 1.48 migration, I'll take a look if I can't fix this.

comment:3 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

The above implementation of localtime from sqlite is incorrect, AFAICT. The problem is that the tm_yday and tm_isdst fields are not set correctly. Further, even the hour differs sometimes, which I guess might be due to the daylight saving time offsets. I haven't completely figured out how to pull that info out of the system.

The code for gmtime() below was tested on a German MS Windows XP system for time_t values between 1 and 0xfffffff8, using the native gmtime() implementation of VC8 as reference. Both yield the same results. This also runs on MS Windows CE6, though I still need to test a few checkpoint values since I don't have a native gmtime() at my service there.

I'm a bit unsure if I can simply set the tm_isdst to zero for gmtime(), maybe someone else could jump in here.

      //! requires a pointer to a user created std::tm struct
      inline
      static std::tm* gmtime(const std::time_t* t, std::tm* result)
      {
        /* Three conversions here:
         1. convert to 64-bit type to avoid overflows
         2. epoch beginning 1970 to one beginning 1601
         3. seconds to 100ns steps */
        int64_t t64 = static_cast<int64_t>(*t);
        t64 += 11644473600;
        t64 *= 10000000;
        // convert to FILETIME struct
        FILETIME utc_time;
        utc_time.dwLowDateTime = static_cast<DWORD>(t64 & 0xFFFFFFFF);
        utc_time.dwHighDateTime= static_cast<DWORD>(t64 >> 32);
        // split into year, month, day etc
        SYSTEMTIME st;
        if(!FileTimeToSystemTime(&utc_time, &st))
          boost::throw_exception(std::runtime_error("could not convert calendar time to local time"));
        result->tm_year = st.wYear - 1900;
        result->tm_mon = st.wMonth - 1;
        result->tm_wday = st.wDayOfWeek;
        result->tm_mday = st.wDay;
        result->tm_hour = st.wHour;
        result->tm_min = st.wMinute;
        result->tm_sec = st.wSecond;
        // compute day of year
        bool leapyear;
        if((st.wYear % 1000) == 0)
            leapyear = true;
        else if((st.wYear % 100) == 0)
            leapyear = false;
        else if((st.wYear % 4) == 0)
            leapyear = true;
        else
            leapyear = false;
        result->tm_yday = result->tm_mday - 1;
        if(leapyear)
        {
          int const ml[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
          for(int i=0; i!=result->tm_mon; ++i)
            result->tm_yday += ml[i];
        }
        else
        {
          int const ml[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
          for(int i=0; i!=result->tm_mon; ++i)
            result->tm_yday += ml[i];
        }

        /* MSVC8 implementation always does that, using a German MS Windows XP,
        not sure if that is correct... */
        result->tm_isdst = 0;

        return result;
      }

comment:4 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

Short update: Another function missing from both CE5 and CE6 is time(). This function is used in boost/date_time/date_clock_device.hpp and boost/date_time/time_clock.hpp. Both uses are inside of template code, so the lack of these functions isn't obvious until the templates are instantiated.

My plan is to create a patch that adds a wrapper for time() to the c_time class and redirect any direct uses of time() there. Then, in a second step, I can implement the time wrapper there for CE. I'll post it in two steps because the first step will affect all platforms and I want that step to be as small and clear as possible, hopefully increasing the chances for it to be applied.

Notes:

  • I don't have any environments earlier than CE5 here, so I can't speak for those, but I'm assuming that the state of the time functions is the same.
  • There are no definitions of time() etc in CE5 and CE6, see e.g. this blog posting of one of the CE developers.
  • In CE5 you have declarations in time.h, which are imported by STLport into namespace std, in CE6 those are gone, too.

by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

add central point for time() workarounds

comment:5 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

The attached patch is step 1. It adds a time() function to c_time, which currently only forwards to std::time(). All uses of std::time() in date_time were replaced with calls to that wrapper function.

I did two more things:

  1. In c_time.hpp were a few tabs and some foobar'd formatting, which I fixed along the way. There also were two misleading comments #else // BOOST_HAS_THREADS which I simply removed.
  2. In the four cases where time() was used, it was used like time_t t; time(&t); which I replaced with a single line time_t t = time(0);. I was even wondering if I shouldn't drop the pointer argument completely from the wrapper, it seems of little use to me.

I'd be happy about some feedback whether these changes are acceptable. I'll send the second step implementing c_time::time() for CE tomorrow, I still need to clean it up a bit.

by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

implementations of time(), localtime(), gmtime() for CE

comment:6 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

This second patch adds implementations of the missing functions to c_time. With the exception of the tests relying on serialization, I have run all unit tests on a CE6 system without additional failures when compared to the desktop win32 version. Note that all this is based on 1.48, though the files in question haven't changed in trunk, AFAICT.

comment:7 by Ulrich Eckhardt <ulrich.eckhardt@…>, 11 years ago

I just verified that the unit tests also succeed under CE5.

Note: See TracTickets for help on using tickets.