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>
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
33using namespace basis;
34using namespace structures;
35using namespace textual;
36
37namespace 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
63void 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
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
86bool 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
96bool 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
106{
107 astring to_return;
108 text_form(to_return, how);
109 return to_return;
110}
111
112void 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
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
161void 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
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
184bool 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
191bool 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
198{
199 astring to_return;
200 text_form(to_return, how);
201 return to_return;
202}
203
204void 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
230{
231 time_number rolls = 0; // rollover counter.
232 time_number daysinm = leap_year?
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
247void 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
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
262astring 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
269bool 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
277bool 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
287void 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
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
326#define static_class_name() "time_locus"
327
329 const tm &cal_values)
330{
331 FUNCDEF("convert");
332 time_locus r;
333
334 r.millisecond = useconds / 1000;
335 r.microsecond = useconds % 1000;
336
337 r.hour = cal_values.tm_hour;
338 r.minute = cal_values.tm_min;
339 r.second = cal_values.tm_sec;
340 r.day_in_month = cal_values.tm_mday;
341 r.month = months(cal_values.tm_mon);
342 r.year = cal_values.tm_year + 1900;
343 r.day_of_week = days(cal_values.tm_wday);
344 r.day_of_year = cal_values.tm_yday;
345
346 LOG(a_sprintf("convert() returning: %s\n",
350
351 return r;
352}
353
355{
356 FUNCDEF("now");
357 timeval currtime;
358 int okay = gettimeofday(&currtime, NULL_POINTER);
359 if (okay != 0) {
360 LOG("failed to gettimeofday!?");
361 }
362 time_t currtime_secs = currtime.tv_sec;
363 struct tm result;
364 tm *tz_ptr = localtime_r(&currtime_secs, &result);
365 if (tz_ptr != &result) {
366 LOG("failed to get time for local area with localtime_r");
367 }
368 return convert(currtime.tv_sec, currtime.tv_usec, result);
369}
370
372{
373 FUNCDEF("greenwich_now");
374 timeval currtime;
375 int okay = gettimeofday(&currtime, NULL_POINTER);
376 if (okay != 0) {
377 LOG("failed to gettimeofday!?");
378 }
379 time_t currtime_secs = currtime.tv_sec;
380 tm result;
381 tm *tz_ptr = gmtime_r(&currtime_secs, &result);
382 if (tz_ptr != &result) {
383 LOG("failed to get time for local area with gmtime_r");
384 }
385 return convert(currtime.tv_sec, currtime.tv_usec, result);
386}
387
388clock_time time_now() { return now(); }
389
391
392months month_now() { return now().month; }
393
395
396day_in_year date_now() { return now(); }
397
398const char *day_name(days to_name)
399{
400 switch (to_name) {
401 case SUNDAY: return "Sunday";
402 case MONDAY: return "Monday";
403 case TUESDAY: return "Tuesday";
404 case WEDNESDAY: return "Wednesday";
405 case THURSDAY: return "Thursday";
406 case FRIDAY: return "Friday";
407 case SATURDAY: return "Saturday";
408 default: return "Not_a_day";
409 }
410}
411
412const char *month_name(months to_name)
413{
414 switch (to_name) {
415 case JANUARY: return "January";
416 case FEBRUARY: return "February";
417 case MARCH: return "March";
418 case APRIL: return "April";
419 case MAY: return "May";
420 case JUNE: return "June";
421 case JULY: return "July";
422 case AUGUST: return "August";
423 case SEPTEMBER: return "September";
424 case OCTOBER: return "October";
425 case NOVEMBER: return "November";
426 case DECEMBER: return "December";
427 default: return "Not_a_month";
428 }
429}
430
431const char *short_month_name(months to_name)
432{
433 switch (to_name) {
434 case JANUARY: return "Jan";
435 case FEBRUARY: return "Feb";
436 case MARCH: return "Mar";
437 case APRIL: return "Apr";
438 case MAY: return "May";
439 case JUNE: return "Jun";
440 case JULY: return "Jul";
441 case AUGUST: return "Aug";
442 case SEPTEMBER: return "Sep";
443 case OCTOBER: return "Oct";
444 case NOVEMBER: return "Nov";
445 case DECEMBER: return "Dec";
446 default: return "Not";
447 }
448}
449
450#undef static_class_name
451
452} // namespace.
453
#define LOG(s)
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
bool operator<(const clock_time &to_compare) const
Returns true if this clock_time is earlier than "to_compare".
time_number minute
The number of minutes after the hour.
Definition earth_time.h:88
basis::astring text_form(int how=MERIDIAN) const
Prints the clock_time according to "how".
static time_number normalize(clock_time &to_fix)
@ MERIDIAN
default: uses 12 hour with AM/PM and no seconds.
Definition earth_time.h:115
@ MILITARY
use military 24 hour time.
Definition earth_time.h:116
@ MILLISECONDS
milliseconds are fourth field (after secs).
Definition earth_time.h:119
@ SECONDS
include the number of seconds as a third field.
Definition earth_time.h:118
virtual bool unpack(basis::byte_array &packed_form)
Unpacks a clock time from an array of bytes.
virtual void pack(basis::byte_array &packed_form) const
Packs a clock time into an array of bytes.
bool operator==(const clock_time &to_compare) const
Returns true if this clock_time is equal to "to_compare".
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:141
bool operator==(const day_in_year &to_compare) const
Returns true if this day is equal to "to_compare".
time_number day_of_year
Numerical day, where January 1st is equal to zero.
Definition earth_time.h:146
@ LONG_MONTH
uses full month name.
Definition earth_time.h:173
@ INCLUDE_DAY
adds the name of the day.
Definition earth_time.h:174
time_number day_in_month
The day number within the month (starting at one).
Definition earth_time.h:144
basis::astring text_form(int how=SHORT_MONTH) const
Prints the day according to "how".
days day_of_week
The day of the week.
Definition earth_time.h:145
virtual void pack(basis::byte_array &packed_form) const
Packs a day object into an array of bytes.
static time_number normalize(day_in_year &to_fix, bool leap_year=false)
normalizes the day as needed and returns the adjustment in years.
months month
The current month.
Definition earth_time.h:143
virtual bool unpack(basis::byte_array &packed_form)
Unpacks a day object from an array of bytes.
bool operator<(const day_in_year &to_compare) const
Returns true if this day is earlier than "to_compare".
An object that represents a particular point in time.
Definition earth_time.h:192
virtual bool less_than(const basis::orderable &s2) const
static time_number normalize(time_locus &to_fix)
Same as text_form() above, but stores into "to_stuff".
@ SHORT_YEAR
use only last two digits of year. ugh–Y2K danger.
Definition earth_time.h:223
@ LONG_YEAR
default: full four digit year (problems in 9999).
Definition earth_time.h:222
virtual void pack(basis::byte_array &packed_form) const
Packs a time_locus object into an array of bytes.
basis::astring text_form_long(int t=clock_time::MERIDIAN, int d=day_in_year::SHORT_MONTH, int y=LONG_YEAR) const
time_number year
The year, using the gregorian calendar.
Definition earth_time.h:194
virtual bool equal_to(const basis::equalizable &s2) const
virtual bool unpack(basis::byte_array &packed_form)
Unpacks a time_locus object from an array of bytes.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define limit_value(val, max)
#define EASY_LT(x, y)
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
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:1018
bool detach(byte_array &packed_form, astring &to_detach)
Unpacks a character string "to_attach" from "packed_form".
Definition astring.cpp:1026
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#include <time.h>
const char * month_name(months to_name)
Returns the name of the month "to_name".
basis::signed_long time_number
Definition earth_time.h:31
time_locus greenwich_now()
returns Greenwich Mean Time (their now).
time_locus now()
returns our current locus in the time continuum.
@ SATURDAY
Definition earth_time.h:33
@ WEDNESDAY
Definition earth_time.h:33
@ THURSDAY
Definition earth_time.h:33
@ TUESDAY
Definition earth_time.h:33
const char * day_name(days to_name)
Returns the name of the day "to_name".
@ 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
time_number year_now()
what year is it?
const time_number leap_days_in_month[12]
The number of days in each month in a leap year.
const time_number julian_days_in_month[12]
Number of days in each month based on the julian calendar.
clock_time time_now()
what time is it?
days day_now()
Returns the current local day.
const char * short_month_name(months to_name)
Returns a shorter, constant-length (3 characters) month name.
time_locus convert(time_number seconds, time_number useconds, const tm &cal_values)
day_in_year date_now()
what day on the calendar is it?
const time_number julian_leap_days_in_month[12]
Number of days in each month of a leap year in the julian calendar.
const time_number days_in_month[12]
The number of days in each month in the standard year.
months month_now()
returns the local month.
time_number limit_day_of_month(time_number &day, time_number days_in_month, time_number days_in_prev_month)
Support for unicode builds.