feisty meow concerns codebase  2.140
earth_time.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : earth_time *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 1999-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "earth_time.h"
16 #include "time_stamp.h"
17 
18 #include <basis/astring.h>
19 #include <basis/utf_conversion.h>
20 #include <textual/parser_bits.h>
21 
22 #include <time.h>
23 #include <sys/time.h>
24 #if defined(__WIN32__) || defined(__UNIX__)
25 // #include <sys/timeb.h>
26 #endif
27 
28 #include <stdio.h>
29 
30 // uncomment for noisy code.
31 //#define DEBUG_EARTH_TIME
32 
33 using namespace basis;
34 using namespace structures;
35 using namespace textual;
36 
37 namespace timely {
38 
39 #undef LOG
40 #ifdef DEBUG_EARTH_TIME
41  #define LOG(tpr) printf("%s", (astring("earth_time::") + func + ": " + tpr + parser_bits::platform_eol_to_chars()).s())
42 #else
43  #define LOG(tpr)
44 #endif
45 
47 
49  = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
50 
52  = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
53 
55  = { 31, 29, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
56 //hmmm: is this right?
57 
59  = { 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30 };
60 
62 
63 void clock_time::pack(byte_array &packed_form) const
64 {
65  attach(packed_form, hour);
66  attach(packed_form, minute);
67  attach(packed_form, second);
68  attach(packed_form, millisecond);
69  attach(packed_form, microsecond);
70 }
71 
72 bool clock_time::unpack(byte_array &packed_form)
73 {
74  if (!detach(packed_form, hour)) return false;
75  if (!detach(packed_form, minute)) return false;
76  if (!detach(packed_form, second)) return false;
77  if (!detach(packed_form, millisecond)) return false;
78  if (!detach(packed_form, microsecond)) return false;
79  return true;
80 }
81 
82 #define EASY_LT(x, y) \
83  if (x < y) return true; \
84  if (x > y) return false
85 
86 bool clock_time::operator < (const clock_time &to_compare) const
87 {
88  EASY_LT(hour, to_compare.hour);
89  EASY_LT(minute, to_compare.minute);
90  EASY_LT(second, to_compare.second);
91  EASY_LT(millisecond, to_compare.millisecond);
92  EASY_LT(microsecond, to_compare.microsecond);
93  return false;
94 }
95 
96 bool clock_time::operator == (const clock_time &to_compare) const
97 {
98  return (hour == to_compare.hour)
99  && (minute == to_compare.minute)
100  && (second == to_compare.second)
101  && (millisecond == to_compare.millisecond)
102  && (microsecond == to_compare.microsecond);
103 }
104 
105 astring clock_time::text_form(int how) const
106 {
107  astring to_return;
108  text_form(to_return, how);
109  return to_return;
110 }
111 
112 void clock_time::text_form(astring &to_return, int how) const
113 {
114  if (!how) return; // enforce use of the default.
115  if (how & MILITARY)
116  to_return += a_sprintf("%02ld:%02ld", hour, minute);
117  else {
118  time_number uhr = hour;
119  if (uhr > 12) uhr -= 12;
120  to_return += a_sprintf("%2ld:%02ld", uhr, minute);
121  }
122  if ( (how & SECONDS) || (how & MILLISECONDS) )
123  to_return += a_sprintf(":%02ld", second);
124  if (how & MILLISECONDS)
125  to_return += a_sprintf(":%03ld", millisecond);
126  if (how & MERIDIAN) {
127  if (hour >= 12) to_return += "PM";
128  else to_return += "AM";
129  }
130 }
131 
132 // makes sure that "val" is not larger than "max". if it is, then max is
133 // used as a divisor and stored in "rolls".
134 #define limit_value(val, max) \
135  if (val < 0) { \
136  rolls = val / max; \
137  rolls--; /* subtract an extra one since we definitely roll before -max */ \
138  val += max * -rolls; \
139  } else if (val >= max) { \
140  rolls = val / max; \
141  val -= max * rolls; \
142  } else { rolls = 0; }
143 
144 time_number clock_time::normalize(clock_time &to_fix)
145 {
146  time_number rolls = 0; // rollover counter.
147  limit_value(to_fix.microsecond, 1000);
148  to_fix.millisecond += rolls;
149  limit_value(to_fix.millisecond, 1000);
150  to_fix.second += rolls;
151  limit_value(to_fix.second, 60);
152  to_fix.minute += rolls;
153  limit_value(to_fix.minute, 60);
154  to_fix.hour += rolls;
155  limit_value(to_fix.hour, 24);
156  return rolls;
157 }
158 
160 
161 void day_in_year::pack(byte_array &packed_form) const
162 {
163  attach(packed_form, day_of_year);
164  attach(packed_form, abyte(day_of_week));
165  attach(packed_form, abyte(month));
166  attach(packed_form, day_in_month);
167  attach(packed_form, abyte(1));
168  // still packing dst chunk; must for backward compatibility.
169 }
170 
171 bool day_in_year::unpack(byte_array &packed_form)
172 {
173  if (!detach(packed_form, day_of_year)) return false;
174  abyte temp;
175  if (!detach(packed_form, temp)) return false;
176  day_of_week = days(temp);
177  if (!detach(packed_form, temp)) return false;
178  month = months(temp);
179  if (!detach(packed_form, day_in_month)) return false;
180  if (!detach(packed_form, temp)) return false; // dst chunk--backward compat.
181  return true;
182 }
183 
184 bool day_in_year::operator < (const day_in_year &to_compare) const
185 {
186  EASY_LT(month, to_compare.month);
187  EASY_LT(day_in_month, to_compare.day_in_month);
188  return false;
189 }
190 
191 bool day_in_year::operator == (const day_in_year &to_compare) const
192 {
193  return (month == to_compare.month)
194  && (day_in_month == to_compare.day_in_month);
195 }
196 
197 astring day_in_year::text_form(int how) const
198 {
199  astring to_return;
200  text_form(to_return, how);
201  return to_return;
202 }
203 
204 void day_in_year::text_form(astring &to_stuff, int how) const
205 {
206  if (!how) return; // enforce use of the default.
207  if (how & INCLUDE_DAY) to_stuff += astring(day_name(day_of_week)) + " ";
208  const char *monat = short_month_name(month);
209  if (how & LONG_MONTH)
210  monat = month_name(month);
211 //hmmm: more formatting, like euro?
212  to_stuff += monat;
213  to_stuff += a_sprintf(" %02ld", day_in_month);
214 }
215 
216 // note: this only works when adjusting across one month, not multiples.
218 {
219  if (day > days_in_month) {
220  day -= days_in_month;
221  return 1; // forward rollover.
222  } else if (day < 1) {
223  day += days_in_prev_month;
224  return -1;
225  }
226  return 0; // no rolling.
227 }
228 
229 time_number day_in_year::normalize(day_in_year &to_fix, bool leap_year)
230 {
231  time_number rolls = 0; // rollover counter.
232  time_number daysinm = leap_year?
233  leap_days_in_month[to_fix.month] : days_in_month[to_fix.month];
234  time_number prev_month = to_fix.month - 1;
235  if (prev_month < 0) prev_month = 11;
236  time_number daysinpm = leap_year?
237  leap_days_in_month[prev_month] : days_in_month[prev_month];
238  rolls = limit_day_of_month(to_fix.day_in_month, daysinm, daysinpm);
239  time_number monat = to_fix.month + rolls;
240  limit_value(monat, 12); // months are zero based.
241  to_fix.month = months(monat);
242  return rolls;
243 }
244 
246 
247 void time_locus::pack(byte_array &packed_form) const
248 {
249  attach(packed_form, year);
250  clock_time::pack(packed_form);
251  day_in_year::pack(packed_form);
252 }
253 
254 bool time_locus::unpack(byte_array &packed_form)
255 {
256  if (!detach(packed_form, year)) return false;
257  if (!clock_time::unpack(packed_form)) return false;
258  if (!day_in_year::unpack(packed_form)) return false;
259  return true;
260 }
261 
262 astring time_locus::text_form_long(int t, int d, int y) const
263 {
264  astring to_return;
265  text_form_long(to_return, t, d, y);
266  return to_return;
267 }
268 
269 bool time_locus::equal_to(const equalizable &s2) const {
270  const time_locus *s2_cast = dynamic_cast<const time_locus *>(&s2);
271  if (!s2_cast) throw "error: time_locus::==: unknown type";
272  return (year == s2_cast->year)
273  && ( (const day_in_year &) *this == *s2_cast)
274  && ( (const clock_time &) *this == *s2_cast);
275 }
276 
277 bool time_locus::less_than(const orderable &s2) const {
278  const time_locus *s2_cast = dynamic_cast<const time_locus *>(&s2);
279  if (!s2_cast) throw "error: time_locus::<: unknown type";
280  EASY_LT(year, s2_cast->year);
281  if (day_in_year::operator < (*s2_cast)) return true;
282  if (!(day_in_year::operator == (*s2_cast))) return false;
283  if (clock_time::operator < (*s2_cast)) return true;
284  return false;
285 }
286 
287 void time_locus::text_form_long(astring &to_stuff, int t, int d, int y) const
288 {
289 //hmmm: more formatting desired, like european.
290  if (!y) {
291  text_form_long(to_stuff, t, d); // enforce use of the default.
292  return;
293  }
294  // add the day.
295  day_in_year::text_form(to_stuff, d);
296  to_stuff += " ";
297  // add the year.
298  if (y & SHORT_YEAR)
299  to_stuff += a_sprintf("%2ld", year % 100);
300  else
301  to_stuff += a_sprintf("%4ld", year);
302  // add the time.
303  to_stuff += " ";
304  clock_time::text_form(to_stuff, t);
305 }
306 
307 time_number time_locus::normalize(time_locus &to_fix)
308 {
309  time_number rolls = clock_time::normalize(to_fix);
310  to_fix.day_in_month += rolls;
311 
312 //hmmm: this little gem should be abstracted to a method.
313  bool leaping = !(to_fix.year % 4);
314  if (!(to_fix.year % 100)) leaping = false;
315  if (!(to_fix.year % 400)) leaping = true;
316 
317  rolls = day_in_year::normalize(to_fix, leaping);
318  to_fix.year += rolls;
319  return 0;
320  // is that always right? not for underflow.
321 //hmmm: resolve the issue of rollovers here.
322 }
323 
325 
327  const tm &cal_values)
328 {
329  FUNCDEF("convert");
330  time_locus r;
331 
332  r.millisecond = useconds / 1000;
333  r.microsecond = useconds % 1000;
334 
335  r.hour = cal_values.tm_hour;
336  r.minute = cal_values.tm_min;
337  r.second = cal_values.tm_sec;
338  r.day_in_month = cal_values.tm_mday;
339  r.month = months(cal_values.tm_mon);
340  r.year = cal_values.tm_year + 1900;
341  r.day_of_week = days(cal_values.tm_wday);
342  r.day_of_year = cal_values.tm_yday;
343 
344  LOG(a_sprintf("convert() returning: %s\n",
345  r.text_form_long(clock_time::MILITARY,
346  day_in_year::LONG_MONTH | day_in_year::INCLUDE_DAY,
347  time_locus::LONG_YEAR).s()));
348 
349  return r;
350 }
351 
353 {
354  FUNCDEF("now")
355  timeval currtime;
356  int okay = gettimeofday(&currtime, NULL_POINTER);
357  if (okay != 0) {
358  LOG("failed to gettimeofday!?");
359  }
360  time_t currtime_secs = currtime.tv_sec;
361  struct tm result;
362  tm *tz_ptr = localtime_r(&currtime_secs, &result);
363  if (tz_ptr != &result) {
364  LOG("failed to get time for local area with localtime_r");
365  }
366  return convert(currtime.tv_sec, currtime.tv_usec, result);
367 }
368 
370 {
371  FUNCDEF("greenwich_now")
372  timeval currtime;
373  int okay = gettimeofday(&currtime, NULL_POINTER);
374  if (okay != 0) {
375  LOG("failed to gettimeofday!?");
376  }
377  time_t currtime_secs = currtime.tv_sec;
378  tm result;
379  tm *tz_ptr = gmtime_r(&currtime_secs, &result);
380  if (tz_ptr != &result) {
381  LOG("failed to get time for local area with gmtime_r");
382  }
383  return convert(currtime.tv_sec, currtime.tv_usec, result);
384 }
385 
386 clock_time time_now() { return now(); }
387 
388 days day_now() { return now().day_of_week; }
389 
390 months month_now() { return now().month; }
391 
392 time_number year_now() { return now().year; }
393 
394 day_in_year date_now() { return now(); }
395 
396 const char *day_name(days to_name)
397 {
398  switch (to_name) {
399  case SUNDAY: return "Sunday";
400  case MONDAY: return "Monday";
401  case TUESDAY: return "Tuesday";
402  case WEDNESDAY: return "Wednesday";
403  case THURSDAY: return "Thursday";
404  case FRIDAY: return "Friday";
405  case SATURDAY: return "Saturday";
406  default: return "Not_a_day";
407  }
408 }
409 
410 const char *month_name(months to_name)
411 {
412  switch (to_name) {
413  case JANUARY: return "January";
414  case FEBRUARY: return "February";
415  case MARCH: return "March";
416  case APRIL: return "April";
417  case MAY: return "May";
418  case JUNE: return "June";
419  case JULY: return "July";
420  case AUGUST: return "August";
421  case SEPTEMBER: return "September";
422  case OCTOBER: return "October";
423  case NOVEMBER: return "November";
424  case DECEMBER: return "December";
425  default: return "Not_a_month";
426  }
427 }
428 
429 const char *short_month_name(months to_name)
430 {
431  switch (to_name) {
432  case JANUARY: return "Jan";
433  case FEBRUARY: return "Feb";
434  case MARCH: return "Mar";
435  case APRIL: return "Apr";
436  case MAY: return "May";
437  case JUNE: return "Jun";
438  case JULY: return "Jul";
439  case AUGUST: return "Aug";
440  case SEPTEMBER: return "Sep";
441  case OCTOBER: return "Oct";
442  case NOVEMBER: return "Nov";
443  case DECEMBER: return "Dec";
444  default: return "Not";
445  }
446 }
447 
448 } // namespace.
449 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
Base class for object that can tell itself apart from other instances.
Definition: contracts.h:44
A base for objects that can be alphabetically (lexicographically) ordered.
Definition: contracts.h:57
A specific point in time as represented by a 24 hour clock.
Definition: earth_time.h:85
time_number minute
The number of minutes after the hour.
Definition: earth_time.h:88
time_number second
The number of seconds after the current minute.
Definition: earth_time.h:89
time_number microsecond
Number of microseconds elapsed in this millisecond.
Definition: earth_time.h:91
time_number hour
The hour represented in military time: 0 through 23.
Definition: earth_time.h:87
time_number millisecond
The number of milliseconds elapsed in this second.
Definition: earth_time.h:90
An object that represents a particular day in a year.
Definition: earth_time.h:139
time_number day_of_year
Numerical day, where January 1st is equal to zero.
Definition: earth_time.h:144
time_number day_in_month
The day number within the month (starting at one).
Definition: earth_time.h:142
days day_of_week
The day of the week.
Definition: earth_time.h:143
months month
The current month.
Definition: earth_time.h:141
An object that represents a particular point in time.
Definition: earth_time.h:188
basis::astring text_form_long(int t=clock_time::MERIDIAN, int d=day_in_year::SHORT_MONTH, int y=LONG_YEAR) const
Definition: earth_time.cpp:262
time_number year
The year, using the gregorian calendar.
Definition: earth_time.h:190
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define limit_value(val, max)
Definition: earth_time.cpp:134
#define EASY_LT(x, y)
Definition: earth_time.cpp:82
#define LOG(tpr)
Definition: earth_time.cpp:43
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
unsigned char abyte
A fairly important unit which is seldom defined...
Definition: definitions.h:51
void attach(byte_array &packed_form, const char *to_attach)
Packs a character string "to_attach" into "packed_form".
Definition: astring.cpp:1015
bool detach(byte_array &packed_form, astring &to_detach)
Unpacks a character string "to_attach" from "packed_form".
Definition: astring.cpp:1023
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
bool unpack(basis::byte_array &packed_form, set< contents > &to_unpack)
provides a way to unpack any set that stores packable objects.
Definition: set.h:139
void pack(basis::byte_array &packed_form, const set< contents > &to_pack)
provides a way to pack any set that stores packable objects.
Definition: set.h:131
#include <time.h>
Definition: earth_time.cpp:37
const char * month_name(months to_name)
Returns the name of the month "to_name".
Definition: earth_time.cpp:410
basis::signed_long time_number
Definition: earth_time.h:31
time_locus greenwich_now()
returns Greenwich Mean Time (their now).
Definition: earth_time.cpp:369
time_locus now()
returns our current locus in the time continuum.
Definition: earth_time.cpp:352
@ SATURDAY
Definition: earth_time.h:33
@ WEDNESDAY
Definition: earth_time.h:33
@ MONDAY
Definition: earth_time.h:33
@ FRIDAY
Definition: earth_time.h:33
@ THURSDAY
Definition: earth_time.h:33
@ TUESDAY
Definition: earth_time.h:33
@ SUNDAY
Definition: earth_time.h:33
const char * day_name(days to_name)
Returns the name of the day "to_name".
Definition: earth_time.cpp:396
@ DECEMBER
Definition: earth_time.h:42
@ OCTOBER
Definition: earth_time.h:42
@ SEPTEMBER
Definition: earth_time.h:42
@ JANUARY
Definition: earth_time.h:41
@ NOVEMBER
Definition: earth_time.h:42
@ FEBRUARY
Definition: earth_time.h:41
@ APRIL
Definition: earth_time.h:41
@ AUGUST
Definition: earth_time.h:41
@ JUNE
Definition: earth_time.h:41
@ JULY
Definition: earth_time.h:41
@ MARCH
Definition: earth_time.h:41
time_number year_now()
what year is it?
Definition: earth_time.cpp:392
const time_number leap_days_in_month[12]
The number of days in each month in a leap year.
Definition: earth_time.cpp:52
const time_number julian_days_in_month[12]
Number of days in each month based on the julian calendar.
Definition: earth_time.cpp:55
clock_time time_now()
what time is it?
Definition: earth_time.cpp:386
days day_now()
Returns the current local day.
Definition: earth_time.cpp:388
const char * short_month_name(months to_name)
Returns a shorter, constant-length (3 characters) month name.
Definition: earth_time.cpp:429
time_locus convert(time_number seconds, time_number useconds, const tm &cal_values)
Definition: earth_time.cpp:326
day_in_year date_now()
what day on the calendar is it?
Definition: earth_time.cpp:394
const time_number julian_leap_days_in_month[12]
Number of days in each month of a leap year in the julian calendar.
Definition: earth_time.cpp:59
const time_number days_in_month[12]
The number of days in each month in the standard year.
Definition: earth_time.cpp:49
months month_now()
returns the local month.
Definition: earth_time.cpp:390
time_number limit_day_of_month(time_number &day, time_number days_in_month, time_number days_in_prev_month)
Definition: earth_time.cpp:217
Support for unicode builds.