3 docCopyright("Steve Dekorte", 2002)
4 docLicense("BSD revised")
5 docDescription("A container for a date and time information.
6 credits: fromString method by Sean Perry")
12 #include "IoCFunction.h"
16 #include "IoDuration.h"
17 #include "PortableStrptime.h"
20 #define DATA(self) ((Date *)IoObject_dataPointer(self))
22 IoTag
*IoDate_newTag(void *state
)
24 IoTag
*tag
= IoTag_newWithName_("Date");
25 IoTag_state_(tag
, state
);
26 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoDate_rawClone
);
27 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoDate_free
);
28 IoTag_compareFunc_(tag
, (IoTagCompareFunc
*)IoDate_compare
);
29 IoTag_writeToStreamFunc_(tag
, (IoTagWriteToStreamFunc
*)IoDate_writeToStream_
);
30 IoTag_readFromStreamFunc_(tag
, (IoTagReadFromStreamFunc
*)IoDate_readFromStream_
);
34 void IoDate_writeToStream_(IoDate
*self
, BStream
*stream
)
36 BStream_writeTaggedDouble_(stream
, Date_asSeconds(DATA(self
)));
39 void IoDate_readFromStream_(IoDate
*self
, BStream
*stream
)
41 Date_fromSeconds_(DATA(self
), BStream_readTaggedDouble(stream
));
44 IoDate
*IoDate_proto(void *state
)
46 IoMethodTable methodTable
[] = {
48 {"clock", IoDate_clock
},
49 {"copy", IoDate_copy
},
50 {"cpuSecondsToRun", IoDate_cpuSecondsToRun
},
51 {"year", IoDate_year
},
52 {"setYear", IoDate_setYear
},
53 {"month", IoDate_month
},
54 {"setMonth", IoDate_setMonth
},
56 {"setDay", IoDate_setDay
},
57 {"hour", IoDate_hour
},
58 {"setHour", IoDate_setHour
},
59 {"minute", IoDate_minute
},
60 {"setMinute", IoDate_setMinute
},
61 {"second", IoDate_second
},
62 {"setSecond", IoDate_setSecond
},
63 {"isDaylightSavingsTime", IoDate_isDaylightSavingsTime
},
64 {"zone", IoDate_zone
},
65 {"gmtOffset", IoDate_gmtOffset
},
66 {"gmtOffsetSeconds", IoDate_gmtOffsetSeconds
},
67 {"isValidTime", IoDate_isValidTime
},
68 {"secondsSince", IoDate_secondsSince_
},
69 {"secondsSinceNow", IoDate_secondsSinceNow
},
70 {"isPast", IoDate_isPast
},
71 //{"dateAfterSeconds", IoDate_dateAfterSeconds_},
72 {"asString", IoDate_asString
},
73 {"asNumber", IoDate_asNumber
},
74 {"fromNumber", IoDate_fromNumber
},
75 {"fromString", IoDate_fromString
},
76 {"print", IoDate_printDate
},
78 {"-", IoDate_subtract
},
79 {"+=", IoDate_addInPlace
},
80 {"-=", IoDate_subtractInPlace
},
84 IoObject
*self
= IoObject_new(state
);
86 IoObject_tag_(self
, IoDate_newTag(state
));
87 IoObject_setDataPointer_(self
, Date_new());
91 "Returns the format string for the receiver. Tthe default is \"%Y-%m-%d %H:%M:%S %Z\".")
93 IoObject_setSlot_to_(self
, IOSYMBOL("format"), IOSYMBOL("%Y-%m-%d %H:%M:%S %Z"));
94 IoState_registerProtoWithFunc_((IoState
*)state
, self
, IoDate_proto
);
96 IoObject_addMethodTable_(self
, methodTable
);
100 IoDate
*IoDate_rawClone(IoDate
*proto
)
102 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
103 IoObject_setDataPointer_(self
, Date_new());
104 Date_copy_(DATA(self
), DATA(proto
));
108 IoDate
*IoDate_new(void *state
)
110 IoDate
*proto
= IoState_protoWithInitFunction_((IoState
*)state
, IoDate_proto
);
111 return IOCLONE(proto
);
114 IoDate
*IoDate_newWithTime_(void *state
, time_t t
)
116 IoDate
*self
= IoDate_new(state
);
117 Date_fromTime_(DATA(self
), t
);
121 IoDate
*IoDate_newWithTimeval_(void *state
, struct timeval tv
)
123 IoDate
*self
= IoDate_new(state
);
128 IoDate
*IoDate_newWithLocalTime_(void *state
, struct tm
*t
)
130 IoDate
*self
= IoDate_new(state
);
131 Date_fromLocalTime_(DATA(self
), t
);
135 void IoDate_free(IoDate
*self
)
137 Date_free(DATA(self
));
140 int IoDate_compare(IoDate
*self
, IoDate
*date
)
142 if (ISDATE(date
)) return Date_compare(DATA(self
), DATA(date
));
143 return IoObject_defaultCompare(self
, date
);
146 // -----------------------------------------------------------
148 IoObject
*IoDate_now(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
151 docSlot("now", "Sets the receiver to the current time. Returns self.")
154 Date_now(DATA(self
));
158 IoObject
*IoDate_copy(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
161 docSlot("copy(aDate)", "Sets the receiver to be the same date as aDate. Returns self.")
164 IoDate
*date
= IoMessage_locals_dateArgAt_(m
, locals
, 0);
166 Date_copy_(DATA(self
), DATA(date
));
170 IoObject
*IoDate_clock(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
173 docSlot("clock", "Returns a number containing the number of seconds
174 of processor time since the beginning of the program or -1 if unavailable. ")
177 return IONUMBER(Date_Clock());
180 IoObject
*IoDate_cpuSecondsToRun(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
183 docSlot("cpuSecondsToRun(expression)",
184 "Evaluates message and returns a Number whose value is the cpu seconds taken to do the evaluation.")
187 IoMessage_assertArgCount_receiver_(m
, 1, self
);
190 double t2
, t1
= clock();
191 IoMessage
*doMessage
= IoMessage_rawArgAt_(m
, 0);
192 IoMessage_locals_performOn_(doMessage
, locals
, locals
);
194 //printf(" dt = %f / %i\n", (float)(t2 - t1), CLOCKS_PER_SEC);
195 return IONUMBER((t2
- t1
)/((double)CLOCKS_PER_SEC
));
199 IoObject
*IoDate_year(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
203 "Returns a number containing the year of the receiver. ")
206 return IONUMBER(Date_year(DATA(self
)));
209 IoObject
*IoDate_setYear(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
212 docSlot("setYear(aNumber)",
213 "Sets the year of the receiver. ")
216 Date_setYear_(DATA(self
), IoMessage_locals_intArgAt_(m
, locals
, 0));
220 IoObject
*IoDate_month(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
224 "Returns a number containing the month(1-12) of the year of the receiver. ")
227 return IONUMBER(Date_month(DATA(self
)) + 1);
230 IoObject
*IoDate_setMonth(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
233 docSlot("setMonth(aNumber)",
234 "Sets the month(1-12) of the receiver. Returns self. ")
237 int v
= IoMessage_locals_intArgAt_(m
, locals
, 0);
238 IOASSERT(v
>= 1 && v
<= 12, "month must be within range 1-12");
239 Date_setMonth_(DATA(self
), v
- 1);
243 IoObject
*IoDate_day(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
247 "Returns a number containing the day of the month of the receiver. ")
250 return IONUMBER(Date_day(DATA(self
)));
253 IoObject
*IoDate_setDay(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
256 docSlot("setDay(aNumber)",
257 "Sets the day of the receiver. Returns self.")
260 int v
= IoMessage_locals_intArgAt_(m
, locals
, 0);
261 int month
= Date_month(DATA(self
)) + 1;
263 IOASSERT(v
>= 1 && v
<= 31, "day must be within range 1-31");
267 if (Date_isLeapYear(DATA(self
)))
269 IOASSERT(v
>= 1 && v
<= 29, "day must be within range 1-29");
273 IOASSERT(v
>= 1 && v
<= 28, "day must be within range 1-28");
276 else if (month
== 11)
278 IOASSERT(v
>= 1 && v
<= 30, "day must be within range 1-30");
280 else if (month
== 12)
282 IOASSERT(v
>= 1 && v
<= 31, "day must be within range 1-31");
285 Date_setDay_(DATA(self
), v
);
289 IoObject
*IoDate_hour(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
293 "Returns a number containing the hour of the day(0-23) of the receiver. ")
296 return IONUMBER(Date_hour(DATA(self
)));
299 IoObject
*IoDate_setHour(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
302 docSlot("setHour(aNumber)",
303 "Sets the hour of the receiver. Returns self.")
306 int v
= IoMessage_locals_intArgAt_(m
, locals
, 0);
307 IOASSERT(v
>= 0 && v
<= 23, "hour must be within range 0-23");
308 Date_setHour_(DATA(self
), v
);
312 IoObject
*IoDate_minute(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
316 "Returns a number containing the minute of the hour(0-59) of the receiver. ")
319 return IONUMBER(Date_minute(DATA(self
)));
323 IoObject
*IoDate_setMinute(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
326 docSlot("setMinute(aNumber)",
327 "Sets the minute of the receiver. Returns self.")
330 int v
= IoMessage_locals_intArgAt_(m
, locals
, 0);
331 IOASSERT(v
>= 0 && v
<= 59, "minute must be within range 0-59");
332 Date_setMinute_(DATA(self
), v
);
336 IoObject
*IoDate_second(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
340 "Returns a number containing the seconds of the minute(0-59) of the receiver. This number may contain fractions of seconds. ")
343 return IONUMBER(Date_second(DATA(self
)));
347 IoObject
*IoDate_setSecond(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
350 docSlot("setSecond(aNumber)",
351 "Sets the second of the receiver. Returns self.")
354 int v
= IoMessage_locals_intArgAt_(m
, locals
, 0);
355 IOASSERT(v
>= 0 && v
<= 59, "second must be within range 0-59");
356 Date_setSecond_(DATA(self
), v
);
360 IoObject
*IoDate_zone(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
363 docSlot("zone", "Returns a string containing the system's time zone code. ")
366 time_t t
= time(NULL
);
367 const struct tm
*tp
= localtime(&t
);
369 strftime(s
, 32,"%Z", tp
);
373 IoObject
*IoDate_gmtOffsetSeconds(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
376 docSlot("gmtOffsetSeconds", "Returns the system's seconds east of UTC.")
379 time_t t
= time(NULL
);
380 const struct tm
*tp
= localtime(&t
);
381 #if defined(__CYGWIN__) || defined(_WIN32)
382 return IONUMBER(_timezone
);
384 return IONUMBER(tp
->tm_gmtoff
);
388 IoObject
*IoDate_gmtOffset(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
391 docSlot("gmtOffset", "Returns the system's timezone string. E.g., +1300 or -0500.")
394 time_t t
= time(NULL
);
395 const struct tm
*tp
= localtime(&t
);
398 #if defined(__CYGWIN__) || defined(_WIN32)
399 int minutes
= _timezone
/ 60;
401 int minutes
= tp
->tm_gmtoff
/ 60;
403 snprintf(buf
, sizeof(buf
), "%+03d%02d", minutes
/ 60, minutes
% 60);
405 return IOSYMBOL(buf
);
408 IoObject
*IoDate_isDaylightSavingsTime(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
411 docSlot("isDaylightSavingsTime",
412 "Returns self if Daylight Saving Time is in effect for the receiver, otherwise returns Nil. ")
415 return IOBOOL(self
, Date_isDaylightSavingsTime(DATA(self
)));
418 IoObject
*IoDate_isValidTime(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
421 docSlot("isValidTime(hour, min, sec)",
422 "Returns self if the specified time is valid, otherwise returns Nil. A negative value will count back; i.e., a value of -5 for the hour, will count back 5 hours to return a value of 19. No adjustment is done for values above 24.")
425 int hour
= IoMessage_locals_intArgAt_(m
, locals
, 0);
426 int min
= IoMessage_locals_intArgAt_(m
, locals
, 1);
427 int sec
= IoMessage_locals_intArgAt_(m
, locals
, 2);
429 if (hour
< 0) hour
+= 24;
430 if (min
< 0) min
+= 60;
431 if (sec
< 0) sec
+= 60;
433 return IOBOOL(self
, ((hour
>= 0) && (hour
< 24)) &&
434 ((min
>= 0) && (min
< 60)) &&
435 ((sec
>= 0) && (sec
< 60)));
438 IoObject
*IoDate_secondsSince_(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
441 docSlot("secondsSince(aDate)",
442 "Returns a number of seconds of between aDate and the receiver. ")
445 IoDate
*date
= IoMessage_locals_dateArgAt_(m
, locals
, 0);
446 return IONUMBER(Date_secondsSince_(DATA(self
), DATA(date
)));
449 IoObject
*IoDate_secondsSinceNow(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
452 docSlot("secondsSinceNow(aDate)", "Returns the number of seconds since aDate. ")
455 return IONUMBER(Date_secondsSinceNow(DATA(self
)));
458 IoObject
*IoDate_isPast(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
461 docSlot("isPast", "Returns true if the receiver is a date in the past. ")
464 return IOBOOL(self
, Date_secondsSinceNow(DATA(self
)) > 0);
468 IoObject *IoDate_dateAfterSeconds_(IoDate *self, IoObject *locals, IoMessage *m)
470 docSlot("dateAfterSeconds(secondsNumber)",
471 "Returns a new date that is secondsNumber seconds after the receiver. ")
473 IoDate *newDate = IoDate_new(IOSTATE);
474 Date_addSeconds_(DATA(newDate), IoMessage_locals_doubleArgAt_(m, locals, 0));
479 IoObject
*IoDate_asString(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
482 docSlot("asString(optionalFormatString)",
483 """Returns a string representation of the receiver using the
484 receivers format. If the optionalFormatString argument is present, the
485 receiver's format is set to it first. Formatting is according to ANSI C
486 date formating rules.
489 %a abbreviated weekday name (Sun, Mon, etc.)
490 %A full weekday name (Sunday, Monday, etc.)
491 %b abbreviated month name (Jan, Feb, etc.)
492 %B full month name (January, February, etc.)
493 %c full date and time string
494 %d day of the month as two-digit decimal integer (01-31)
495 %H hour as two-digit 24-hour clock decimal integer (00-23)
496 %I hour as two-digit 12-hour clock decimal integer (01-12)
497 %m month as a two-digit decimal integer (01-12)
498 %M minute as a two-digit decimal integer (00-59)
499 %p either "AM" or "PM"
500 %S second as a two-digit decimal integer (00-59)
501 %U number of week in the year as two-digit decimal integer (00-52)
502 with Sunday considered as first day of the week
503 %w weekday as one-digit decimal integer (0-6) with Sunday as 0
504 %W number of week in the year as two-digit decimal integer (00-52)
505 with Monday considered as first day of the week
506 %x full date string (no time); in the C locale, this is equivalent
508 %y year without century as two-digit decimal number (00-99)
509 %Y year with century as four-digit decimal number
510 %Z time zone name (e.g. EST);
511 null string if no time zone can be obtained
512 %% stands for '%' character in output string.
517 char *format
= "%Y-%m-%d %H:%M:%S %Z";
519 if (IoMessage_argCount(m
) == 1)
521 format
= CSTRING(IoMessage_locals_symbolArgAt_(m
, locals
, 0));
525 IoObject
*f
= IoObject_getSlot_(self
, IOSYMBOL("format"));
526 if (ISSEQ(f
)) { format
= CSTRING(f
); }
530 UArray
*ba
= Date_asString(DATA(self
), format
);
531 return IoState_symbolWithUArray_copy_(IOSTATE
, ba
, 0);
535 IoObject
*IoDate_printDate(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
538 docSlot("print", "Prints the receiver. Returns self.")
541 IoSymbol
*s
= (IoSymbol
*)IoDate_asString(self
, locals
, m
);
542 IoSeq_print(s
, locals
, m
);
546 IoObject
*IoDate_asNumber(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
549 docSlot("asNumber", "Returns the date as seconds since 1970.")
552 return IONUMBER(Date_asSeconds(DATA(self
)));
555 IoObject
*IoDate_fromNumber(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
558 docSlot("fromNumber(aNumber)", "Sets the receiver to be aNumber seconds since 1970.")
561 Date_fromSeconds_(DATA(self
), IoMessage_locals_doubleArgAt_(m
, locals
, 0));
565 IoObject
*IoDate_fromString(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
568 docSlot("fromString(aString, formatString)", "Sets the receiver to the date specified by aString as parsed according to the given formatString. See the Date asString method for formating rules. Returns self. ")
571 IoMessage_assertArgCount_receiver_(m
, 2, self
);
573 IoSymbol
*date_input
= IoMessage_locals_seqArgAt_(m
, locals
, 0);
574 IoSymbol
*format
= IoMessage_locals_seqArgAt_(m
, locals
, 1);
575 Date_fromString_format_(DATA(self
), CSTRING(date_input
), CSTRING(format
));
580 /* --- Durations -------------------------------------------------------- */
582 IoObject
*IoDate_subtract(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
585 docSlot("-(aDurationOrDate)", "Return a new Date with the receiver's value minus an amount of time specified by aDuration to the receiver. Returns self. ")
588 IoObject
*v
= IoMessage_locals_valueArgAt_(m
, locals
, 0);
592 double d
= Date_secondsSince_(DATA(self
), DATA(v
));
593 return IoDuration_newWithSeconds_(IOSTATE
, d
);
595 else if (ISDURATION(v
))
597 IoDate
*newDate
= IOCLONE(self
);
598 Date_subtractDuration_(DATA(newDate
), IoDuration_duration(v
));
602 IOASSERT(1, "Date or Duration argument required");
607 IoObject
*IoDate_subtractInPlace(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
610 docSlot("-=(aDuration)", "Subtract aDuration from the receiver. Returns self.")
613 IoDuration
*d
= IoMessage_locals_durationArgAt_(m
, locals
, 0);
614 Date_subtractDuration_(DATA(self
), IoDuration_duration(d
));
618 IoObject
*IoDate_addInPlace(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
621 docSlot("+=(aDuration)", "Add aDuration to the receiver. Returns self. ")
624 IoDuration
*d
= IoMessage_locals_durationArgAt_(m
, locals
, 0);
625 Date_addDuration_(DATA(self
), IoDuration_duration(d
));
629 IoObject
*IoDate_add(IoDate
*self
, IoObject
*locals
, IoMessage
*m
)
632 docSlot("+(aDuration)", "Return a new Date with the receiver's value plus an amount of time specified by aDuration object to the receiver. ")
635 IoDate
*newDate
= IOCLONE(self
);
636 return IoDate_addInPlace(newDate
, locals
, m
);