1 /*
2 * Copyright 2007-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Julun, host.haiku@gmx.de
8 */
9
10 #include "DateTime.h"
11
12
13 #include <time.h>
14 #include <sys/time.h>
15
16 #include <DateFormat.h>
17 #include <Locale.h>
18 #include <LocaleRoster.h>
19 #include <Message.h>
20
21
22 namespace BPrivate {
23
24 const int32 kSecondsPerMinute = 60;
25
26 const int32 kHoursPerDay = 24;
27 const int32 kMinutesPerDay = 1440;
28 const int32 kSecondsPerDay = 86400;
29 const int32 kMillisecondsPerDay = 86400000;
30
31 const bigtime_t kMicrosecondsPerSecond = 1000000LL;
32 const bigtime_t kMicrosecondsPerMinute = 60000000LL;
33 const bigtime_t kMicrosecondsPerHour = 3600000000LL;
34 const bigtime_t kMicrosecondsPerDay = 86400000000LL;
35
36
37 /*!
38 Constructs a new BTime object. Asked for its time representation, it will
39 return 0 for Hour(), Minute(), Second() etc. This can represent midnight,
40 but be aware IsValid() will return false.
41 */
BTime()42 BTime::BTime()
43 :
44 fMicroseconds(-1)
45 {
46 }
47
48
49 /*!
50 Constructs a new BTime object as a copy of \c other.
51 */
BTime(const BTime & other)52 BTime::BTime(const BTime& other)
53 :
54 fMicroseconds(other.fMicroseconds)
55 {
56 }
57
58
59 /*!
60 Constructs a BTime object with \c hour \c minute, \c second, \c microsecond.
61
62 \c hour must be between 0 and 23, \c minute and \c second must be between
63 0 and 59 and \c microsecond should be in the range of 0 and 999999. If the
64 specified time is invalid, the time is not set and IsValid() returns false.
65 */
BTime(int32 hour,int32 minute,int32 second,int32 microsecond)66 BTime::BTime(int32 hour, int32 minute, int32 second, int32 microsecond)
67 :
68 fMicroseconds(-1)
69 {
70 _SetTime(hour, minute, second, microsecond);
71 }
72
73
74 /*!
75 Constructs a new BTime object from the provided BMessage archive.
76 */
BTime(const BMessage * archive)77 BTime::BTime(const BMessage* archive)
78 :
79 fMicroseconds(-1)
80 {
81 if (archive == NULL)
82 return;
83 archive->FindInt64("microseconds", &fMicroseconds);
84 }
85
86
87 /*!
88 Empty destructor.
89 */
~BTime()90 BTime::~BTime()
91 {
92 }
93
94
95 /*!
96 Archives the BTime object into the provided BMessage object.
97 @returns \c B_OK if all went well.
98 \c B_BAD_VALUE, if the message is \c NULL.
99 \c other error codes, depending on failure to append
100 fields to the message.
101 */
102 status_t
Archive(BMessage * into) const103 BTime::Archive(BMessage* into) const
104 {
105 if (into == NULL)
106 return B_BAD_VALUE;
107 return into->AddInt64("microseconds", fMicroseconds);
108 }
109
110
111 /*!
112 Returns true if the time is valid, otherwise false. A valid time can be
113 BTime(23, 59, 59, 999999) while BTime(24, 00, 01) would be invalid.
114 */
115 bool
IsValid() const116 BTime::IsValid() const
117 {
118 return fMicroseconds > -1 && fMicroseconds < kMicrosecondsPerDay;
119 }
120
121
122 /*!
123 This is an overloaded member function, provided for convenience.
124 */
125 /*static*/ bool
IsValid(const BTime & time)126 BTime::IsValid(const BTime& time)
127 {
128 return time.IsValid();
129 }
130
131
132 /*!
133 This is an overloaded member function, provided for convenience.
134 */
135 /*static*/ bool
IsValid(int32 hour,int32 minute,int32 second,int32 microsecond)136 BTime::IsValid(int32 hour, int32 minute, int32 second, int32 microsecond)
137 {
138 return BTime(hour, minute, second, microsecond).IsValid();
139 }
140
141
142 /*!
143 Returns the current time as reported by the system depending on the given
144 time_type \c type.
145 */
146 BTime
CurrentTime(time_type type)147 BTime::CurrentTime(time_type type)
148 {
149 struct timeval tv;
150 if (gettimeofday(&tv, NULL) != 0) {
151 // gettimeofday failed?
152 time(&tv.tv_sec);
153 }
154
155 struct tm result;
156 struct tm* timeinfo;
157 if (type == B_GMT_TIME)
158 timeinfo = gmtime_r(&tv.tv_sec, &result);
159 else
160 timeinfo = localtime_r(&tv.tv_sec, &result);
161
162 if (timeinfo == NULL)
163 return BTime();
164
165 int32 sec = timeinfo->tm_sec;
166 return BTime(timeinfo->tm_hour, timeinfo->tm_min, (sec > 59) ? 59 : sec,
167 tv.tv_usec);
168 }
169
170
171 /*!
172 Returns a copy of the current BTime object.
173 */
174 BTime
Time() const175 BTime::Time() const
176 {
177 return *this;
178 }
179
180
181 /*!
182 This is an overloaded member function, provided for convenience. Set the
183 current BTime object to the passed BTime \c time object.
184 */
185 bool
SetTime(const BTime & time)186 BTime::SetTime(const BTime& time)
187 {
188 fMicroseconds = time.fMicroseconds;
189 return IsValid();
190 }
191
192
193 /*!
194 Set the time to \c hour \c minute, \c second and \c microsecond.
195
196 \c hour must be between 0 and 23, \c minute and \c second must be between
197 0 and 59 and \c microsecond should be in the range of 0 and 999999. Returns
198 true if the time is valid; otherwise false. If the specified time is
199 invalid, the time is not set and the function returns false.
200 */
201 bool
SetTime(int32 hour,int32 minute,int32 second,int32 microsecond)202 BTime::SetTime(int32 hour, int32 minute, int32 second, int32 microsecond)
203 {
204 return _SetTime(hour, minute, second, microsecond);
205 }
206
207
208 /*!
209 Adds \c hours to the current time. If the passed value is negative it
210 will become earlier. Note: The time will wrap if it passes midnight.
211 */
212 BTime&
AddHours(int32 hours)213 BTime::AddHours(int32 hours)
214 {
215 return _AddMicroseconds(bigtime_t(hours % kHoursPerDay)
216 * kMicrosecondsPerHour);
217 }
218
219
220 /*!
221 Adds \c minutes to the current time. If the passed value is negative it
222 will become earlier. Note: The time will wrap if it passes midnight.
223 */
224 BTime&
AddMinutes(int32 minutes)225 BTime::AddMinutes(int32 minutes)
226 {
227 return _AddMicroseconds(bigtime_t(minutes % kMinutesPerDay)
228 * kMicrosecondsPerMinute);
229 }
230
231
232 /*!
233 Adds \c seconds to the current time. If the passed value is negative
234 it will become earlier. Note: The time will wrap if it passes midnight.
235 */
236 BTime&
AddSeconds(int32 seconds)237 BTime::AddSeconds(int32 seconds)
238 {
239 return _AddMicroseconds(bigtime_t(seconds % kSecondsPerDay)
240 * kMicrosecondsPerSecond);
241 }
242
243
244 /*!
245 Adds \c milliseconds to the current time. If the passed value is negative
246 it will become earlier. Note: The time will wrap if it passes midnight.
247 */
248 BTime&
AddMilliseconds(int32 milliseconds)249 BTime::AddMilliseconds(int32 milliseconds)
250 {
251 return _AddMicroseconds(bigtime_t(milliseconds % kMillisecondsPerDay)
252 * 1000);
253 }
254
255
256 /*!
257 Adds \c microseconds to the current time. If the passed value is negative
258 it will become earlier. Note: The time will wrap if it passes midnight.
259 */
260 BTime&
AddMicroseconds(int32 microseconds)261 BTime::AddMicroseconds(int32 microseconds)
262 {
263 return _AddMicroseconds(microseconds);
264 }
265
266
267 /*!
268 Returns the hour fragment of the time.
269 */
270 int32
Hour() const271 BTime::Hour() const
272 {
273 return int32(_Microseconds() / kMicrosecondsPerHour);
274 }
275
276
277 /*!
278 Returns the minute fragment of the time.
279 */
280 int32
Minute() const281 BTime::Minute() const
282 {
283 return int32(((_Microseconds() % kMicrosecondsPerHour))
284 / kMicrosecondsPerMinute);
285 }
286
287
288 /*!
289 Returns the second fragment of the time.
290 */
291 int32
Second() const292 BTime::Second() const
293 {
294 return int32(_Microseconds() / kMicrosecondsPerSecond) % kSecondsPerMinute;
295 }
296
297
298 /*!
299 Returns the millisecond fragment of the time.
300 */
301 int32
Millisecond() const302 BTime::Millisecond() const
303 {
304
305 return Microsecond() / 1000;
306 }
307
308
309 /*!
310 Returns the microsecond fragment of the time.
311 */
312 int32
Microsecond() const313 BTime::Microsecond() const
314 {
315 return int32(_Microseconds() % kMicrosecondsPerSecond);
316 }
317
318
319 bigtime_t
_Microseconds() const320 BTime::_Microseconds() const
321 {
322 return fMicroseconds == -1 ? 0 : fMicroseconds;
323 }
324
325
326 /*!
327 Returns the difference between this time and the given BTime \c time based
328 on the passed diff_type \c type. If \c time is earlier the return value will
329 be negativ.
330
331 The return value then can be hours, minutes, seconds, milliseconds or
332 microseconds while its range will always be between -86400000000 and
333 86400000000 depending on diff_type \c type.
334 */
335 bigtime_t
Difference(const BTime & time,diff_type type) const336 BTime::Difference(const BTime& time, diff_type type) const
337 {
338 bigtime_t diff = time._Microseconds() - _Microseconds();
339 switch (type) {
340 case B_HOURS_DIFF:
341 diff /= kMicrosecondsPerHour;
342 break;
343 case B_MINUTES_DIFF:
344 diff /= kMicrosecondsPerMinute;
345 break;
346 case B_SECONDS_DIFF:
347 diff /= kMicrosecondsPerSecond;
348 break;
349 case B_MILLISECONDS_DIFF:
350 diff /= 1000;
351 break;
352 case B_MICROSECONDS_DIFF:
353 default:
354 break;
355 }
356 return diff;
357 }
358
359
360 /*!
361 Returns true if this time is different from \c time, otherwise false.
362 */
363 bool
operator !=(const BTime & time) const364 BTime::operator!=(const BTime& time) const
365 {
366 return fMicroseconds != time.fMicroseconds;
367 }
368
369
370 /*!
371 Returns true if this time is equal to \c time, otherwise false.
372 */
373 bool
operator ==(const BTime & time) const374 BTime::operator==(const BTime& time) const
375 {
376 return fMicroseconds == time.fMicroseconds;
377 }
378
379
380 /*!
381 Returns true if this time is earlier than \c time, otherwise false.
382 */
383 bool
operator <(const BTime & time) const384 BTime::operator<(const BTime& time) const
385 {
386 return fMicroseconds < time.fMicroseconds;
387 }
388
389
390 /*!
391 Returns true if this time is earlier than or equal to \c time, otherwise false.
392 */
393 bool
operator <=(const BTime & time) const394 BTime::operator<=(const BTime& time) const
395 {
396 return fMicroseconds <= time.fMicroseconds;
397 }
398
399
400 /*!
401 Returns true if this time is later than \c time, otherwise false.
402 */
403 bool
operator >(const BTime & time) const404 BTime::operator>(const BTime& time) const
405 {
406 return fMicroseconds > time.fMicroseconds;
407 }
408
409
410 /*!
411 Returns true if this time is later than or equal to \c time, otherwise false.
412 */
413 bool
operator >=(const BTime & time) const414 BTime::operator>=(const BTime& time) const
415 {
416 return fMicroseconds >= time.fMicroseconds;
417 }
418
419
420 BTime&
_AddMicroseconds(bigtime_t microseconds)421 BTime::_AddMicroseconds(bigtime_t microseconds)
422 {
423 bigtime_t count = 0;
424 if (microseconds < 0) {
425 count = ((kMicrosecondsPerDay - microseconds) / kMicrosecondsPerDay) *
426 kMicrosecondsPerDay;
427 }
428 fMicroseconds = (_Microseconds() + microseconds + count) % kMicrosecondsPerDay;
429 return *this;
430 }
431
432
433 bool
_SetTime(bigtime_t hour,bigtime_t minute,bigtime_t second,bigtime_t microsecond)434 BTime::_SetTime(bigtime_t hour, bigtime_t minute, bigtime_t second,
435 bigtime_t microsecond)
436 {
437 fMicroseconds = hour * kMicrosecondsPerHour +
438 minute * kMicrosecondsPerMinute +
439 second * kMicrosecondsPerSecond +
440 microsecond;
441
442 bool isValid = IsValid();
443 if (!isValid)
444 fMicroseconds = -1;
445
446 return isValid;
447 }
448
449
450 // #pragma mark - BDate
451
452
453 /*!
454 Constructs a new BDate object. IsValid() will return false.
455 */
BDate()456 BDate::BDate()
457 :
458 fDay(-1),
459 fYear(0),
460 fMonth(-1)
461 {
462 }
463
464
465 /*!
466 Constructs a new BDate object as a copy of \c other.
467 */
BDate(const BDate & other)468 BDate::BDate(const BDate& other)
469 :
470 fDay(other.fDay),
471 fYear(other.fYear),
472 fMonth(other.fMonth)
473 {
474 }
475
476
477 /*!
478 Constructs a BDate object with \c year \c month and \c day.
479
480 Please note that a date before 1.1.4713 BC, a date with year 0 and a date
481 between 4.10.1582 and 15.10.1582 are considered invalid. If the specified
482 date is invalid, the date is not set and IsValid() returns false. Also note
483 that every passed year will be interpreted as is.
484
485 */
BDate(int32 year,int32 month,int32 day)486 BDate::BDate(int32 year, int32 month, int32 day)
487 {
488 _SetDate(year, month, day);
489 }
490
491
BDate(time_t time,time_type type)492 BDate::BDate(time_t time, time_type type)
493 {
494 struct tm result;
495 struct tm* timeinfo;
496
497 if (type == B_GMT_TIME)
498 timeinfo = gmtime_r(&time, &result);
499 else
500 timeinfo = localtime_r(&time, &result);
501
502 if (timeinfo != NULL) {
503 _SetDate(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1,
504 timeinfo->tm_mday);
505 }
506 }
507
508
509 /*!
510 Constructs a new BDate object from the provided archive.
511 */
BDate(const BMessage * archive)512 BDate::BDate(const BMessage* archive)
513 :
514 fDay(-1),
515 fYear(0),
516 fMonth(-1)
517 {
518 if (archive == NULL)
519 return;
520 archive->FindInt32("day", &fDay);
521 archive->FindInt32("year", &fYear);
522 archive->FindInt32("month", &fMonth);
523 }
524
525
526 /*!
527 Empty destructor.
528 */
~BDate()529 BDate::~BDate()
530 {
531 }
532
533
534 /*!
535 Archives the BDate object into the provided BMessage object.
536 @returns \c B_OK if all went well.
537 \c B_BAD_VALUE, if the message is \c NULL.
538 \c other error codes, depending on failure to append
539 fields to the message.
540 */
541 status_t
Archive(BMessage * into) const542 BDate::Archive(BMessage* into) const
543 {
544 if (into == NULL)
545 return B_BAD_VALUE;
546 status_t ret = into->AddInt32("day", fDay);
547 if (ret == B_OK)
548 ret = into->AddInt32("year", fYear);
549 if (ret == B_OK)
550 ret = into->AddInt32("month", fMonth);
551 return ret;
552 }
553
554
555 /*!
556 Returns true if the date is valid, otherwise false.
557
558 Please note that a date before 1.1.4713 BC, a date with year 0 and a date
559 between 4.10.1582 and 15.10.1582 are considered invalid.
560 */
561 bool
IsValid() const562 BDate::IsValid() const
563 {
564 return IsValid(fYear, fMonth, fDay);
565 }
566
567
568 /*!
569 This is an overloaded member function, provided for convenience.
570 */
571 /*static*/ bool
IsValid(const BDate & date)572 BDate::IsValid(const BDate& date)
573 {
574 return IsValid(date.fYear, date.fMonth, date.fDay);
575 }
576
577
578 /*!
579 This is an overloaded member function, provided for convenience.
580 */
581 /*static*/ bool
IsValid(int32 year,int32 month,int32 day)582 BDate::IsValid(int32 year, int32 month, int32 day)
583 {
584 // no year 0 in Julian and nothing before 1.1.4713 BC
585 if (year == 0 || year < -4713)
586 return false;
587
588 if (month < 1 || month > 12)
589 return false;
590
591 if (day < 1 || day > _DaysInMonth(year, month))
592 return false;
593
594 // 'missing' days between switch julian - gregorian
595 if (year == 1582 && month == 10 && day > 4 && day < 15)
596 return false;
597
598 return true;
599 }
600
601
602 /*!
603 Returns the current date as reported by the system depending on the given
604 time_type \c type.
605 */
606 BDate
CurrentDate(time_type type)607 BDate::CurrentDate(time_type type)
608 {
609 return BDate(time(NULL), type);
610 }
611
612
613 /*!
614 Returns a copy of the current BTime object.
615 */
616 BDate
Date() const617 BDate::Date() const
618 {
619 return *this;
620 }
621
622
623 /*!
624 This is an overloaded member function, provided for convenience.
625 */
626 bool
SetDate(const BDate & date)627 BDate::SetDate(const BDate& date)
628 {
629 return _SetDate(date.fYear, date.fMonth, date.fDay);
630 }
631
632
633 /*!
634 Set the date to \c year \c month and \c day.
635
636 Returns true if the date is valid; otherwise false. If the specified date is
637 invalid, the date is not set and the function returns false.
638 */
639 bool
SetDate(int32 year,int32 month,int32 day)640 BDate::SetDate(int32 year, int32 month, int32 day)
641 {
642 return _SetDate(year, month, day);
643 }
644
645
646 /*!
647 This function sets the given \c year, \c month and \c day to the
648 representative values of this date. The pointers can be NULL. If the date is
649 invalid, the values will be set to -1 for \c month and \c day, the \c year
650 will be set to 0.
651 */
652 void
GetDate(int32 * year,int32 * month,int32 * day) const653 BDate::GetDate(int32* year, int32* month, int32* day) const
654 {
655 if (year)
656 *year = fYear;
657
658 if (month)
659 *month = fMonth;
660
661 if (day)
662 *day = fDay;
663 }
664
665
666 /*!
667 Adds \c days to the current date. If the passed value is negative it will
668 become earlier. If the current date is invalid, the \c days are not added.
669 */
670 void
AddDays(int32 days)671 BDate::AddDays(int32 days)
672 {
673 if (IsValid())
674 *this = JulianDayToDate(DateToJulianDay() + days);
675 }
676
677
678 /*!
679 Adds \c years to the current date. If the passed value is negativ it will
680 become earlier. If the current date is invalid, the \c years are not added.
681 The day/ month combination will be adjusted if it does not exist in the
682 resulting year, so this function will then return the latest valid date.
683 */
684 void
AddYears(int32 years)685 BDate::AddYears(int32 years)
686 {
687 if (IsValid()) {
688 const int32 tmp = fYear;
689 fYear += years;
690
691 if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0))
692 fYear += (years > 0) ? +1 : -1;
693
694 fDay = min_c(fDay, _DaysInMonth(fYear, fMonth));
695 }
696 }
697
698
699 /*!
700 Adds \c months to the current date. If the passed value is negativ it will
701 become earlier. If the current date is invalid, the \c months are not added.
702 The day/ month combination will be adjusted if it does not exist in the
703 resulting year, so this function will then return the latest valid date.
704 */
705 void
AddMonths(int32 months)706 BDate::AddMonths(int32 months)
707 {
708 if (IsValid()) {
709 const int32 tmp = fYear;
710 fYear += months / 12;
711 fMonth += months % 12;
712
713 if (fMonth > 12) {
714 fYear++;
715 fMonth -= 12;
716 } else if (fMonth < 1) {
717 fYear--;
718 fMonth += 12;
719 }
720
721 if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0))
722 fYear += (months > 0) ? +1 : -1;
723
724 // 'missing' days between switch julian - gregorian
725 if (fYear == 1582 && fMonth == 10 && fDay > 4 && fDay < 15)
726 fDay = (months > 0) ? 15 : 4;
727
728 fDay = min_c(fDay, _DaysInMonth(fYear, fMonth));
729 }
730 }
731
732
733 /*!
734 Returns the day fragment of the date. The return value will be in the range
735 of 1 to 31, in case the date is invalid it will be -1.
736 */
737 int32
Day() const738 BDate::Day() const
739 {
740 return fDay;
741 }
742
743
744 /*!
745 Returns the year fragment of the date. If the date is invalid, the function
746 returns 0.
747 */
748 int32
Year() const749 BDate::Year() const
750 {
751 return fYear;
752 }
753
754
755 /*!
756 Returns the month fragment of the date. The return value will be in the
757 range of 1 to 12, in case the date is invalid it will be -1.
758 */
759 int32
Month() const760 BDate::Month() const
761 {
762 return fMonth;
763 }
764
765
766 /*!
767 Returns the difference in days between this date and the given BDate \c date.
768 If \c date is earlier the return value will be negativ. If the calculation
769 is done with an invalid date, the result is undefined.
770 */
771 int32
Difference(const BDate & date) const772 BDate::Difference(const BDate& date) const
773 {
774 return date.DateToJulianDay() - DateToJulianDay();
775 }
776
777
778 void
SetDay(int32 day)779 BDate::SetDay(int32 day)
780 {
781 fDay = day;
782 }
783
784
785 void
SetMonth(int32 month)786 BDate::SetMonth(int32 month)
787 {
788 fMonth = month;
789 }
790
791
792 void
SetYear(int32 year)793 BDate::SetYear(int32 year)
794 {
795 fYear = year;
796 }
797
798
799 /*!
800 Returns the week number of the date, if the date is invalid it will return
801 B_ERROR. Please note that this function does only work within the Gregorian
802 calendar, thus a date before 15.10.1582 will return B_ERROR.
803 */
804 int32
WeekNumber() const805 BDate::WeekNumber() const
806 {
807 /*
808 This algorithm is taken from:
809 Frequently Asked Questions about Calendars
810 Version 2.8 Claus Tøndering 15 December 2005
811
812 Note: it will work only within the Gregorian Calendar
813 */
814
815 if (!IsValid() || fYear < 1582
816 || (fYear == 1582 && fMonth < 10)
817 || (fYear == 1582 && fMonth == 10 && fDay < 15))
818 return int32(B_ERROR);
819
820 int32 a;
821 int32 b;
822 int32 s;
823 int32 e;
824 int32 f;
825
826 if (fMonth > 0 && fMonth < 3) {
827 a = fYear - 1;
828 b = (a / 4) - (a / 100) + (a / 400);
829 int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
830 s = b - c;
831 e = 0;
832 f = fDay - 1 + 31 * (fMonth - 1);
833 } else if (fMonth >= 3 && fMonth <= 12) {
834 a = fYear;
835 b = (a / 4) - (a / 100) + (a / 400);
836 int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400);
837 s = b - c;
838 e = s + 1;
839 f = fDay + ((153 * (fMonth - 3) + 2) / 5) + 58 + s;
840 } else
841 return int32(B_ERROR);
842
843 int32 g = (a + b) % 7;
844 int32 d = (f + g - e) % 7;
845 int32 n = f + 3 - d;
846
847 int32 weekNumber;
848 if (n < 0)
849 weekNumber = 53 - (g -s) / 5;
850 else if (n > 364 + s)
851 weekNumber = 1;
852 else
853 weekNumber = n / 7 + 1;
854
855 return weekNumber;
856 }
857
858
859 /*!
860 Returns the day of the week in the range of 1 to 7, while 1 stands for
861 monday. If the date is invalid, the function will return B_ERROR.
862 */
863 int32
DayOfWeek() const864 BDate::DayOfWeek() const
865 {
866 // http://en.wikipedia.org/wiki/Julian_day#Calculation
867 return IsValid() ? (DateToJulianDay() % 7) + 1 : int32(B_ERROR);
868 }
869
870
871 /*!
872 Returns the day of the year in the range of 1 to 365 (366 in leap years). If
873 the date is invalid, the function will return B_ERROR.
874 */
875 int32
DayOfYear() const876 BDate::DayOfYear() const
877 {
878 if (!IsValid())
879 return int32(B_ERROR);
880
881 return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1;
882 }
883
884
885 /*!
886 Returns true if the year of this object is a leap year, otherwise false. If
887 the \c year passed is before 4713 BC, the result is undefined.
888 */
889 bool
IsLeapYear() const890 BDate::IsLeapYear() const
891 {
892 return IsLeapYear(fYear);
893 }
894
895
896 /*!
897 Returns true if the passed \c year is a leap year, otherwise false. If the
898 \c year passed is before 4713 BC, the result is undefined.
899 */
900 /*static*/ bool
IsLeapYear(int32 year)901 BDate::IsLeapYear(int32 year)
902 {
903 if (year < 1582) {
904 if (year < 0)
905 year++;
906 return (year % 4) == 0;
907 }
908 return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
909 }
910
911
912 /*!
913 Returns the number of days in the year of the current date. If the date is
914 valid it will return 365 or 366, otherwise B_ERROR;
915 */
916 int32
DaysInYear() const917 BDate::DaysInYear() const
918 {
919 if (!IsValid())
920 return int32(B_ERROR);
921
922 return IsLeapYear(fYear) ? 366 : 365;
923 }
924
925
926 /*!
927 Returns the number of days in the month of the current date. If the date is
928 valid it will return 28 up to 31, otherwise B_ERROR;
929 */
930 int32
DaysInMonth() const931 BDate::DaysInMonth() const
932 {
933 if (!IsValid())
934 return int32(B_ERROR);
935
936 return _DaysInMonth(fYear, fMonth);
937 }
938
939
940 /*!
941 Returns the short day name of this object.
942 */
943 BString
ShortDayName() const944 BDate::ShortDayName() const
945 {
946 return ShortDayName(DayOfWeek());
947 }
948
949
950 /*!
951 Returns the short day name in case of an valid day, otherwise an empty
952 string. The passed \c day must be in the range of 1 to 7 while 1 stands for
953 monday.
954 */
955 /*static*/ BString
ShortDayName(int32 day)956 BDate::ShortDayName(int32 day)
957 {
958 if (day < 1 || day > 7)
959 return BString();
960
961 tm tm_struct;
962 memset(&tm_struct, 0, sizeof(tm));
963 tm_struct.tm_wday = day == 7 ? 0 : day;
964
965 char buffer[256];
966 strftime(buffer, sizeof(buffer), "%a", &tm_struct);
967
968 return BString(buffer);
969 }
970
971
972 /*!
973 Returns the short month name of this object.
974 */
975 BString
ShortMonthName() const976 BDate::ShortMonthName() const
977 {
978 return ShortMonthName(Month());
979 }
980
981
982 /*!
983 Returns the short month name in case of an valid month, otherwise an empty
984 string. The passed \c month must be in the range of 1 to 12.
985 */
986 /*static*/ BString
ShortMonthName(int32 month)987 BDate::ShortMonthName(int32 month)
988 {
989 if (month < 1 || month > 12)
990 return BString();
991
992 tm tm_struct;
993 memset(&tm_struct, 0, sizeof(tm));
994 tm_struct.tm_mon = month - 1;
995
996 char buffer[256];
997 strftime(buffer, sizeof(buffer), "%b", &tm_struct);
998
999 return BString(buffer);
1000 }
1001
1002
1003 /*!
1004 Returns the long day name of this object's week day.
1005 */
1006 BString
LongDayName() const1007 BDate::LongDayName() const
1008 {
1009 return LongDayName(DayOfWeek());
1010 }
1011
1012
1013 /*!
1014 Returns the long day name in case of an valid day, otherwise an empty
1015 string. The passed \c day must be in the range of 1 to 7 while 1 stands for
1016 monday.
1017 */
1018 /*static*/ BString
LongDayName(int32 day)1019 BDate::LongDayName(int32 day)
1020 {
1021 if (day < 1 || day > 7)
1022 return BString();
1023
1024 const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale();
1025 BDateFormat format(locale);
1026 BString out;
1027 if (format.GetDayName(day, out, B_LONG_DATE_FORMAT) != B_OK)
1028 return BString();
1029
1030 return out;
1031 }
1032
1033
1034 /*!
1035 Returns the long month name of this object's month.
1036 */
1037 BString
LongMonthName() const1038 BDate::LongMonthName() const
1039 {
1040 return LongMonthName(Month());
1041 }
1042
1043
1044 /*!
1045 Returns the long month name in case of an valid month, otherwise an empty
1046 string. The passed \c month must be in the range of 1 to 12.
1047 */
1048 /*static*/ BString
LongMonthName(int32 month)1049 BDate::LongMonthName(int32 month)
1050 {
1051 if (month < 1 || month > 12)
1052 return BString();
1053
1054 const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale();
1055 BDateFormat format(locale);
1056 BString out;
1057 if (format.GetMonthName(month, out, B_LONG_DATE_FORMAT) != B_OK)
1058 return BString();
1059
1060 return out;
1061 }
1062
1063
1064 /*!
1065 Converts the date to Julian day. If your date is invalid, the function will
1066 return B_ERROR.
1067 */
1068 int32
DateToJulianDay() const1069 BDate::DateToJulianDay() const
1070 {
1071 return _DateToJulianDay(fYear, fMonth, fDay);
1072 }
1073
1074
1075 /*!
1076 Converts the passed \c julianDay to an BDate. If the \c julianDay is negativ,
1077 the function will return an invalid date. Because of the switch from Julian
1078 calendar to Gregorian calendar the 4.10.1582 is followed by the 15.10.1582.
1079 */
1080 /*static*/ BDate
JulianDayToDate(int32 julianDay)1081 BDate::JulianDayToDate(int32 julianDay)
1082 {
1083 BDate date;
1084 const int32 kGregorianCalendarStart = 2299161;
1085 if (julianDay >= kGregorianCalendarStart) {
1086 // http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number
1087 int32 j = julianDay + 32044;
1088 int32 dg = j % 146097;
1089 int32 c = (dg / 36524 + 1) * 3 / 4;
1090 int32 dc = dg - c * 36524;
1091 int32 db = dc % 1461;
1092 int32 a = (db / 365 + 1) * 3 / 4;
1093 int32 da = db - a * 365;
1094 int32 m = (da * 5 + 308) / 153 - 2;
1095 date.fYear = ((j / 146097) * 400 + c * 100 + (dc / 1461) * 4 + a)
1096 - 4800 + (m + 2) / 12;
1097 date.fMonth = (m + 2) % 12 + 1;
1098 date.fDay = int32((da - (m + 4) * 153 / 5 + 122) + 1.5);
1099 } else if (julianDay >= 0) {
1100 // http://en.wikipedia.org/wiki/Julian_day#Calculation
1101 julianDay += 32082;
1102 int32 d = (4 * julianDay + 3) / 1461;
1103 int32 e = julianDay - (1461 * d) / 4;
1104 int32 m = ((5 * e) + 2) / 153;
1105 date.fDay = e - (153 * m + 2) / 5 + 1;
1106 date.fMonth = m + 3 - 12 * (m / 10);
1107 int32 year = d - 4800 + (m / 10);
1108 if (year <= 0)
1109 year--;
1110 date.fYear = year;
1111 }
1112 return date;
1113 }
1114
1115
1116 /*!
1117 Returns true if this date is different from \c date, otherwise false.
1118 */
1119 bool
operator !=(const BDate & date) const1120 BDate::operator!=(const BDate& date) const
1121 {
1122 return DateToJulianDay() != date.DateToJulianDay();
1123 }
1124
1125
1126 /*!
1127 Returns true if this date is equal to \c date, otherwise false.
1128 */
1129 bool
operator ==(const BDate & date) const1130 BDate::operator==(const BDate& date) const
1131 {
1132 return DateToJulianDay() == date.DateToJulianDay();
1133 }
1134
1135
1136 /*!
1137 Returns true if this date is earlier than \c date, otherwise false.
1138 */
1139 bool
operator <(const BDate & date) const1140 BDate::operator<(const BDate& date) const
1141 {
1142 return DateToJulianDay() < date.DateToJulianDay();
1143 }
1144
1145
1146 /*!
1147 Returns true if this date is earlier than or equal to \c date, otherwise
1148 false.
1149 */
1150 bool
operator <=(const BDate & date) const1151 BDate::operator<=(const BDate& date) const
1152 {
1153 return DateToJulianDay() <= date.DateToJulianDay();
1154 }
1155
1156
1157 /*!
1158 Returns true if this date is later than \c date, otherwise false.
1159 */
1160 bool
operator >(const BDate & date) const1161 BDate::operator>(const BDate& date) const
1162 {
1163 return DateToJulianDay() > date.DateToJulianDay();
1164 }
1165
1166
1167 /*!
1168 Returns true if this date is later than or equal to \c date, otherwise
1169 false.
1170 */
1171 bool
operator >=(const BDate & date) const1172 BDate::operator>=(const BDate& date) const
1173 {
1174 return DateToJulianDay() >= date.DateToJulianDay();
1175 }
1176
1177
1178 bool
_SetDate(int32 year,int32 month,int32 day)1179 BDate::_SetDate(int32 year, int32 month, int32 day)
1180 {
1181 fDay = -1;
1182 fYear = 0;
1183 fMonth = -1;
1184
1185 bool valid = IsValid(year, month, day);
1186 if (valid) {
1187 fDay = day;
1188 fYear = year;
1189 fMonth = month;
1190 }
1191
1192 return valid;
1193 }
1194
1195
1196 int32
_DaysInMonth(int32 year,int32 month)1197 BDate::_DaysInMonth(int32 year, int32 month)
1198 {
1199 if (month == 2 && IsLeapYear(year))
1200 return 29;
1201
1202 const int32 daysInMonth[12] =
1203 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1204
1205 return daysInMonth[month -1];
1206 }
1207
1208
1209 int32
_DateToJulianDay(int32 _year,int32 month,int32 day)1210 BDate::_DateToJulianDay(int32 _year, int32 month, int32 day)
1211 {
1212 if (IsValid(_year, month, day)) {
1213 int32 year = _year;
1214 if (year < 0) year++;
1215
1216 int32 a = (14 - month) / 12;
1217 int32 y = year + 4800 - a;
1218 int32 m = month + (12 * a) - 3;
1219
1220 // http://en.wikipedia.org/wiki/Julian_day#Calculation
1221 if (year > 1582
1222 || (year == 1582 && month > 10)
1223 || (year == 1582 && month == 10 && day >= 15)) {
1224 return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) -
1225 (y / 100) + (y / 400) - 32045;
1226 } else if (year < 1582
1227 || (year == 1582 && month < 10)
1228 || (year == 1582 && month == 10 && day <= 4)) {
1229 return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 32083;
1230 }
1231 }
1232
1233 // http://en.wikipedia.org/wiki/Gregorian_calendar:
1234 // The last day of the Julian calendar was Thursday October 4, 1582
1235 // and this was followed by the first day of the Gregorian calendar,
1236 // Friday October 15, 1582 (the cycle of weekdays was not affected).
1237 return int32(B_ERROR);
1238 }
1239
1240
1241 // #pragma mark - BDateTime
1242
1243
1244 /*!
1245 Constructs a new BDateTime object. IsValid() will return false.
1246 */
BDateTime()1247 BDateTime::BDateTime()
1248 : fDate(),
1249 fTime()
1250 {
1251 }
1252
1253
1254 /*!
1255 Constructs a BDateTime object with \c date and \c time. The return value
1256 of IsValid() depends on the validity of the passed objects.
1257 */
BDateTime(const BDate & date,const BTime & time)1258 BDateTime::BDateTime(const BDate& date, const BTime& time)
1259 : fDate(date),
1260 fTime(time)
1261 {
1262 }
1263
1264
1265 /*!
1266 Constructs a new BDateTime object. IsValid() will return false.
1267 */
BDateTime(const BMessage * archive)1268 BDateTime::BDateTime(const BMessage* archive)
1269 : fDate(archive),
1270 fTime(archive)
1271 {
1272 }
1273
1274
1275 /*!
1276 Empty destructor.
1277 */
~BDateTime()1278 BDateTime::~BDateTime()
1279 {
1280 }
1281
1282
1283 /*!
1284 Archives the BDateTime object into the provided BMessage object.
1285 @returns \c B_OK if all went well.
1286 \c B_BAD_VALUE, if the message is \c NULL.
1287 \c other error codes, depending on failure to append
1288 fields to the message.
1289 */
1290 status_t
Archive(BMessage * into) const1291 BDateTime::Archive(BMessage* into) const
1292 {
1293 status_t ret = fDate.Archive(into);
1294 if (ret == B_OK)
1295 ret = fTime.Archive(into);
1296 return ret;
1297 }
1298
1299
1300 /*!
1301 Returns true if the date time is valid, otherwise false.
1302 */
1303 bool
IsValid() const1304 BDateTime::IsValid() const
1305 {
1306 return fDate.IsValid() && fTime.IsValid();
1307 }
1308
1309
1310 /*!
1311 Returns the current date and time as reported by the system depending on the
1312 given time_type \c type.
1313 */
1314 BDateTime
CurrentDateTime(time_type type)1315 BDateTime::CurrentDateTime(time_type type)
1316 {
1317 return BDateTime(BDate::CurrentDate(type), BTime::CurrentTime(type));
1318 }
1319
1320
1321 /*!
1322 Sets the current date and time of this object to \c date and \c time.
1323 */
1324 void
SetDateTime(const BDate & date,const BTime & time)1325 BDateTime::SetDateTime(const BDate& date, const BTime& time)
1326 {
1327 fDate = date;
1328 fTime = time;
1329 }
1330
1331
1332 /*!
1333 Returns the current date of this object.
1334 */
1335 BDate&
Date()1336 BDateTime::Date()
1337 {
1338 return fDate;
1339 }
1340
1341
1342 /*!
1343 Returns the current date of this object.
1344 */
1345 const BDate&
Date() const1346 BDateTime::Date() const
1347 {
1348 return fDate;
1349 }
1350
1351
1352 /*!
1353 Set the current date of this object to \c date.
1354 */
1355 void
SetDate(const BDate & date)1356 BDateTime::SetDate(const BDate& date)
1357 {
1358 fDate = date;
1359 }
1360
1361
1362 /*!
1363 Returns the current time of this object.
1364 */
1365 BTime&
Time()1366 BDateTime::Time()
1367 {
1368 return fTime;
1369 }
1370
1371
1372 /*!
1373 Returns the current time of this object.
1374 */
1375 const BTime&
Time() const1376 BDateTime::Time() const
1377 {
1378 return fTime;
1379 }
1380
1381
1382 /*!
1383 Sets the current time of this object to \c time.
1384 */
1385 void
SetTime(const BTime & time)1386 BDateTime::SetTime(const BTime& time)
1387 {
1388 fTime = time;
1389 }
1390
1391
1392 /*!
1393 Returns the current date and time converted to seconds since
1394 1.1.1970 - 00:00:00. If the current date is before 1.1.1970 the function
1395 returns -1;
1396 */
1397 time_t
Time_t() const1398 BDateTime::Time_t() const
1399 {
1400 BDate date(1970, 1, 1);
1401 if (date.Difference(fDate) < 0)
1402 return -1;
1403
1404 tm tm_struct;
1405
1406 tm_struct.tm_hour = fTime.Hour();
1407 tm_struct.tm_min = fTime.Minute();
1408 tm_struct.tm_sec = fTime.Second();
1409
1410 tm_struct.tm_year = fDate.Year() - 1900;
1411 tm_struct.tm_mon = fDate.Month() - 1;
1412 tm_struct.tm_mday = fDate.Day();
1413
1414 // set less 0 as we won't use it
1415 tm_struct.tm_isdst = -1;
1416
1417 // return secs_since_jan1_1970 or -1 on error
1418 return mktime(&tm_struct);
1419 }
1420
1421
1422 /*!
1423 Sets the current date and time converted from seconds since
1424 1.1.1970 - 00:00:00.
1425 */
1426 void
SetTime_t(time_t seconds)1427 BDateTime::SetTime_t(time_t seconds)
1428 {
1429 time_t timePart = seconds % kSecondsPerDay;
1430 if (timePart < 0) {
1431 timePart += kSecondsPerDay;
1432 seconds -= kSecondsPerDay;
1433 }
1434
1435 BTime time;
1436 time.AddSeconds(timePart);
1437 fTime.SetTime(time);
1438
1439 BDate date(1970, 1, 1);
1440 date.AddDays(seconds / kSecondsPerDay);
1441 fDate.SetDate(date);
1442 }
1443
1444
1445 /*!
1446 Returns true if this datetime is different from \c dateTime, otherwise false.
1447 */
1448 bool
operator !=(const BDateTime & dateTime) const1449 BDateTime::operator!=(const BDateTime& dateTime) const
1450 {
1451 return fTime != dateTime.fTime && fDate != dateTime.fDate;
1452 }
1453
1454
1455 /*!
1456 Returns true if this datetime is equal to \c dateTime, otherwise false.
1457 */
1458 bool
operator ==(const BDateTime & dateTime) const1459 BDateTime::operator==(const BDateTime& dateTime) const
1460 {
1461 return fTime == dateTime.fTime && fDate == dateTime.fDate;
1462 }
1463
1464
1465 /*!
1466 Returns true if this datetime is earlier than \c dateTime, otherwise false.
1467 */
1468 bool
operator <(const BDateTime & dateTime) const1469 BDateTime::operator<(const BDateTime& dateTime) const
1470 {
1471 if (fDate < dateTime.fDate)
1472 return true;
1473 if (fDate == dateTime.fDate)
1474 return fTime < dateTime.fTime;
1475 return false;
1476 }
1477
1478
1479 /*!
1480 Returns true if this datetime is earlier than or equal to \c dateTime,
1481 otherwise false.
1482 */
1483 bool
operator <=(const BDateTime & dateTime) const1484 BDateTime::operator<=(const BDateTime& dateTime) const
1485 {
1486 if (fDate < dateTime.fDate)
1487 return true;
1488 if (fDate == dateTime.fDate)
1489 return fTime <= dateTime.fTime;
1490 return false;
1491 }
1492
1493
1494 /*!
1495 Returns true if this datetime is later than \c dateTime, otherwise false.
1496 */
1497 bool
operator >(const BDateTime & dateTime) const1498 BDateTime::operator>(const BDateTime& dateTime) const
1499 {
1500 if (fDate > dateTime.fDate)
1501 return true;
1502 if (fDate == dateTime.fDate)
1503 return fTime > dateTime.fTime;
1504 return false;
1505 }
1506
1507
1508 /*!
1509 Returns true if this datetime is later than or equal to \c dateTime,
1510 otherwise false.
1511 */
1512 bool
operator >=(const BDateTime & dateTime) const1513 BDateTime::operator>=(const BDateTime& dateTime) const
1514 {
1515 if (fDate > dateTime.fDate)
1516 return true;
1517 if (fDate == dateTime.fDate)
1518 return fTime >= dateTime.fTime;
1519 return false;
1520 }
1521
1522 } /* namespace BPrivate */
1523