7 #define FileName _FileName
8 #define Instance _Instance
13 #define uint64 _uint64
14 #define Alignment _Alignment
18 #if defined(__WIN32__)
19 #define WIN32_LEAN_AND_MEAN
20 #define String String_
24 #elif defined(__unix__) || defined(__APPLE__)
47 define EPOCH_YEAR = 1970;
48 define EPOCH_WEEKDAY = thursday;
49 static define SECS_PER_HOUR = 60 * 60;
50 static define SECS_PER_DAY = SECS_PER_HOUR * 24;
52 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
53 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
54 #define ISLEAP(y) (!((y)%4) && (((y) % 100) || (!((y)% 400))))
56 const int daysInAYearBeforeMonth[2][13] =
59 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
61 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
64 int monthLengths[2][12] =
66 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
67 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
70 #if defined(__WIN32__)
72 #define LL2FILETIME( ll, pft ) (pft)->dwLowDateTime = (UINT)(ll); (pft)->dwHighDateTime = (UINT)((ll) >> 32);
73 #define FILETIME2LL( pft, ll) ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
75 static int TIME_DayLightCompareDate(const SYSTEMTIME *date, const SYSTEMTIME *compareDate)
77 int limit_day, dayinsecs;
79 if(date->wMonth < compareDate->wMonth) return -1;
80 if(date->wMonth > compareDate->wMonth) return 1;
82 if(compareDate->wDayOfWeek <= 6)
85 int weekofmonth = compareDate->wDay;
86 First = ( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay ) % 7 + 1;
87 limit_day = First + 7 * (weekofmonth - 1);
88 if(limit_day > monthLengths[date->wMonth==2 && ISLEAP(date->wYear)][date->wMonth - 1])
93 limit_day = compareDate->wDay;
96 limit_day = ((limit_day * 24 + compareDate->wHour) * 60 + compareDate->wMinute ) * 60;
97 dayinsecs = ((date->wDay * 24 + date->wHour) * 60 + date->wMinute ) * 60 + date->wSecond;
98 return dayinsecs < limit_day ? -1 : dayinsecs > limit_day ? 1 : 0;
101 static uint TIME_CompTimeZoneID(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal)
104 bool beforeStandardDate, afterDaylightDate;
105 DWORD retval = TIME_ZONE_ID_INVALID;
110 if (pTZinfo->DaylightDate.wMonth != 0)
112 if (pTZinfo->StandardDate.wMonth == 0 ||
113 pTZinfo->StandardDate.wDay<1 ||
114 pTZinfo->StandardDate.wDay>5 ||
115 pTZinfo->DaylightDate.wDay<1 ||
116 pTZinfo->DaylightDate.wDay>5)
118 SetLastError(ERROR_INVALID_PARAMETER);
119 return TIME_ZONE_ID_INVALID;
124 FILETIME2LL( lpFileTime, llTime );
125 llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias ) * (LONGLONG)600000000;
126 LL2FILETIME( llTime, &ftTemp)
127 lpFileTime = &ftTemp;
130 FileTimeToSystemTime(lpFileTime, &SysTime);
132 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
134 return TIME_ZONE_ID_INVALID;
136 beforeStandardDate = ret < 0;
140 llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias ) * (LONGLONG)600000000;
141 LL2FILETIME( llTime, &ftTemp)
142 FileTimeToSystemTime(lpFileTime, &SysTime);
145 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
147 return TIME_ZONE_ID_INVALID;
149 afterDaylightDate = ret >= 0;
151 retval = TIME_ZONE_ID_STANDARD;
152 if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth )
154 if( beforeStandardDate && afterDaylightDate )
155 retval = TIME_ZONE_ID_DAYLIGHT;
157 else if( beforeStandardDate || afterDaylightDate )
158 retval = TIME_ZONE_ID_DAYLIGHT;
161 retval = TIME_ZONE_ID_UNKNOWN;
165 static bool TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal, LONG *pBias)
167 LONG bias = pTZinfo->Bias;
168 DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
170 if( tzid == TIME_ZONE_ID_INVALID)
172 if (tzid == TIME_ZONE_ID_DAYLIGHT)
173 bias += pTZinfo->DaylightBias;
174 else if (tzid == TIME_ZONE_ID_STANDARD)
175 bias += pTZinfo->StandardBias;
180 static bool _TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime)
185 TIME_ZONE_INFORMATION tzinfo;
187 if(lpTimeZoneInformation)
189 memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
193 if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
197 if (!SystemTimeToFileTime(lpLocalTime, &ft))
200 if (!TIME_GetTimezoneBias(&tzinfo, &ft, true, &lBias))
203 t += (LONGLONG)lBias * 600000000;
205 return (bool)FileTimeToSystemTime(&ft, lpUniversalTime);
211 public class Time : double
213 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
219 value = (int)(time / (60 * 60 * 24));
223 sprintf(temp, "%d:", value);
224 strcat(tempString, temp);
225 time -= value * 60 * 60 * 24;
227 value = (int)(time / (60 * 60));
230 sprintf(temp, "%d:", value);
231 strcat(tempString, temp);
232 time -= value * 60 * 60;
235 value = (int)(time / 60);
236 sprintf(temp, "%d:", value);
237 strcat(tempString, temp);
241 sprintf(temp, "%02d", value);
242 strcat(tempString, temp);
247 sprintf(temp, "%f" time);
248 strcat(tempString, temp+1);
254 public class Seconds : Time { public property Time {} };
256 #if !defined(__WIN32__)
257 static time_t MakeTimeT(SecSince1970 t)
262 tm.tm_year = dt.year - 1900;
263 tm.tm_mon = dt.month;
265 tm.tm_hour = dt.hour;
266 tm.tm_min = dt.minute;
267 tm.tm_sec = dt.second;
268 tm.tm_yday = dt.dayInTheYear;
269 tm.tm_wday = dt.dayOfTheWeek;
270 result = mktime(&tm);
274 static time_t MakeTimeTfromDT(DateTime dt)
278 tm.tm_year = dt.year - 1900;
279 tm.tm_mon = dt.month;
281 tm.tm_hour = dt.hour;
282 tm.tm_min = dt.minute;
283 tm.tm_sec = dt.second;
284 tm.tm_yday = dt.dayInTheYear;
285 tm.tm_wday = dt.dayOfTheWeek;
286 result = mktime(&tm);
292 public class SecSince1970 : int64
294 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
296 // TOFIX: passing argument 2 of '__ecereProp___ecereNameSpace__ecere__sys__DateTime_Set___ecereNameSpace__ecere__sys__SecSince1970' makes integer from pointer without a cast
298 return t.OnGetString(tempString, fieldData, needClass);
300 // return ((DateTime)this).OnGetString(tempString, fieldData, needClass);
304 int OnCompare(SecSince1970 data2)
311 else if(this < data2)
317 property SecSince1970 global
321 #if defined(__WIN32__)
322 SYSTEMTIME localTime, systemTime;
323 FILETIME fileTime, localFileTime;
324 DateTime input, global;
328 localTime.wYear = (short)input.year;
329 localTime.wMonth = (short)input.month + 1;
330 localTime.wDay = (short)input.day;
331 localTime.wHour = (short)input.hour;
332 localTime.wMinute = (short)input.minute;
333 localTime.wSecond = (short)input.second;
334 localTime.wMilliseconds = 0;
337 SystemTimeToFileTime(&localTime, &fileTime);
338 LocalFileTimeToFileTime(&fileTime, &localFileTime);
339 FileTimeToSystemTime(&localFileTime, &systemTime);
342 _TzSpecificLocalTimeToSystemTime(null, &localTime, &systemTime);
344 global.year = systemTime.wYear;
345 global.month = (Month)(systemTime.wMonth - 1);
346 global.day = systemTime.wDay;
347 global.hour = systemTime.wHour;
348 global.minute = systemTime.wMinute;
349 global.second = systemTime.wSecond;
355 time_t t = MakeTimeT(this);
356 // gmtime_r((time_t *)&this, &tm);
358 global.year = tm.tm_year + 1900;
359 global.month = (Month)tm.tm_mon;
360 global.day = tm.tm_mday;
361 global.hour = tm.tm_hour;
362 global.minute = tm.tm_min;
363 global.second = tm.tm_sec;
364 global.dayInTheYear = tm.tm_yday;
365 global.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
370 property SecSince1970 local
374 #if defined(__WIN32__)
375 SYSTEMTIME systemTime, localTime;
380 systemTime.wYear = (short)utc.year;
381 systemTime.wMonth = (short)utc.month + 1;
382 systemTime.wDay = (short)utc.day;
383 systemTime.wHour = (short)utc.hour;
384 systemTime.wMinute = (short)utc.minute;
385 systemTime.wSecond = (short)utc.second;
386 systemTime.wMilliseconds = 0;
388 SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
390 local.year = localTime.wYear;
391 local.month = (Month)(localTime.wMonth - 1);
392 local.day = localTime.wDay;
393 local.hour = localTime.wHour;
394 local.minute = localTime.wMinute;
395 local.second = localTime.wSecond;
396 local.dayOfTheWeek = (DayOfTheWeek)localTime.wDayOfWeek;
398 local.FixDayOfYear();
403 time_t t = MakeTimeT(this);
404 //localtime_r((time_t *)&this, &tm);
405 localtime_r(&t, &tm);
406 local.year = tm.tm_year + 1900;
407 local.month = (Month)tm.tm_mon;
408 local.day = tm.tm_mday;
409 local.hour = tm.tm_hour;
410 local.minute = tm.tm_min;
411 local.second = tm.tm_sec;
412 local.dayInTheYear = tm.tm_yday;
413 local.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
420 public class TimeStamp32 : uint32
423 char * OnGetString(char * tempString, void * fieldData, bool * needClass)
425 DateTime t = (SecSince1970)(int)this;
426 return t.OnGetString(tempString, fieldData, needClass);
428 // return ((DateTime)this).OnGetString(tempString, fieldData, needClass);
432 int OnCompare(TimeStamp32 data2)
439 else if(this < data2)
446 public class TimeStamp : SecSince1970
448 public property SecSince1970 {};
450 public enum DayOfTheWeek { sunday, monday, tuesday, wednesday, thursday, friday, saturday };
451 public struct DateTime
455 int day, hour, minute, second;
456 DayOfTheWeek dayOfTheWeek;
461 #if defined(__WIN32__)
462 SYSTEMTIME systemTime;
463 ::GetLocalTime(&systemTime);
465 year = systemTime.wYear;
466 month = (Month)(systemTime.wMonth - 1);
467 day = systemTime.wDay;
468 hour = systemTime.wHour;
469 minute = systemTime.wMinute;
470 second = systemTime.wSecond;
474 Date date { year, month, day };
475 dayOfTheWeek = date.dayOfTheWeek;
479 time_t currentTime = time(null);
480 localtime_r(¤tTime, &tm);
482 year = tm.tm_year + 1900;
483 month = (Month)tm.tm_mon;
488 dayInTheYear = tm.tm_yday;
489 dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
497 dayInTheYear = daysInAYearBeforeMonth[ISLEAP(year)][month] + day - 1;
501 property DateTime global
503 set { this = value.local; }
506 #if defined(__WIN32__)
507 SYSTEMTIME localTime, systemTime;
508 FILETIME fileTime, localFileTime;
510 localTime.wYear = (short)year;
511 localTime.wMonth = (short)month + 1;
512 localTime.wDay = (short)day;
513 localTime.wHour = (short)hour;
514 localTime.wMinute = (short)minute;
515 localTime.wSecond = (short)second;
516 localTime.wMilliseconds = 0;
518 SystemTimeToFileTime(&localTime, &fileTime);
519 LocalFileTimeToFileTime(&fileTime, &localFileTime);
520 FileTimeToSystemTime(&localFileTime, &systemTime);
522 value.year = systemTime.wYear;
523 value.month = (Month)(systemTime.wMonth - 1);
524 value.day = systemTime.wDay;
525 value.hour = systemTime.wHour;
526 value.minute = systemTime.wMinute;
527 value.second = systemTime.wSecond;
530 //time_t t = (time_t)(SecSince1970)this;
531 time_t t = MakeTimeTfromDT(this);
533 value.year = tm.tm_year + 1900;
534 value.month = (Month)tm.tm_mon;
535 value.day = tm.tm_mday;
536 value.hour = tm.tm_hour;
537 value.minute = tm.tm_min;
538 value.second = tm.tm_sec;
539 value.dayInTheYear = tm.tm_yday;
540 value.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
544 property DateTime local
546 set { this = value.global; }
549 #if defined(__WIN32__)
550 SYSTEMTIME systemTime, localTime;
552 systemTime.wYear = (short)year;
553 systemTime.wMonth = (short)month + 1;
554 systemTime.wDay = (short)day;
555 systemTime.wHour = (short)hour;
556 systemTime.wMinute = (short)minute;
557 systemTime.wSecond = (short)second;
558 systemTime.wMilliseconds = 0;
560 SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
562 value.year = localTime.wYear;
563 value.month = (Month)(localTime.wMonth - 1);
564 value.day = localTime.wDay;
565 value.hour = localTime.wHour;
566 value.minute = localTime.wMinute;
567 value.second = localTime.wSecond;
568 value.dayOfTheWeek = (DayOfTheWeek)localTime.wDayOfWeek;
570 value.FixDayOfYear();
573 // time_t t = (time_t)(SecSince1970)this;
574 time_t t = MakeTimeTfromDT(this);
575 localtime_r(&t, &tm);
576 value.year = tm.tm_year + 1900;
577 value.month = (Month)tm.tm_mon;
578 value.day = tm.tm_mday;
579 value.hour = tm.tm_hour;
580 value.minute = tm.tm_min;
581 value.second = tm.tm_sec;
582 value.dayInTheYear = tm.tm_yday;
583 value.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
587 property SecSince1970
594 days = value / SECS_PER_DAY;
595 rem = (int)(value % SECS_PER_DAY);
597 while(rem < 0) { rem += SECS_PER_DAY; days--; }
598 while(rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; days++; }
600 hour = rem / SECS_PER_HOUR;
602 rem %= SECS_PER_HOUR;
606 dayOfTheWeek = (EPOCH_WEEKDAY + days) % 7;
611 while(days < 0 || days >= daysInAYearBeforeMonth[ISLEAP(y)][12])
613 int64 yg = y + days / 365 - (days % 365 < 0);
614 days -= ((yg - y) * 365 + LEAPS_THRU_END_OF(yg - 1) - LEAPS_THRU_END_OF(y - 1));
619 const int * daysBeforeMonth = daysInAYearBeforeMonth[ISLEAP(y)];
620 dayInTheYear = (int)days;
621 for(y = 11; days < daysBeforeMonth[y]; y--);
622 days -= daysBeforeMonth[y];
624 day = (int)(days + 1);
630 int month = this.month;
631 int monthRemainder = month % 12;
632 bool negativeMonthRemainder = monthRemainder < 0;
633 int monthYears = month / 12 - negativeMonthRemainder;
634 int year = this.year + monthYears;
637 int a4 = (year / 4) - !(year & 3);
638 int b4 = (EPOCH_YEAR / 4) - !(EPOCH_YEAR & 3);
639 int a100 = a4 / 25 - (a4 % 25 < 0);
640 int b100 = b4 / 25 - (b4 % 25 < 0);
643 int leapDays = (a4 - b4) - (a100 - b100) + (a400 - b400);
644 int64 days = 365 * (year - EPOCH_YEAR) + leapDays;
645 month = monthRemainder + 12 * negativeMonthRemainder;
646 days += daysInAYearBeforeMonth[ISLEAP(year)][month] + day - 1;
647 return 60 * (60 * (24 * days + hour) + minute) + second;
663 get { return Date { year, month, day }; }
666 char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
668 static const char ampm[2][3] = { "AM", "PM" };
669 int hour = this.hour;
671 if(hour > 12) { hour -= 12; pm = true; }
672 else if(hour == 12) pm = true;
675 if(!year && !day && !month && !this.hour && !minute && !second)
678 sprintf(stringOutput, "%s %s %2d %2d:%02d:%02d %s %04d",
679 shortDaysNames[dayOfTheWeek], shortMonthsNames[month], day, hour, minute, second, ampm[pm], year);
684 bool OnGetDataFromString(char * string)
686 char * s = CopyString(string);
688 int count = TokenizeWith(s, 20, tokens, " ", false);
690 bool foundDayOfTheWeek = false;
691 bool foundDate = false;
692 DayOfTheWeek dayOfTheWeek;
699 for(c = 0; c < count; c++)
703 if(!strcmpi(tokens[c], shortDaysNames[i]) || !strcmpi(tokens[c], longDaysNames[i]) ||
704 !strcmpi(tokens[c], enShortDaysNames[i]) || !strcmpi(tokens[c], enLongDaysNames[i]))
706 if(i < 7) { dayOfTheWeek = (DayOfTheWeek)i; foundDayOfTheWeek = true; continue; }
708 for(i = 0; i<12; i++)
709 if(!strcmpi(tokens[c], shortMonthsNames[i]) || !strcmpi(tokens[c], longMonthsNames[i]) ||
710 !strcmpi(tokens[c], enShortMonthsNames[i]) || !strcmpi(tokens[c], enLongMonthsNames[i]))
712 if(i < 12) { month = (Month)i; continue; }
714 if(strchr(tokens[c], ':'))
716 char * subTokens[20];
717 int sCount = TokenizeWith(tokens[c], 20, subTokens, " :", false);
719 bool pm = false, am = false;
720 for(t = 0; t<sCount; t++)
722 if(!strcmpi(subTokens[t], "am")) am = true;
723 else if(!strcmpi(subTokens[t], "pm")) pm = true;
724 else if(t-am-pm == 0) hour = atoi(subTokens[t]);
725 else if(t-am-pm == 1) minute = atoi(subTokens[t]);
726 else if(t-am-pm == 2) second = atoi(subTokens[t]);
731 if(!strcmpi(tokens[c+1], "am")) am = true;
732 else if(!strcmpi(tokens[c+1], "pm")) pm = true;
735 if(am && hour == 12) hour = 0;
736 else if(pm && hour < 12) hour += 12;
743 if(strchr(tokens[c], '/') || strchr(tokens[c], '-'))
746 if(date.OnGetDataFromString(tokens[c]))
769 Date date { year, month, day };
770 this.dayOfTheWeek = date.dayOfTheWeek;
772 this.minute = minute;
773 this.second = second;
777 else if(foundDayOfTheWeek)
781 if(dayOfTheWeek <= this.dayOfTheWeek) dayOfTheWeek += 7;
782 weWant = (SecSince1970)this + (int)(dayOfTheWeek - this.dayOfTheWeek) * 24 * 60 * 60;
783 this = (DateTime)weWant;
785 else if(!strcmpi(s, "today") || !strcmpi(s, $"today") ||
786 !strcmpi(s, "now") || !strcmpi(s, $"now"))
788 else if(!strcmpi(s, "tomorrow") || !strcmpi(s, $"tomorrow"))
792 weWant = (SecSince1970)this + 24 * 60 * 60;
793 this = (DateTime)weWant;
795 else if(!strcmpi(s, "yesterday") || !strcmpi(s, $"yesterday"))
799 weWant = (SecSince1970)this - 24 * 60 * 60;
800 this = (DateTime)weWant;
809 return this.day != 0;
813 public Time GetTime(void)
815 #if defined(__WIN32__)
816 return timeGetTime() / 1000.0;
817 #elif defined(__unix__) || defined(__APPLE__)
820 static int secbase = 0;
822 gettimeofday(&tp, &tzp);
826 secbase = (int)tp.tv_sec;
827 return tp.tv_usec / 1000000.0;
829 return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
833 public void Sleep(Seconds seconds)
835 #if defined(__WIN32__)
836 ::Sleep((uint)(seconds * 1000));
842 // usleep((uint)(seconds * 1000000));
843 struct timeval tv = { (int)seconds, (int)((seconds - (int)seconds) * 1000000) };
844 select(0,null,null,null, &tv);
849 public void RandomSeed(uint seed)
851 #if defined(__linux__) || defined(__DJGPP__)
858 public int GetRandom(int lo, int hi)
862 #if defined(__linux__) || defined(__DJGPP__)
863 // return lo+(int)(((uint)(hi - lo) + 1.0)*random()/(RAND_MAX+1.0));
864 return (int)(lo + ((uint)(hi - lo) + 1.0) * random() / (RAND_MAX + 1.0));
866 // return lo+(int)(((uint)(hi - lo) + 1.0)*rand()/(RAND_MAX+1.0));
867 return (int)(lo + ((uint)(hi - lo) + 1.0) * rand() / (RAND_MAX + 1.0));