earth_time.cpp

Go to the documentation of this file.
00001 #ifndef EARTH_TIME_IMPLEMENTATION_FILE
00002 #define EARTH_TIME_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : earth_time                                                        *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1999-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "convert_utf.h"
00019 #include "earth_time.h"
00020 #include "istring.h"
00021 #include "portable.h"
00022 
00023 #include <time.h>
00024 #if defined(__WIN32__) || defined(__UNIX__)
00025   #include <sys/timeb.h>
00026 #endif
00027 
00028 using namespace basis;
00029 
00030 namespace earth_time {
00031 
00032 const int days_in_month[12]
00033     = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00034 
00035 const int leap_days_in_month[12]
00036     = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00037 
00038 const int julian_days_in_month[12]
00039     = { 31, 29, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
00040 //hmmm: is this right?
00041 
00042 const int julian_leap_days_in_month[12]
00043     = { 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
00044 
00046 
00047 void clock_time::pack(byte_array &packed_form) const
00048 {
00049   attach(packed_form, hour);
00050   attach(packed_form, minute);
00051   attach(packed_form, second);
00052   attach(packed_form, millisecond);
00053   attach(packed_form, microsecond);
00054 }
00055 
00056 bool clock_time::unpack(byte_array &packed_form)
00057 {
00058   if (!detach(packed_form, hour)) return false;
00059   if (!detach(packed_form, minute)) return false;
00060   if (!detach(packed_form, second)) return false;
00061   if (!detach(packed_form, millisecond)) return false;
00062   if (!detach(packed_form, microsecond)) return false;
00063   return true;
00064 }
00065 
00066 #define EASY_LT(x, y) \
00067   if (x < y) return true; \
00068   if (x > y) return false
00069 
00070 bool clock_time::operator < (const clock_time &to_compare) const
00071 {
00072   EASY_LT(hour, to_compare.hour);
00073   EASY_LT(minute, to_compare.minute);
00074   EASY_LT(second, to_compare.second);
00075   EASY_LT(millisecond, to_compare.millisecond);
00076   EASY_LT(microsecond, to_compare.microsecond);
00077   return false;
00078 }
00079 
00080 bool clock_time::operator == (const clock_time &to_compare) const
00081 {
00082   return (hour == to_compare.hour) 
00083       && (minute == to_compare.minute)
00084       && (second == to_compare.second) 
00085       && (millisecond == to_compare.millisecond) 
00086       && (microsecond == to_compare.microsecond);
00087 }
00088 
00089 istring clock_time::text_form(int how) const
00090 {
00091   istring to_return;
00092   text_form(to_return, how);
00093   return to_return;
00094 }
00095 
00096 void clock_time::text_form(istring &to_return, int how) const
00097 {
00098   if (!how) return;  // enforce use of the default.
00099   if (how & MILITARY)
00100     to_return += isprintf("%02d:%02d", hour, minute);
00101   else {
00102     int uhr = hour;
00103     if (uhr > 12) uhr -= 12;
00104     to_return += isprintf("%2d:%02d", uhr, minute);
00105   }
00106   if ( (how & SECONDS) || (how & MILLISECONDS) )
00107     to_return += isprintf(":%02d", second);
00108   if (how & MILLISECONDS)
00109     to_return += isprintf(":%03d", millisecond);
00110   if (how & MERIDIAN) {
00111     if (hour >= 12) to_return += "PM";
00112     else to_return += "AM";
00113   }
00114 }
00115 
00116 // makes sure that "val" is not larger than "max".  if it is, then max is
00117 // used as a divisor and stored in "rolls".
00118 #define limit_value(val, max) \
00119   if (val < 0) { \
00120     rolls = val / max; \
00121     rolls--; /* subtract an extra one since we definitely roll before -max */ \
00122     val += max * -rolls; \
00123   } else if (val >= max) { \
00124     rolls = val / max; \
00125     val -= max * rolls; \
00126   } else { rolls = 0; }
00127 
00128 int clock_time::normalize(clock_time &to_fix)
00129 {
00130   int rolls = 0;  // rollover counter.
00131   limit_value(to_fix.microsecond, 1000);
00132   to_fix.millisecond += rolls;
00133   limit_value(to_fix.millisecond, 1000);
00134   to_fix.second += rolls;
00135   limit_value(to_fix.second, 60);
00136   to_fix.minute += rolls;
00137   limit_value(to_fix.minute, 60);
00138   to_fix.hour += rolls;
00139   limit_value(to_fix.hour, 24);
00140   return rolls;
00141 }
00142 
00144 
00145 void day_in_year::pack(byte_array &packed_form) const
00146 {
00147   attach(packed_form, day_of_year);
00148   attach(packed_form, byte(day_of_week));
00149   attach(packed_form, byte(month));
00150   attach(packed_form, day_in_month);
00151   attach(packed_form, byte(1));
00152     // still packing dst chunk; must for backward compatibility.
00153 }
00154 
00155 bool day_in_year::unpack(byte_array &packed_form)
00156 {
00157   if (!detach(packed_form, day_of_year)) return false;
00158   byte temp;
00159   if (!detach(packed_form, temp)) return false;
00160   day_of_week = days(temp);
00161   if (!detach(packed_form, temp)) return false;
00162   month = months(temp);
00163   if (!detach(packed_form, day_in_month)) return false;
00164   if (!detach(packed_form, temp)) return false;  // dst chunk--backward compat.
00165   return true;
00166 }
00167 
00168 bool day_in_year::operator < (const day_in_year &to_compare) const
00169 {
00170   EASY_LT(month, to_compare.month);
00171   EASY_LT(day_in_month, to_compare.day_in_month);
00172   return false;
00173 }
00174 
00175 bool day_in_year::operator == (const day_in_year &to_compare) const
00176 {
00177   return (month == to_compare.month)
00178       && (day_in_month == to_compare.day_in_month);
00179 }
00180 
00181 istring day_in_year::text_form(int how) const
00182 {
00183   istring to_return;
00184   text_form(to_return, how);
00185   return to_return;
00186 }
00187 
00188 void day_in_year::text_form(istring &to_stuff, int how) const
00189 {
00190   if (!how) return;  // enforce use of the default.
00191   if (how & INCLUDE_DAY) to_stuff += istring(day_name(day_of_week)) + " ";
00192   const char *monat = short_month_name(month);
00193   if (how & LONG_MONTH)
00194     monat = month_name(month);
00195 //hmmm: more formatting, like euro?
00196   to_stuff += monat;
00197   to_stuff += isprintf(" %02d", day_in_month);
00198 }
00199 
00200 // note: this only works when adjusting across one month, not multiples.
00201 int limit_day_of_month(int &day, int days_in_month, int days_in_prev_month)
00202 {
00203   if (day > days_in_month) {
00204     day -= days_in_month;
00205     return 1;  // forward rollover.
00206   } else if (day < 1) {
00207     day += days_in_prev_month;
00208     return -1;
00209   }
00210   return 0;  // no rolling.
00211 }
00212 
00213 int day_in_year::normalize(day_in_year &to_fix, bool leap_year)
00214 {
00215   int rolls = 0;  // rollover counter.
00216   int daysinm = leap_year?
00217       leap_days_in_month[to_fix.month] : days_in_month[to_fix.month];
00218   int prev_month = to_fix.month - 1;
00219   if (prev_month < 0) prev_month = 11;
00220   int daysinpm = leap_year?
00221       leap_days_in_month[prev_month] : days_in_month[prev_month];
00222   rolls = limit_day_of_month(to_fix.day_in_month, daysinm, daysinpm);
00223   int monat = to_fix.month + rolls;
00224   limit_value(monat, 12);  // months are zero based.
00225   to_fix.month = months(monat);
00226   return rolls;
00227 }
00228 
00230 
00231 void time_locus::pack(byte_array &packed_form) const
00232 {
00233   attach(packed_form, year);
00234   clock_time::pack(packed_form);
00235   day_in_year::pack(packed_form);
00236 }
00237 
00238 bool time_locus::unpack(byte_array &packed_form)
00239 {
00240   if (!detach(packed_form, year)) return false;
00241   if (!clock_time::unpack(packed_form)) return false;
00242   if (!day_in_year::unpack(packed_form)) return false;
00243   return true;
00244 }
00245 
00246 istring time_locus::text_form(int t, int d, int y) const
00247 {
00248   istring to_return;
00249   text_form(to_return, t, d, y);
00250   return to_return;
00251 }
00252 
00253 bool time_locus::operator < (const time_locus &to_compare) const
00254 {
00255   EASY_LT(year, to_compare.year);
00256   if (day_in_year::operator < (to_compare)) return true;
00257   if (!(day_in_year::operator == (to_compare))) return false;
00258   if (clock_time::operator < (to_compare)) return true;
00259   return false;
00260 }
00261 
00262 bool time_locus::operator == (const time_locus &to_compare) const
00263 {
00264   return (year == to_compare.year)
00265       && ( (const day_in_year &) *this == to_compare)
00266       && ( (const clock_time &) *this == to_compare);
00267 }
00268 
00269 void time_locus::text_form(istring &to_stuff, int t, int d, int y) const
00270 {
00271 //hmmm: more formatting desired, like european.
00272   if (!y) {
00273     text_form(to_stuff, t, d);  // enforce use of the default.
00274     return;
00275   }
00276   // add the day.
00277   day_in_year::text_form(to_stuff, d);
00278   to_stuff += " ";
00279   // add the year.
00280   if (y & SHORT_YEAR)
00281     to_stuff += isprintf("%2d", year % 100);
00282   else
00283     to_stuff += isprintf("%4d", year);
00284   // add the time.
00285   to_stuff += " ";
00286   clock_time::text_form(to_stuff, t);
00287 }
00288 
00289 int time_locus::normalize(time_locus &to_fix)
00290 {
00291   int rolls = clock_time::normalize(to_fix);
00292   to_fix.day_in_month += rolls;
00293 
00294 //hmmm: this little gem should be abstracted to a method.
00295   bool leaping = !(to_fix.year % 4);
00296   if (!(to_fix.year % 100)) leaping = false;
00297   if (!(to_fix.year % 400)) leaping = true;
00298 
00299   rolls = day_in_year::normalize(to_fix, leaping);
00300   to_fix.year += rolls;
00301   return 0;
00302     // is that always right?  not for underflow.
00303 //hmmm: resolve the issue of rollovers here.
00304 }
00305 
00307 
00308 time_locus convert(const tm &to_convert, int ms)
00309 {
00310   time_locus r;
00311 
00312   // we lack the resolution for this, currently.
00313   r.microsecond = 0;
00314 
00315   r.second = to_convert.tm_sec;
00316   r.minute = to_convert.tm_min;
00317   r.hour = to_convert.tm_hour;
00318   r.day_in_month = to_convert.tm_mday;
00319   r.month = months(to_convert.tm_mon);
00320   r.year = to_convert.tm_year + 1900;
00321   r.day_of_week = days(to_convert.tm_wday);
00322   r.day_of_year = to_convert.tm_yday;
00323   r.millisecond = ms;
00324   return r;
00325 }
00326 
00327 time_locus now()
00328 {
00329   timeb current;
00330   ftime(&current);
00331   tm split_time(*localtime(&current.time));
00332   return convert(split_time, current.millitm);
00333 }
00334 
00335 time_locus greenwich_now()
00336 {
00337   timeb current;
00338   ftime(&current);
00339   tm split_time(*gmtime(&current.time));
00340   return convert(split_time, current.millitm);
00341 }
00342 
00343 clock_time time_now() { return now(); }
00344 
00345 days day_now() { return now().day_of_week; }
00346 
00347 months month_now() { return now().month; }
00348 
00349 int year_now() { return now().year; }
00350 
00351 day_in_year date_now() { return now(); }
00352 
00353 const char *day_name(days to_name)
00354 {
00355   switch (to_name) {
00356     case SUNDAY: return "Sunday";
00357     case MONDAY: return "Monday";
00358     case TUESDAY: return "Tuesday";
00359     case WEDNESDAY: return "Wednesday";
00360     case THURSDAY: return "Thursday";
00361     case FRIDAY: return "Friday";
00362     case SATURDAY: return "Saturday";
00363     default: return "Not_a_day";
00364   }
00365 }
00366 
00367 const char *month_name(months to_name)
00368 {
00369   switch (to_name) {
00370     case JANUARY: return "January";
00371     case FEBRUARY: return "February";
00372     case MARCH: return "March";
00373     case APRIL: return "April";
00374     case MAY: return "May";
00375     case JUNE: return "June";
00376     case JULY: return "July";
00377     case AUGUST: return "August";
00378     case SEPTEMBER: return "September";
00379     case OCTOBER: return "October";
00380     case NOVEMBER: return "November";
00381     case DECEMBER: return "December";
00382     default: return "Not_a_month";
00383   }
00384 }
00385 
00386 const char *short_month_name(months to_name)
00387 {
00388   switch (to_name) {
00389     case JANUARY: return "Jan";
00390     case FEBRUARY: return "Feb";
00391     case MARCH: return "Mar";
00392     case APRIL: return "Apr";
00393     case MAY: return "May";
00394     case JUNE: return "Jun";
00395     case JULY: return "Jul";
00396     case AUGUST: return "Aug";
00397     case SEPTEMBER: return "Sep";
00398     case OCTOBER: return "Oct";
00399     case NOVEMBER: return "Nov";
00400     case DECEMBER: return "Dec";
00401     default: return "Not";
00402   }
00403 }
00404 
00405 bool set_time(const time_locus &new_time)
00406 {
00407 #ifdef __WIN32__
00408   SYSTEMTIME os_time;
00409   os_time.wYear = WORD(new_time.year);
00410   os_time.wMonth = new_time.month;
00411   os_time.wDayOfWeek = new_time.day_of_week;
00412   os_time.wDay = new_time.day_of_year;
00413   os_time.wHour = new_time.hour;
00414   os_time.wMinute = new_time.minute;
00415   os_time.wSecond = new_time.second;
00416   os_time.wMilliseconds = 0;  // currently unused.
00417 
00418   // get our process token for manipulation.
00419   HANDLE petoken;
00420   OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
00421       | TOKEN_QUERY, &petoken);
00422   // get our 
00423 //something or other
00424 // identifier so we can adjust our privileges.
00425   LUID our_id;
00426   LookupPrivilegeValue(NULL, to_unicode_temp("SeSystemTimePrivilege"), &our_id);
00427   // make up a privilege structure for the adjustment.
00428   TOKEN_PRIVILEGES privs;
00429   privs.PrivilegeCount = 1;
00430   privs.Privileges[0].Luid = our_id;
00431   privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00432   // enable system-time privileges.
00433   AdjustTokenPrivileges(petoken, false, &privs, sizeof(TOKEN_PRIVILEGES),
00434       NULL, NULL);
00435 
00436   SetLocalTime(&os_time);  // actually set the time.
00437 
00438   // disable the time adjustment privileges again.
00439   AdjustTokenPrivileges(petoken, true, &privs, sizeof(TOKEN_PRIVILEGES),
00440       NULL, NULL);
00441 
00442   // let all the main windows know that the time got adjusted.
00443 //do we need to do this ourselves?
00444   ::PostMessage(HWND_BROADCAST, WM_TIMECHANGE, 0, 0);
00445 
00446 //hmmm: make sure this seems right.
00447   CloseHandle(petoken);
00448 
00449   return true;
00450 #elif defined(__UNIX__)
00451 //no implem yet.
00452 
00453 //temp to shut up warnings
00454 time_locus ted = new_time;
00455 return ted.year ? 0:1;
00456 
00457 #else
00458   return false;
00459 #endif
00460 }
00461 
00462 } // namespace.
00463 
00464 
00465 #endif //EARTH_TIME_IMPLEMENTATION_FILE
00466 

Generated on Fri Nov 28 04:29:07 2008 for HOOPLE Libraries by  doxygen 1.5.1