earth_time.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : earth_time                                                        *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 1999-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 #include "earth_time.h"
00016 
00017 #include <basis/astring.h>
00018 #include <basis/utf_conversion.h>
00019 
00020 #include <time.h>
00021 #if defined(__WIN32__) || defined(__UNIX__)
00022   #include <sys/timeb.h>
00023 #endif
00024 
00025 using namespace basis;
00026 using namespace structures;
00027 
00028 namespace timely {
00029 
00030 const int days_in_month[12]
00031     = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00032 
00033 const int leap_days_in_month[12]
00034     = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00035 
00036 const int julian_days_in_month[12]
00037     = { 31, 29, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
00038 //hmmm: is this right?
00039 
00040 const int julian_leap_days_in_month[12]
00041     = { 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
00042 
00044 
00045 void clock_time::pack(byte_array &packed_form) const
00046 {
00047   attach(packed_form, hour);
00048   attach(packed_form, minute);
00049   attach(packed_form, second);
00050   attach(packed_form, millisecond);
00051   attach(packed_form, microsecond);
00052 }
00053 
00054 bool clock_time::unpack(byte_array &packed_form)
00055 {
00056   if (!detach(packed_form, hour)) return false;
00057   if (!detach(packed_form, minute)) return false;
00058   if (!detach(packed_form, second)) return false;
00059   if (!detach(packed_form, millisecond)) return false;
00060   if (!detach(packed_form, microsecond)) return false;
00061   return true;
00062 }
00063 
00064 #define EASY_LT(x, y) \
00065   if (x < y) return true; \
00066   if (x > y) return false
00067 
00068 bool clock_time::operator < (const clock_time &to_compare) const
00069 {
00070   EASY_LT(hour, to_compare.hour);
00071   EASY_LT(minute, to_compare.minute);
00072   EASY_LT(second, to_compare.second);
00073   EASY_LT(millisecond, to_compare.millisecond);
00074   EASY_LT(microsecond, to_compare.microsecond);
00075   return false;
00076 }
00077 
00078 bool clock_time::operator == (const clock_time &to_compare) const
00079 {
00080   return (hour == to_compare.hour) 
00081       && (minute == to_compare.minute)
00082       && (second == to_compare.second) 
00083       && (millisecond == to_compare.millisecond) 
00084       && (microsecond == to_compare.microsecond);
00085 }
00086 
00087 astring clock_time::text_form(int how) const
00088 {
00089   astring to_return;
00090   text_form(to_return, how);
00091   return to_return;
00092 }
00093 
00094 void clock_time::text_form(astring &to_return, int how) const
00095 {
00096   if (!how) return;  // enforce use of the default.
00097   if (how & MILITARY)
00098     to_return += a_sprintf("%02d:%02d", hour, minute);
00099   else {
00100     int uhr = hour;
00101     if (uhr > 12) uhr -= 12;
00102     to_return += a_sprintf("%2d:%02d", uhr, minute);
00103   }
00104   if ( (how & SECONDS) || (how & MILLISECONDS) )
00105     to_return += a_sprintf(":%02d", second);
00106   if (how & MILLISECONDS)
00107     to_return += a_sprintf(":%03d", millisecond);
00108   if (how & MERIDIAN) {
00109     if (hour >= 12) to_return += "PM";
00110     else to_return += "AM";
00111   }
00112 }
00113 
00114 // makes sure that "val" is not larger than "max".  if it is, then max is
00115 // used as a divisor and stored in "rolls".
00116 #define limit_value(val, max) \
00117   if (val < 0) { \
00118     rolls = val / max; \
00119     rolls--; /* subtract an extra one since we definitely roll before -max */ \
00120     val += max * -rolls; \
00121   } else if (val >= max) { \
00122     rolls = val / max; \
00123     val -= max * rolls; \
00124   } else { rolls = 0; }
00125 
00126 int clock_time::normalize(clock_time &to_fix)
00127 {
00128   int rolls = 0;  // rollover counter.
00129   limit_value(to_fix.microsecond, 1000);
00130   to_fix.millisecond += rolls;
00131   limit_value(to_fix.millisecond, 1000);
00132   to_fix.second += rolls;
00133   limit_value(to_fix.second, 60);
00134   to_fix.minute += rolls;
00135   limit_value(to_fix.minute, 60);
00136   to_fix.hour += rolls;
00137   limit_value(to_fix.hour, 24);
00138   return rolls;
00139 }
00140 
00142 
00143 void day_in_year::pack(byte_array &packed_form) const
00144 {
00145   attach(packed_form, day_of_year);
00146   attach(packed_form, abyte(day_of_week));
00147   attach(packed_form, abyte(month));
00148   attach(packed_form, day_in_month);
00149   attach(packed_form, abyte(1));
00150     // still packing dst chunk; must for backward compatibility.
00151 }
00152 
00153 bool day_in_year::unpack(byte_array &packed_form)
00154 {
00155   if (!detach(packed_form, day_of_year)) return false;
00156   abyte temp;
00157   if (!detach(packed_form, temp)) return false;
00158   day_of_week = days(temp);
00159   if (!detach(packed_form, temp)) return false;
00160   month = months(temp);
00161   if (!detach(packed_form, day_in_month)) return false;
00162   if (!detach(packed_form, temp)) return false;  // dst chunk--backward compat.
00163   return true;
00164 }
00165 
00166 bool day_in_year::operator < (const day_in_year &to_compare) const
00167 {
00168   EASY_LT(month, to_compare.month);
00169   EASY_LT(day_in_month, to_compare.day_in_month);
00170   return false;
00171 }
00172 
00173 bool day_in_year::operator == (const day_in_year &to_compare) const
00174 {
00175   return (month == to_compare.month)
00176       && (day_in_month == to_compare.day_in_month);
00177 }
00178 
00179 astring day_in_year::text_form(int how) const
00180 {
00181   astring to_return;
00182   text_form(to_return, how);
00183   return to_return;
00184 }
00185 
00186 void day_in_year::text_form(astring &to_stuff, int how) const
00187 {
00188   if (!how) return;  // enforce use of the default.
00189   if (how & INCLUDE_DAY) to_stuff += astring(day_name(day_of_week)) + " ";
00190   const char *monat = short_month_name(month);
00191   if (how & LONG_MONTH)
00192     monat = month_name(month);
00193 //hmmm: more formatting, like euro?
00194   to_stuff += monat;
00195   to_stuff += a_sprintf(" %02d", day_in_month);
00196 }
00197 
00198 // note: this only works when adjusting across one month, not multiples.
00199 int limit_day_of_month(int &day, int days_in_month, int days_in_prev_month)
00200 {
00201   if (day > days_in_month) {
00202     day -= days_in_month;
00203     return 1;  // forward rollover.
00204   } else if (day < 1) {
00205     day += days_in_prev_month;
00206     return -1;
00207   }
00208   return 0;  // no rolling.
00209 }
00210 
00211 int day_in_year::normalize(day_in_year &to_fix, bool leap_year)
00212 {
00213   int rolls = 0;  // rollover counter.
00214   int daysinm = leap_year?
00215       leap_days_in_month[to_fix.month] : days_in_month[to_fix.month];
00216   int prev_month = to_fix.month - 1;
00217   if (prev_month < 0) prev_month = 11;
00218   int daysinpm = leap_year?
00219       leap_days_in_month[prev_month] : days_in_month[prev_month];
00220   rolls = limit_day_of_month(to_fix.day_in_month, daysinm, daysinpm);
00221   int monat = to_fix.month + rolls;
00222   limit_value(monat, 12);  // months are zero based.
00223   to_fix.month = months(monat);
00224   return rolls;
00225 }
00226 
00228 
00229 void time_locus::pack(byte_array &packed_form) const
00230 {
00231   attach(packed_form, year);
00232   clock_time::pack(packed_form);
00233   day_in_year::pack(packed_form);
00234 }
00235 
00236 bool time_locus::unpack(byte_array &packed_form)
00237 {
00238   if (!detach(packed_form, year)) return false;
00239   if (!clock_time::unpack(packed_form)) return false;
00240   if (!day_in_year::unpack(packed_form)) return false;
00241   return true;
00242 }
00243 
00244 astring time_locus::text_form_long(int t, int d, int y) const
00245 {
00246   astring to_return;
00247   text_form_long(to_return, t, d, y);
00248   return to_return;
00249 }
00250 
00251 bool time_locus::equal_to(const equalizable &s2) const {
00252   const time_locus *s2_cast = dynamic_cast<const time_locus *>(&s2);
00253   if (!s2_cast) throw "error: time_locus::==: unknown type";
00254   return (year == s2_cast->year)
00255       && ( (const day_in_year &) *this == *s2_cast)
00256       && ( (const clock_time &) *this == *s2_cast);
00257 }
00258 
00259 bool time_locus::less_than(const orderable &s2) const {
00260   const time_locus *s2_cast = dynamic_cast<const time_locus *>(&s2);
00261   if (!s2_cast) throw "error: time_locus::<: unknown type";
00262   EASY_LT(year, s2_cast->year);
00263   if (day_in_year::operator < (*s2_cast)) return true;
00264   if (!(day_in_year::operator == (*s2_cast))) return false;
00265   if (clock_time::operator < (*s2_cast)) return true;
00266   return false;
00267 }
00268 
00269 void time_locus::text_form_long(astring &to_stuff, int t, int d, int y) const
00270 {
00271 //hmmm: more formatting desired, like european.
00272   if (!y) {
00273     text_form_long(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 += a_sprintf("%2d", year % 100);
00282   else
00283     to_stuff += a_sprintf("%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 } // namespace.
00406 
Generated on Sat Jan 28 04:22:33 2012 for hoople2 project by  doxygen 1.6.3