/*#io
Date ioDoc(
docCopyright("Steve Dekorte", 2002)
docLicense("BSD revised")
docDescription("A container for a date and time information.
credits: fromString method by Sean Perry")
docCategory("Time")
*/
#include "IoDate.h"
#include "IoState.h"
#include "IoCFunction.h"
#include "IoObject.h"
#include "IoSeq.h"
#include "IoNumber.h"
#include "IoDuration.h"
#include "PortableStrptime.h"
#include <string.h>
#define DATA(self) ((Date *)IoObject_dataPointer(self))
IoTag *IoDate_tag(void *state)
{
IoTag *tag = IoTag_newWithName_("Date");
tag->state = state;
tag->cloneFunc = (TagCloneFunc *)IoDate_rawClone;
tag->freeFunc = (TagFreeFunc *)IoDate_free;
tag->compareFunc = (TagCompareFunc *)IoDate_compare;
tag->writeToStoreOnStreamFunc = (TagWriteToStoreOnStreamFunc *)IoDate_writeToStore_stream_;
tag->readFromStoreOnStreamFunc = (TagReadFromStoreOnStreamFunc *)IoDate_readFromStore_stream_;
return tag;
}
void IoDate_writeToStore_stream_(IoDate *self, IoStore *store, BStream *stream)
{
BStream_writeTaggedDouble_(stream, Date_asSeconds(DATA(self)));
}
void IoDate_readFromStore_stream_(IoDate *self, IoStore *store, BStream *stream)
{
Date_fromSeconds_(DATA(self), BStream_readTaggedDouble(stream));
}
IoDate *IoDate_proto(void *state)
{
IoMethodTable methodTable[] = {
{"now", IoDate_now},
{"clock", IoDate_clock},
{"copy", IoDate_copy},
{"cpuSecondsToRun", IoDate_cpuSecondsToRun},
{"year", IoDate_year},
{"setYear", IoDate_setYear},
{"month", IoDate_month},
{"setMonth", IoDate_setMonth},
{"day", IoDate_day},
{"setDay", IoDate_setDay},
{"hour", IoDate_hour},
{"setHour", IoDate_setHour},
{"minute", IoDate_minute},
{"setMinute", IoDate_setMinute},
{"second", IoDate_second},
{"setSecond", IoDate_setSecond},
{"isDaylightSavingsTime", IoDate_isDaylightSavingsTime},
{"zone", IoDate_zone},
{"isValidTime", IoDate_isValidTime},
{"secondsSince", IoDate_secondsSince_},
{"secondsSinceNow", IoDate_secondsSinceNow},
{"isPast", IoDate_isPast},
//{"dateAfterSeconds", IoDate_dateAfterSeconds_},
{"asString", IoDate_asString},
{"asNumber", IoDate_asNumber},
{"fromNumber", IoDate_fromNumber},
{"fromString", IoDate_fromString},
{"print", IoDate_printDate},
{"+", IoDate_add},
{"-", IoDate_subtract},
{"+=", IoDate_addInPlace},
{"-=", IoDate_subtractInPlace},
{NULL, NULL},
};
IoObject *self = IoObject_new(state);
self->tag = IoDate_tag(state);
IoObject_setDataPointer_(self, Date_new());
IoObject_setSlot_to_(self, IOSYMBOL("format"), IOSYMBOL("%Y-%m-%d %H:%M:%S %Z"));
IoState_registerProtoWithFunc_((IoState *)state, self, IoDate_proto);
IoObject_addMethodTable_(self, methodTable);
return self;
}
IoDate *IoDate_rawClone(IoDate *proto)
{
IoObject *self = IoObject_rawClonePrimitive(proto);
IoObject_setDataPointer_(self, Date_new());
Date_copy_(DATA(self), DATA(proto));
return self;
}
IoDate *IoDate_new(void *state)
{
IoDate *proto = IoState_protoWithInitFunction_((IoState *)state, IoDate_proto);
return IOCLONE(proto);
}
IoDate *IoDate_newWithTime_(void *state, time_t t)
{
IoDate *self = IoDate_new(state);
Date_fromTime_(DATA(self), t);
return self;
}
IoDate *IoDate_newWithTimeval_(void *state, struct timeval tv)
{
IoDate *self = IoDate_new(state);
Date_setTimevalue_(DATA(self), tv);
return self;
}
IoDate *IoDate_newWithLocalTime_(void *state, struct tm *t)
{
IoDate *self = IoDate_new(state);
Date_fromLocalTime_(DATA(self), t);
return self;
}
void IoDate_free(IoDate *self)
{
Date_free(DATA(self));
}
int IoDate_compare(IoDate *self, IoDate *date)
{
if (ISDATE(date)) return Date_compare(DATA(self), DATA(date));
return ((ptrdiff_t)self->tag) - ((ptrdiff_t)date->tag);
}
// -----------------------------------------------------------
IoObject *IoDate_now(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("now", "Sets the receiver to the current time. Returns self.")
*/
Date_now(DATA(self));
return self;
}
IoObject *IoDate_copy(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("copy(aDate)", "Sets the receiver to be the same date as aDate. Returns self.")
*/
IoDate *date = IoMessage_locals_dateArgAt_(m, locals, 0);
Date_copy_(DATA(self), DATA(date));
return self;
}
IoObject *IoDate_clock(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("clock", "Returns a number containing the number of seconds
of processor time since the beginning of the program or -1 if unavailable. ")
*/
return IONUMBER(Date_Clock());
}
IoObject *IoDate_cpuSecondsToRun(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("cpuSecondsToRun(expression)",
"Evaluates message and returns a Number whose value is the cpu seconds taken to do the evaluation.")
*/
IoMessage_assertArgCount_receiver_(m, 1, self);
{
clock_t t = clock();
IoMessage *doMessage = IoMessage_rawArgAt_(m, 0);
IoMessage_locals_performOn_(doMessage, locals, locals);
return IONUMBER(((double)(clock() - t))/((double)CLOCKS_PER_SEC));
}
}
IoObject *IoDate_year(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("year",
"Returns a number containing the year of the receiver. ")
*/
return IONUMBER(Date_year(DATA(self)));
}
IoObject *IoDate_setYear(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setYear(aNumber)",
"Sets the year of the receiver. ")
*/
Date_setYear_(DATA(self), IoMessage_locals_intArgAt_(m, locals, 0));
return self;
}
IoObject *IoDate_month(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("month",
"Returns a number containing the month(1-12) of the year of the receiver. ")
*/
return IONUMBER(Date_month(DATA(self)));
}
IoObject *IoDate_setMonth(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setMonth(aNumber)",
"Sets the month(1-12) of the receiver. Returns self. ")
*/
int v = IoMessage_locals_intArgAt_(m, locals, 0);
IOASSERT(v >= 1 && v <= 12, "month must be within range 1-12");
Date_setMonth_(DATA(self), v);
return self;
}
IoObject *IoDate_day(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("day",
"Returns a number containing the day of the month of the receiver. ")
*/
return IONUMBER(Date_day(DATA(self)));
}
IoObject *IoDate_setDay(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setDay(aNumber)",
"Sets the day of the receiver. Returns self.")
*/
int v = IoMessage_locals_intArgAt_(m, locals, 0);
int month = Date_month(DATA(self));
IOASSERT(v >= 1 && v <= 31, "day must be within range 1-31");
if (month == 2)
{
if (Date_isLeapYear(DATA(self)))
{
IOASSERT(v >= 1 && v <= 29, "day must be within range 1-29");
}
else
{
IOASSERT(v >= 1 && v <= 28, "day must be within range 1-28");
}
} else if (month == 11)
{
IOASSERT(v >= 1 && v <= 30, "day must be within range 1-30");
} else if (month == 12)
{
IOASSERT(v >= 1 && v <= 31, "day must be within range 1-31");
}
Date_setDay_(DATA(self), v);
return self;
}
IoObject *IoDate_hour(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("hour",
"Returns a number containing the hour of the day(0-23) of the receiver. ")
*/
return IONUMBER(Date_hour(DATA(self)));
}
IoObject *IoDate_setHour(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setHour(aNumber)",
"Sets the hour of the receiver. Returns self.")
*/
int v = IoMessage_locals_intArgAt_(m, locals, 0);
IOASSERT(v >= 0 && v <= 23, "hour must be within range 0-23");
Date_setHour_(DATA(self), v);
return self;
}
IoObject *IoDate_minute(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("minute",
"Returns a number containing the minute of the hour(0-59) of the receiver. ")
*/
return IONUMBER(Date_minute(DATA(self)));
}
IoObject *IoDate_setMinute(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setMinute(aNumber)",
"Sets the minute of the receiver. Returns self.")
*/
int v = IoMessage_locals_intArgAt_(m, locals, 0);
IOASSERT(v >= 0 && v <= 59, "minute must be within range 0-59");
Date_setMinute_(DATA(self), v);
return self;
}
IoObject *IoDate_second(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("second",
"Returns a number containing the seconds of the minute(0-59) of the receiver. This number may contain fractions of seconds. ")
*/
return IONUMBER(Date_second(DATA(self)));
}
IoObject *IoDate_setSecond(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("setSecond(aNumber)",
"Sets the second of the receiver. Returns self.")
*/
int v = IoMessage_locals_intArgAt_(m, locals, 0);
IOASSERT(v >= 0 && v <= 59, "second must be within range 0-59");
Date_setSecond_(DATA(self), v);
return self;
}
IoObject *IoDate_zone(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("zone",
"Returns a string containing the time zone code of the receiver. ")
*/
time_t t = time(NULL);
const struct tm *tp = localtime(&t);
char s[32];
strftime(s, 32,"%Z", tp);
return IOSYMBOL(s);
}
IoObject *IoDate_isDaylightSavingsTime(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("isDaylightSavingsTime",
"Returns self if Daylight Saving Time is in effect for the receiver, otherwise returns Nil. ")
*/
return IOBOOL(self, Date_isDaylightSavingsTime(DATA(self)));
}
IoObject *IoDate_isValidTime(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("validTime(hour, min, sec)",
"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.")
*/
int hour = IoMessage_locals_intArgAt_(m, locals, 0);
int min = IoMessage_locals_intArgAt_(m, locals, 1);
int sec = IoMessage_locals_intArgAt_(m, locals, 2);
if (hour < 0) hour += 24;
if (min < 0) min += 60;
if (sec < 0) sec += 60;
return IOBOOL(self, ((hour >= 0) && (hour < 24)) &&
((min >= 0) && (min < 60)) &&
((sec >= 0) && (sec < 60)));
}
IoObject *IoDate_secondsSince_(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("secondsSince(aDate)",
"Returns a number of seconds of between aDate and the receiver. ")
*/
IoDate *date = IoMessage_locals_dateArgAt_(m, locals, 0);
return IONUMBER(Date_secondsSince_(DATA(self), DATA(date)));
}
IoObject *IoDate_secondsSinceNow(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("secondsSinceNow(aDate)", "Returns the number of seconds since aDate. ")
*/
return IONUMBER(Date_secondsSinceNow(DATA(self)));
}
IoObject *IoDate_isPast(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("isPast", "Returns true if the receiver is a date in the past. ")
*/
return IOBOOL(self, Date_secondsSinceNow(DATA(self)) > 0);
}
/*
IoObject *IoDate_dateAfterSeconds_(IoDate *self, IoObject *locals, IoMessage *m)
{
docSlot("dateAfterSeconds(secondsNumber)",
"Returns a new date that is secondsNumber seconds after the receiver. ")
IoDate *newDate = IoDate_new(IOSTATE);
Date_addSeconds_(DATA(newDate), IoMessage_locals_doubleArgAt_(m, locals, 0));
return newDate;
}
*/
IoObject *IoDate_asString(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("asString(optionalFormatString)",
"""Returns a string representation of the receiver using the
receivers format. If the optionalFormatString argument is present, the
receiver's format is set to it first. Formatting is according to ANSI C
date formating rules.
<pre>
%a abbreviated weekday name (Sun, Mon, etc.)
%A full weekday name (Sunday, Monday, etc.)
%b abbreviated month name (Jan, Feb, etc.)
%B full month name (January, February, etc.)
%c full date and time string
%d day of the month as two-digit decimal integer (01-31)
%H hour as two-digit 24-hour clock decimal integer (00-23)
%I hour as two-digit 12-hour clock decimal integer (01-12)
%m month as a two-digit decimal integer (01-12)
%M minute as a two-digit decimal integer (00-59)
%p either "AM" or "PM"
%S second as a two-digit decimal integer (00-59)
%U number of week in the year as two-digit decimal integer (00-52)
with Sunday considered as first day of the week
%w weekday as one-digit decimal integer (0-6) with Sunday as 0
%W number of week in the year as two-digit decimal integer (00-52)
with Monday considered as first day of the week
%x full date string (no time); in the C locale, this is equivalent
to "%m/%d/%y".
%y year without century as two-digit decimal number (00-99)
%Y year with century as four-digit decimal number
%Z time zone name (e.g. EST);
null string if no time zone can be obtained
%% stands for '%' character in output string.
</pre>
""")
*/
char *format = "%Y-%m-%d %H:%M:%S %Z";
if (IoMessage_argCount(m) == 1)
{
format = CSTRING(IoMessage_locals_symbolArgAt_(m, locals, 0));
}
else
{
IoObject *f = IoObject_getSlot_(self, IOSYMBOL("format"));
if (ISSEQ(f)) { format = CSTRING(f); }
}
{
ByteArray *ba = Date_asString(DATA(self), format);
return IoState_symbolWithByteArray_copy_(IOSTATE, ba, 0);
}
}
IoObject *IoDate_printDate(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("print", "Prints the receiver. Returns self.")
*/
IoSymbol *s = (IoSymbol *)IoDate_asString(self, locals, m);
IoSeq_print(s, locals, m);
return self;
}
IoObject *IoDate_asNumber(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("asNumber", "Returns the date as seconds since 1970.")
*/
return IONUMBER(Date_asSeconds(DATA(self)));
}
IoObject *IoDate_fromNumber(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("fromNumber(aNumber)", "Sets the receiver to be aNumber seconds since 1970.")
*/
Date_fromSeconds_(DATA(self), IoMessage_locals_doubleArgAt_(m, locals, 0));
return self;
}
IoObject *IoDate_fromString(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
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. ")
*/
IoMessage_assertArgCount_receiver_(m, 2, self);
{
IoSymbol *date_input = IoMessage_locals_seqArgAt_(m, locals, 0);
IoSymbol *format = IoMessage_locals_seqArgAt_(m, locals, 1);
Date_fromString_format_(DATA(self), CSTRING(date_input), CSTRING(format));
}
return self;
}
/* --- Durations -------------------------------------------------------- */
IoObject *IoDate_subtract(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("-(aDurationOrDate)", "Return a new Date with the receiver's value minus an amount of time specified by aDuration to the receiver. Returns self. ")
*/
IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
if (ISDATE(v))
{
double d = Date_secondsSince_(DATA(self), DATA(v));
return IoDuration_newWithSeconds_(IOSTATE, d);
}
else if (ISDURATION(v))
{
IoDate *newDate = IOCLONE(self);
Date_subtractDuration_(DATA(newDate), IoDuration_duration(v));
return newDate;
}
IOASSERT(1, "Date or Duration argument required");
return IONIL(self);
}
IoObject *IoDate_subtractInPlace(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("-=(aDuration)", "Subtract aDuration from the receiver. Returns self.")
*/
IoDuration *d = IoMessage_locals_durationArgAt_(m, locals, 0);
Date_subtractDuration_(DATA(self), IoDuration_duration(d));
return self;
}
IoObject *IoDate_addInPlace(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("+=(aDuration)", "Add aDuration to the receiver. Returns self. ")
*/
IoDuration *d = IoMessage_locals_durationArgAt_(m, locals, 0);
Date_addDuration_(DATA(self), IoDuration_duration(d));
return self;
}
IoObject *IoDate_add(IoDate *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("+(aDuration)", "Return a new Date with the receiver's value plus an amount of time specified by aDuration object to the receiver. ")
*/
IoDate *newDate = IOCLONE(self);
return IoDate_addInPlace(newDate, locals, m);
}
syntax highlighted by Code2HTML, v. 0.9.1