1
2 //metadoc Date category Core
3 //metadoc Date copyright Steve Dekorte 2002
4 //metadoc Date license BSD revised
5 /*metadoc Date description A container for a date and time information.*/
6 //metadoc Date credits fromString method by Sean Perry
7
8 #include "IoDate.h"
9 #include "IoState.h"
10 #include "IoCFunction.h"
11 #include "IoObject.h"
12 #include "IoSeq.h"
13 #include "IoNumber.h"
14 #include "IoDuration.h"
15 #include "PortableStrptime.h"
16 #include <string.h>
17 #include <time.h>
18
19 static const char *protoId = "Date";
20
21 #define DATA(self) ((Date *)IoObject_dataPointer(self))
22
IoDate_newTag(void * state)23 IoTag *IoDate_newTag(void *state)
24 {
25 IoTag *tag = IoTag_newWithName_(protoId);
26 IoTag_state_(tag, state);
27 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoDate_rawClone);
28 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoDate_free);
29 IoTag_compareFunc_(tag, (IoTagCompareFunc *)IoDate_compare);
30 return tag;
31 }
32
IoDate_proto(void * state)33 IoDate *IoDate_proto(void *state)
34 {
35 IoMethodTable methodTable[] = {
36 {"asSerialization", IoDate_asSerialization},
37 {"fromSerialization", IoDate_fromSerialization},
38 {"now", IoDate_now},
39 {"clock", IoDate_clock},
40 {"copy", IoDate_copy},
41 {"cpuSecondsToRun", IoDate_cpuSecondsToRun},
42 {"year", IoDate_year},
43 {"setYear", IoDate_setYear},
44 {"month", IoDate_month},
45 {"setMonth", IoDate_setMonth},
46 {"day", IoDate_day},
47 {"setDay", IoDate_setDay},
48 {"hour", IoDate_hour},
49 {"setHour", IoDate_setHour},
50 {"minute", IoDate_minute},
51 {"setMinute", IoDate_setMinute},
52 {"second", IoDate_second},
53 {"setSecond", IoDate_setSecond},
54 {"isDaylightSavingsTime", IoDate_isDaylightSavingsTime},
55 {"zone", IoDate_zone},
56 {"isDST", IoDate_isDST},
57 {"setGmtOffset", IoDate_setGmtOffset},
58 {"gmtOffset", IoDate_gmtOffset},
59 {"gmtOffsetSeconds", IoDate_gmtOffsetSeconds},
60 {"convertToUTC", IoDate_convertToUTC},
61 {"convertToZone", IoDate_convertToZone},
62 {"convertToLocal", IoDate_convertToLocal},
63 {"setToUTC", IoDate_setToUTC},
64 {"isValidTime", IoDate_isValidTime},
65 {"secondsSince", IoDate_secondsSince_},
66 {"secondsSinceNow", IoDate_secondsSinceNow},
67 {"isPast", IoDate_isPast},
68 //{"dateAfterSeconds", IoDate_dateAfterSeconds_},
69 {"asString", IoDate_asString},
70 {"asNumber", IoDate_asNumber},
71 {"fromNumber", IoDate_fromNumber},
72 {"fromString", IoDate_fromString},
73 {"print", IoDate_printDate},
74 {"+", IoDate_add},
75 {"-", IoDate_subtract},
76 {"+=", IoDate_addInPlace},
77 {"-=", IoDate_subtractInPlace},
78 {NULL, NULL},
79 };
80
81 IoObject *self = IoObject_new(state);
82
83 IoObject_tag_(self, IoDate_newTag(state));
84 IoObject_setDataPointer_(self, Date_new());
85
86 /*doc Date format
87 Returns the format string for the receiver. The default is "%Y-%m-%d %H:%M:%S %Z".
88 */
89
90 IoObject_setSlot_to_(self, IOSYMBOL("format"), IOSYMBOL("%Y-%m-%d %H:%M:%S %Z"));
91 IoState_registerProtoWithId_((IoState *)state, self, protoId);
92
93 IoObject_addMethodTable_(self, methodTable);
94 return self;
95 }
96
IoDate_rawClone(IoDate * proto)97 IoDate *IoDate_rawClone(IoDate *proto)
98 {
99 IoObject *self = IoObject_rawClonePrimitive(proto);
100 IoObject_setDataPointer_(self, Date_new());
101 Date_copy_(DATA(self), DATA(proto));
102 return self;
103 }
104
IoDate_new(void * state)105 IOVM_API IoDate *IoDate_new(void *state)
106 {
107 IoDate *proto = IoState_protoWithId_((IoState *)state, protoId);
108 return IOCLONE(proto);
109 }
110
IoDate_newWithTime_(void * state,time_t t)111 IOVM_API IoDate *IoDate_newWithTime_(void *state, time_t t)
112 {
113 IoDate *self = IoDate_new(state);
114 Date_fromTime_(DATA(self), t);
115 return self;
116 }
117
IoDate_newWithTimeval_(void * state,struct timeval tv)118 IOVM_API IoDate *IoDate_newWithTimeval_(void *state, struct timeval tv)
119 {
120 IoDate *self = IoDate_new(state);
121 DATA(self)->tv = tv;
122 return self;
123 }
124
IoDate_newWithLocalTime_(void * state,struct tm * t)125 IOVM_API IoDate *IoDate_newWithLocalTime_(void *state, struct tm *t)
126 {
127 IoDate *self = IoDate_new(state);
128 Date_fromLocalTime_(DATA(self), t);
129 return self;
130 }
131
IoDate_free(IoDate * self)132 void IoDate_free(IoDate *self)
133 {
134 Date_free(DATA(self));
135 }
136
IoDate_compare(IoDate * self,IoDate * date)137 int IoDate_compare(IoDate *self, IoDate *date)
138 {
139 if (ISDATE(date)) return Date_compare(DATA(self), DATA(date));
140 return IoObject_defaultCompare(self, date);
141 }
142
143 // -----------------------------------------------------------
144
IoDate_asSerialization(IoDate * self,IoObject * locals,IoMessage * m)145 IoSeq *IoDate_asSerialization(IoDate *self, IoObject *locals, IoMessage *m)
146 {
147 /*doc Date asSerialization
148 Returns a serialization (sequence) of the date that allows for perfect reconstruction of the timestamp.
149 */
150
151 return IoSeq_newWithUArray_copy_(IOSTATE, (UArray *) Date_asSerialization(DATA(self)), 0);
152 }
153
IoDate_fromSerialization(IoDate * self,IoObject * locals,IoMessage * m)154 IoDate *IoDate_fromSerialization(IoDate *self, IoObject *locals, IoMessage *m)
155 {
156 /*doc Date fromSerialization
157 Sets the date based on the serialization sequence. Return self.
158 */
159
160 IoSeq *serializationSeq = IoMessage_locals_seqArgAt_(m, locals, 0);
161 UArray *serialization = UArray_clone(IoSeq_rawUArray(serializationSeq));
162
163 UArray_setItemType_(serialization, CTYPE_int32_t);
164 if(UArray_size(serialization) != 4)
165 {
166 IoState_error_(IOSTATE, self, "Expected a serialization sequence comprising 4 int32 items.");
167 }
168
169 Date_fromSerialization(DATA(self), serialization);
170
171 UArray_free(serialization);
172
173 return self;
174 }
175
IO_METHOD(IoDate,now)176 IO_METHOD(IoDate, now)
177 {
178 /*doc Date now
179 Sets the receiver to the current time. Returns self.
180 */
181
182 Date_now(DATA(self));
183 return self;
184 }
185
IO_METHOD(IoDate,copy)186 IO_METHOD(IoDate, copy)
187 {
188 /*doc Date copy(aDate)
189 Sets the receiver to be the same date as aDate. Returns self.
190 */
191
192 IoDate *date = IoMessage_locals_dateArgAt_(m, locals, 0);
193
194 Date_copy_(DATA(self), DATA(date));
195 return self;
196 }
197
IO_METHOD(IoDate,clock)198 IO_METHOD(IoDate, clock)
199 {
200 /*doc Date clock
201 Returns a number containing the number of seconds
202 of processor time since the beginning of the program or -1 if unavailable.
203 */
204
205 return IONUMBER(Date_Clock());
206 }
207
IO_METHOD(IoDate,cpuSecondsToRun)208 IO_METHOD(IoDate, cpuSecondsToRun)
209 {
210 /*doc Date cpuSecondsToRun(expression)
211 Evaluates message and returns a Number whose value
212 is the cpu seconds taken to do the evaluation.
213 */
214
215 IoMessage_assertArgCount_receiver_(m, 1, self);
216
217 {
218 double t2, t1 = clock();
219 IoMessage *doMessage = IoMessage_rawArgAt_(m, 0);
220 IoMessage_locals_performOn_(doMessage, locals, locals);
221 t2 = clock();
222 return IONUMBER((t2 - t1)/((double)CLOCKS_PER_SEC));
223 }
224 }
225
IO_METHOD(IoDate,year)226 IO_METHOD(IoDate, year)
227 {
228 /*doc Date year
229 Returns a number containing the year of the receiver.
230 */
231
232 return IONUMBER(Date_year(DATA(self)));
233 }
234
IO_METHOD(IoDate,setYear)235 IO_METHOD(IoDate, setYear)
236 {
237 /*doc Date setYear(aNumber)
238 Sets the year of the receiver.
239 */
240
241 Date_setYear_(DATA(self), IoMessage_locals_intArgAt_(m, locals, 0));
242 return self;
243 }
244
IO_METHOD(IoDate,month)245 IO_METHOD(IoDate, month)
246 {
247 /*doc Date month
248 Returns a number containing the month(1-12) of the year of the receiver.
249 */
250
251 return IONUMBER(Date_month(DATA(self)) + 1);
252 }
253
IO_METHOD(IoDate,setMonth)254 IO_METHOD(IoDate, setMonth)
255 {
256 /*doc Date setMonth(aNumber)
257 Sets the month(1-12) of the receiver. Returns self.
258 */
259
260 int v = IoMessage_locals_intArgAt_(m, locals, 0);
261 IOASSERT(v >= 1 && v <= 12, "month must be within range 1-12");
262 Date_setMonth_(DATA(self), v - 1);
263 return self;
264 }
265
IO_METHOD(IoDate,day)266 IO_METHOD(IoDate, day)
267 {
268 /*doc Date day
269 Returns a number containing the day of the month of the receiver.
270 */
271
272 return IONUMBER(Date_day(DATA(self)));
273 }
274
IO_METHOD(IoDate,setDay)275 IO_METHOD(IoDate, setDay)
276 {
277 /*doc Date setDay(aNumber)
278 Sets the day of the receiver. Returns self.
279 */
280
281 int v = IoMessage_locals_intArgAt_(m, locals, 0);
282 int month = Date_month(DATA(self)) + 1;
283
284 IOASSERT(v >= 1 && v <= 31, "day must be within range 1-31");
285
286 if (month == 2)
287 {
288 if (Date_isLeapYear(DATA(self)))
289 {
290 IOASSERT(v >= 1 && v <= 29, "day must be within range 1-29");
291 }
292 else
293 {
294 IOASSERT(v >= 1 && v <= 28, "day must be within range 1-28");
295 }
296 }
297 else if (month == 11)
298 {
299 IOASSERT(v >= 1 && v <= 30, "day must be within range 1-30");
300 }
301 else if (month == 12)
302 {
303 IOASSERT(v >= 1 && v <= 31, "day must be within range 1-31");
304 }
305
306 Date_setDay_(DATA(self), v);
307 IoObject_isDirty_(self, 1);
308 return self;
309 }
310
IO_METHOD(IoDate,hour)311 IO_METHOD(IoDate, hour)
312 {
313 /*doc Date hour
314 Returns a number containing the hour of the day(0-23) of the receiver.
315 */
316
317 return IONUMBER(Date_hour(DATA(self)));
318 }
319
IO_METHOD(IoDate,setHour)320 IO_METHOD(IoDate, setHour)
321 {
322 /*doc Date setHour(aNumber)
323 Sets the hour of the receiver. Returns self.
324 */
325
326 int v = IoMessage_locals_intArgAt_(m, locals, 0);
327 IOASSERT(v >= 0 && v <= 23, "hour must be within range 0-23");
328 Date_setHour_(DATA(self), v);
329 IoObject_isDirty_(self, 1);
330 return self;
331 }
332
IO_METHOD(IoDate,minute)333 IO_METHOD(IoDate, minute)
334 {
335 /*doc Date minute
336 Returns a number containing the minute of the hour(0-59) of the receiver.
337 */
338
339 return IONUMBER(Date_minute(DATA(self)));
340 }
341
342
IO_METHOD(IoDate,setMinute)343 IO_METHOD(IoDate, setMinute)
344 {
345 /*doc Date setMinute(aNumber)
346 Sets the minute of the receiver. Returns self.
347 */
348
349 int v = IoMessage_locals_intArgAt_(m, locals, 0);
350 IOASSERT(v >= 0 && v <= 59, "minute must be within range 0-59");
351 Date_setMinute_(DATA(self), v);
352 IoObject_isDirty_(self, 1);
353 return self;
354 }
355
IO_METHOD(IoDate,second)356 IO_METHOD(IoDate, second)
357 {
358 /*doc Date second
359 Returns a number containing the seconds of the minute(0-59) of the receiver. This number may contain fractions of seconds.
360 */
361
362 return IONUMBER(Date_second(DATA(self)));
363 }
364
365
IO_METHOD(IoDate,setSecond)366 IO_METHOD(IoDate, setSecond)
367 {
368 /*doc Date setSecond(aNumber)
369 Sets the second of the receiver. Returns self.
370 */
371
372 int v = IoMessage_locals_intArgAt_(m, locals, 0);
373 IOASSERT(v >= 0 && v <= 59, "second must be within range 0-59");
374 Date_setSecond_(DATA(self), v);
375 IoObject_isDirty_(self, 1);
376 return self;
377 }
378
IO_METHOD(IoDate,zone)379 IO_METHOD(IoDate, zone)
380 {
381 /*doc Date zone
382 Returns a string containing the system's time zone code.
383 */
384
385 time_t t = time(NULL);
386 const struct tm *tp = localtime(&t);
387 char s[32];
388 strftime(s, 32,"%Z", tp);
389 return IOSYMBOL(s);
390 }
391
IO_METHOD(IoDate,isDST)392 IO_METHOD(IoDate, isDST)
393 {
394 /*doc Date isDST
395 Returns true if the Date is set to use DST. Posix only.
396 */
397
398 struct timezone tz = Date_timeZone(DATA(self));
399 #if defined(__CYGWIN__) || defined(_WIN32)
400 IoState_error_(IOSTATE, m, "Not implemented on Windows.");
401 return IONIL(self);
402 #else
403 return IOBOOL(self, tz.tz_dsttime);
404 #endif
405 }
406
IO_METHOD(IoDate,gmtOffsetSeconds)407 IO_METHOD(IoDate, gmtOffsetSeconds)
408 {
409 /*doc Date gmtOffsetSeconds
410 Returns the system's seconds east of UTC.
411 */
412
413 time_t t = time(NULL);
414 const struct tm *tp = localtime(&t);
415 #if defined(__CYGWIN__) || defined(_WIN32)
416 return IONUMBER(_timezone);
417 #else
418 return IONUMBER(tp->tm_gmtoff);
419 #endif
420 }
421
IO_METHOD(IoDate,setGmtOffset)422 IO_METHOD(IoDate, setGmtOffset)
423 {
424 /*doc Date setGmtOffset
425 Set the number of minutes west of GMT for this Date's zone
426 */
427
428 struct timezone tz = Date_timeZone(DATA(self));
429 tz.tz_minuteswest = IoMessage_locals_intArgAt_(m, locals, 0);
430 Date_setTimeZone_(DATA(self), tz);
431 IoObject_isDirty_(self, 1);
432 return self;
433 }
434
IO_METHOD(IoDate,gmtOffset)435 IO_METHOD(IoDate, gmtOffset)
436 {
437 /*doc Date gmtOffset
438 Returns the system's timezone string. E.g., +1300 or -0500.
439 */
440
441 time_t t = time(NULL);
442 const struct tm *tp = localtime(&t);
443
444 char buf[6];
445 #if defined(__CYGWIN__) || defined(_WIN32)
446 int minutes = _timezone / 60;
447 #else
448 int minutes = (int)(tp->tm_gmtoff / 60);
449 #endif
450 snprintf(buf, sizeof(buf), "%+03d%02d", minutes / 60, minutes % 60);
451
452 return IOSYMBOL(buf);
453 }
454
IO_METHOD(IoDate,convertToUTC)455 IO_METHOD(IoDate, convertToUTC)
456 {
457 /*doc Date convertToUTC
458 Converts self from a local date to the equivalent UTC date
459 */
460
461 struct timezone tz;
462 tz.tz_minuteswest = 0;
463 tz.tz_dsttime = 0;
464 Date_convertToTimeZone_(DATA(self), tz);
465 IoObject_isDirty_(self, 1);
466 return self;
467 }
468
IO_METHOD(IoDate,convertToZone)469 IO_METHOD(IoDate, convertToZone)
470 {
471 /*doc Date convertToZone(offset, isDST)
472 Converts self to an equivalent data in a zone with offset (minutes west) and DST (true, false).
473 */
474
475 struct timezone tz;
476
477 int mw = IoMessage_locals_intArgAt_(m, locals, 0);
478 int dst = IoMessage_locals_boolArgAt_(m, locals, 1);
479
480 tz.tz_minuteswest = mw;
481 tz.tz_dsttime = dst;
482 Date_convertToTimeZone_(DATA(self), tz);
483 IoObject_isDirty_(self, 1);
484 return self;
485 }
486
IO_METHOD(IoDate,convertToLocal)487 IO_METHOD(IoDate, convertToLocal)
488 {
489 /*doc Date convertToLocal
490 Converts self date from a UTC date to the equivalent local date
491 */
492
493 struct timeval tv;
494 struct timezone tz;
495
496 gettimeofday(&tv, &tz);
497
498 Date_convertToTimeZone_(DATA(self), tz);
499 IoObject_isDirty_(self, 1);
500 return self;
501 }
502
IO_METHOD(IoDate,setToUTC)503 IO_METHOD(IoDate, setToUTC)
504 {
505 /*doc Date asUTC
506 Changes the timezone of this date to utc
507 */
508
509 struct timezone tz;
510 tz.tz_minuteswest = 0;
511 tz.tz_dsttime = 0;
512
513 Date_setTimeZone_(DATA(self), tz);
514 IoObject_isDirty_(self, 1);
515
516 return self;
517 }
518
IO_METHOD(IoDate,isDaylightSavingsTime)519 IO_METHOD(IoDate, isDaylightSavingsTime)
520 {
521 /*doc Date isDaylightSavingsTime
522 Returns self if Daylight Saving Time is in effect for the receiver, otherwise returns Nil.
523 */
524
525 return IOBOOL(self, Date_isDaylightSavingsTime(DATA(self)));
526 }
527
IO_METHOD(IoDate,isValidTime)528 IO_METHOD(IoDate, isValidTime)
529 {
530 /*doc Date isValidTime(hour, min, sec)
531 Returns self if the specified time is valid, otherwise returns Nil.
532 A negative value will count back; i.e., a value of -5 for the hour,
533 will count back 5 hours to return a value of 19. No adjustment is
534 done for values above 24.
535 */
536
537 int hour = IoMessage_locals_intArgAt_(m, locals, 0);
538 int min = IoMessage_locals_intArgAt_(m, locals, 1);
539 int sec = IoMessage_locals_intArgAt_(m, locals, 2);
540
541 if (hour < 0) hour += 24;
542 if (min < 0) min += 60;
543 if (sec < 0) sec += 60;
544
545 return IOBOOL(self, ((hour >= 0) && (hour < 24)) &&
546 ((min >= 0) && (min < 60)) &&
547 ((sec >= 0) && (sec < 60)));
548 }
549
IO_METHOD(IoDate,secondsSince_)550 IO_METHOD(IoDate, secondsSince_)
551 {
552 /*doc Date secondsSince(aDate)
553 Returns a number of seconds of between aDate and the receiver.
554 */
555
556 IoDate *date = IoMessage_locals_dateArgAt_(m, locals, 0);
557 return IONUMBER(Date_secondsSince_(DATA(self), DATA(date)));
558 }
559
IO_METHOD(IoDate,secondsSinceNow)560 IO_METHOD(IoDate, secondsSinceNow)
561 {
562 /*doc Date secondsSinceNow(aDate)
563 Returns the number of seconds since aDate.
564 */
565
566 return IONUMBER(Date_secondsSinceNow(DATA(self)));
567 }
568
IO_METHOD(IoDate,isPast)569 IO_METHOD(IoDate, isPast)
570 {
571 /*doc Date isPast
572 Returns true if the receiver is a date in the past.
573 */
574
575 return IOBOOL(self, Date_secondsSinceNow(DATA(self)) > 0);
576 }
577
578 /*
579 IO_METHOD(IoDate, dateAfterSeconds_)
580 {
581 // doc Date dateAfterSeconds(secondsNumber)
582 Returns a new date that is secondsNumber seconds after the receiver.
583
584
585 IoDate *newDate = IoDate_new(IOSTATE);
586 Date_addSeconds_(DATA(newDate), IoMessage_locals_doubleArgAt_(m, locals, 0));
587 return newDate;
588 }
589 */
590
IO_METHOD(IoDate,asString)591 IO_METHOD(IoDate, asString)
592 {
593 /*doc Date asString(optionalFormatString)
594 Returns a string representation of the receiver using the
595 receivers format. If the optionalFormatString argument is present, the
596 receiver's format is set to it first. Formatting is according to ANSI C
597 date formatting rules.
598 <p>
599 <pre>
600 %a abbreviated weekday name (Sun, Mon, etc.)
601 %A full weekday name (Sunday, Monday, etc.)
602 %b abbreviated month name (Jan, Feb, etc.)
603 %B full month name (January, February, etc.)
604 %c full date and time string
605 %d day of the month as two-digit decimal integer (01-31)
606 %H hour as two-digit 24-hour clock decimal integer (00-23)
607 %I hour as two-digit 12-hour clock decimal integer (01-12)
608 %m month as a two-digit decimal integer (01-12)
609 %M minute as a two-digit decimal integer (00-59)
610 %p either "AM" or "PM"
611 %S second as a two-digit decimal integer (00-59)
612 %U number of week in the year as two-digit decimal integer (00-52)
613 with Sunday considered as first day of the week
614 %w weekday as one-digit decimal integer (0-6) with Sunday as 0
615 %W number of week in the year as two-digit decimal integer (00-52)
616 with Monday considered as first day of the week
617 %x full date string (no time); in the C locale, this is equivalent
618 to "%m/%d/%y".
619 %y year without century as two-digit decimal number (00-99)
620 %Y year with century as four-digit decimal number
621 %Z time zone name (e.g. EST);
622 null string if no time zone can be obtained
623 %% stands for '%' character in output string.
624 </pre>
625 */
626
627 char *format = "%Y-%m-%d %H:%M:%S %Z";
628
629 if (IoMessage_argCount(m) == 1)
630 {
631 format = CSTRING(IoMessage_locals_symbolArgAt_(m, locals, 0));
632 }
633 else
634 {
635 IoObject *f = IoObject_getSlot_(self, IOSYMBOL("format"));
636 if (ISSEQ(f)) { format = CSTRING(f); }
637 }
638
639 {
640 UArray *ba = Date_asString(DATA(self), format);
641 return IoState_symbolWithUArray_copy_convertToFixedWidth(IOSTATE, ba, 0);
642 }
643 }
644
IO_METHOD(IoDate,printDate)645 IO_METHOD(IoDate, printDate)
646 {
647 /*doc Date print
648 Prints the receiver. Returns self.
649 */
650
651 IoSymbol *s = (IoSymbol *)IoDate_asString(self, locals, m);
652 IoSeq_print(s, locals, m);
653 return self;
654 }
655
IO_METHOD(IoDate,asNumber)656 IO_METHOD(IoDate, asNumber)
657 {
658 /*doc Date asNumber
659 Returns the date as seconds since 1970 UTC.
660 */
661
662 return IONUMBER(Date_asSeconds(DATA(self)));
663 }
664
IO_METHOD(IoDate,fromNumber)665 IO_METHOD(IoDate, fromNumber)
666 {
667 /*doc Date fromNumber(aNumber)
668 Sets the receiver to be aNumber seconds since 1970.
669 */
670
671 Date_fromSeconds_(DATA(self), IoMessage_locals_doubleArgAt_(m, locals, 0));
672 IoObject_isDirty_(self, 1);
673 return self;
674 }
675
IO_METHOD(IoDate,fromString)676 IO_METHOD(IoDate, fromString)
677 {
678 /*doc Date fromString(aString, formatString)
679 Sets the receiver to the date specified by aString as parsed according to the given formatString. See the Date asString method for formatting rules. Returns self.
680 */
681
682 IoMessage_assertArgCount_receiver_(m, 2, self);
683 {
684 IoSymbol *date_input = IoMessage_locals_seqArgAt_(m, locals, 0);
685 IoSymbol *format = IoMessage_locals_seqArgAt_(m, locals, 1);
686 Date_fromString_format_(DATA(self), CSTRING(date_input), CSTRING(format));
687 }
688 IoObject_isDirty_(self, 1);
689 return self;
690 }
691
692 /* --- Durations -------------------------------------------------------- */
693
IO_METHOD(IoDate,subtract)694 IO_METHOD(IoDate, subtract)
695 {
696 /*doc Date -(aDurationOrDate)
697 Return a new Date with the receiver's value minus an amount of time specified by aDuration to the receiver. Returns self.
698 */
699
700 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
701
702 if (ISDATE(v))
703 {
704 double d = Date_secondsSince_(DATA(self), DATA(v));
705 return IoDuration_newWithSeconds_(IOSTATE, d);
706 }
707 else if (ISDURATION(v))
708 {
709 IoDate *newDate = IOCLONE(self);
710 Date_subtractDuration_(DATA(newDate), IoDuration_duration(v));
711 return newDate;
712 }
713
714 IOASSERT(1, "Date or Duration argument required");
715
716 return IONIL(self);
717 }
718
IO_METHOD(IoDate,subtractInPlace)719 IO_METHOD(IoDate, subtractInPlace)
720 {
721 /*doc Date -=(aDuration)
722 Subtract aDuration from the receiver. Returns self.
723 */
724
725 IoDuration *d = IoMessage_locals_durationArgAt_(m, locals, 0);
726 Date_subtractDuration_(DATA(self), IoDuration_duration(d));
727 IoObject_isDirty_(self, 1);
728 return self;
729 }
730
IO_METHOD(IoDate,addInPlace)731 IO_METHOD(IoDate, addInPlace)
732 {
733 /*doc Date +=(aDuration)
734 Add aDuration to the receiver. Returns self.
735 */
736
737 IoDuration *d = IoMessage_locals_durationArgAt_(m, locals, 0);
738 Date_addDuration_(DATA(self), IoDuration_duration(d));
739 IoObject_isDirty_(self, 1);
740 return self;
741 }
742
IO_METHOD(IoDate,add)743 IO_METHOD(IoDate, add)
744 {
745 /*doc Date +(aDuration)
746 Return a new Date with the receiver's value plus an amount
747 of time specified by aDuration object to the receiver.
748 */
749
750 IoDate *newDate = IOCLONE(self);
751 return IoDate_addInPlace(newDate, locals, m);
752 }
753