9 #define FileName _FileName
10 #define Instance _Instance
15 #define uint64 _uint64
16 #define Alignment _Alignment
20 #if defined(__WIN32__)
21 #define WIN32_LEAN_AND_MEAN
22 #define String String_
26 #elif defined(__unix__) || defined(__APPLE__)
49 define EPOCH_YEAR = 1970;
50 define EPOCH_WEEKDAY = thursday;
51 static define SECS_PER_HOUR = 60 * 60;
52 static define SECS_PER_DAY = SECS_PER_HOUR * 24;
54 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
55 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
56 #define ISLEAP(y) (!((y)%4) && (((y) % 100) || (!((y)% 400))))
58 const int daysInAYearBeforeMonth[2][13] =
61 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
63 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
66 int monthLengths[2][12] =
68 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
69 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
72 #if defined(__WIN32__)
74 #define LL2FILETIME( ll, pft ) (pft)->dwLowDateTime = (UINT)(ll); (pft)->dwHighDateTime = (UINT)((ll) >> 32);
75 #define FILETIME2LL( pft, ll) ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
77 static int TIME_DayLightCompareDate(const SYSTEMTIME *date, const SYSTEMTIME *compareDate)
79 int limit_day, dayinsecs;
81 if(date->wMonth < compareDate->wMonth) return -1;
82 if(date->wMonth > compareDate->wMonth) return 1;
84 if(compareDate->wDayOfWeek <= 6)
87 int weekofmonth = compareDate->wDay;
88 First = (WORD)(( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay ) % 7 + 1);
89 limit_day = First + 7 * (weekofmonth - 1);
90 if(limit_day > monthLengths[date->wMonth==2 && ISLEAP(date->wYear)][date->wMonth - 1])
95 limit_day = compareDate->wDay;
98 limit_day = ((limit_day * 24 + compareDate->wHour) * 60 + compareDate->wMinute ) * 60;
99 dayinsecs = ((date->wDay * 24 + date->wHour) * 60 + date->wMinute ) * 60 + date->wSecond;
100 return dayinsecs < limit_day ? -1 : dayinsecs > limit_day ? 1 : 0;
103 static uint TIME_CompTimeZoneID(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal)
106 bool beforeStandardDate, afterDaylightDate;
107 DWORD retval = TIME_ZONE_ID_INVALID;
112 if (pTZinfo->DaylightDate.wMonth != 0)
114 if (pTZinfo->StandardDate.wMonth == 0 ||
115 pTZinfo->StandardDate.wDay<1 ||
116 pTZinfo->StandardDate.wDay>5 ||
117 pTZinfo->DaylightDate.wDay<1 ||
118 pTZinfo->DaylightDate.wDay>5)
120 SetLastError(ERROR_INVALID_PARAMETER);
121 return TIME_ZONE_ID_INVALID;
126 FILETIME2LL( lpFileTime, llTime );
127 llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias ) * (LONGLONG)600000000;
128 LL2FILETIME( llTime, &ftTemp)
129 lpFileTime = &ftTemp;
132 FileTimeToSystemTime(lpFileTime, &SysTime);
134 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
136 return TIME_ZONE_ID_INVALID;
138 beforeStandardDate = ret < 0;
142 llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias ) * (LONGLONG)600000000;
143 LL2FILETIME( llTime, &ftTemp)
144 FileTimeToSystemTime(lpFileTime, &SysTime);
147 ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
149 return TIME_ZONE_ID_INVALID;
151 afterDaylightDate = ret >= 0;
153 retval = TIME_ZONE_ID_STANDARD;
154 if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth )
156 if( beforeStandardDate && afterDaylightDate )
157 retval = TIME_ZONE_ID_DAYLIGHT;
159 else if( beforeStandardDate || afterDaylightDate )
160 retval = TIME_ZONE_ID_DAYLIGHT;
163 retval = TIME_ZONE_ID_UNKNOWN;
167 static bool TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal, LONG *pBias)
169 LONG bias = pTZinfo->Bias;
170 DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
172 if( tzid == TIME_ZONE_ID_INVALID)
174 if (tzid == TIME_ZONE_ID_DAYLIGHT)
175 bias += pTZinfo->DaylightBias;
176 else if (tzid == TIME_ZONE_ID_STANDARD)
177 bias += pTZinfo->StandardBias;
182 static bool _TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime)
187 TIME_ZONE_INFORMATION tzinfo;
189 if(lpTimeZoneInformation)
191 memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
195 if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
199 if (!SystemTimeToFileTime(lpLocalTime, &ft))
202 if (!TIME_GetTimezoneBias(&tzinfo, &ft, true, &lBias))
205 t += (LONGLONG)lBias * 600000000;
207 return (bool)FileTimeToSystemTime(&ft, lpUniversalTime);
213 public class Time : double
215 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
221 value = (int)(time / (60 * 60 * 24));
225 sprintf(temp, "%d:", value);
226 strcat(tempString, temp);
227 time -= value * 60 * 60 * 24;
229 value = (int)(time / (60 * 60));
232 sprintf(temp, "%d:", value);
233 strcat(tempString, temp);
234 time -= value * 60 * 60;
237 value = (int)(time / 60);
238 sprintf(temp, "%d:", value);
239 strcat(tempString, temp);
243 sprintf(temp, "%02d", value);
244 strcat(tempString, temp);
249 sprintf(temp, "%f" time);
250 strcat(tempString, temp+1);
256 public class Seconds : Time { public property Time {} };
258 #if !defined(__WIN32__)
259 static time_t MakeTimeT(SecSince1970 t)
264 tm.tm_year = dt.year - 1900;
265 tm.tm_mon = dt.month;
267 tm.tm_hour = dt.hour;
268 tm.tm_min = dt.minute;
269 tm.tm_sec = dt.second;
270 tm.tm_yday = dt.dayInTheYear;
271 tm.tm_wday = dt.dayOfTheWeek;
272 result = mktime(&tm);
276 static time_t MakeTimeTfromDT(DateTime dt)
280 tm.tm_year = dt.year - 1900;
281 tm.tm_mon = dt.month;
283 tm.tm_hour = dt.hour;
284 tm.tm_min = dt.minute;
285 tm.tm_sec = dt.second;
286 tm.tm_yday = dt.dayInTheYear;
287 tm.tm_wday = dt.dayOfTheWeek;
288 result = mktime(&tm);
294 public class SecSince1970 : int64
296 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
298 return ((DateTime)this).OnGetString(tempString, fieldData, needClass);
301 bool OnGetDataFromString(const char * string)
304 if(dt.OnGetDataFromString(string))
313 int OnCompare(SecSince1970 data2)
320 else if(this < data2)
326 property SecSince1970 global
330 #if defined(__WIN32__)
331 SYSTEMTIME localTime, systemTime;
332 //FILETIME fileTime, localFileTime;
333 DateTime input, global;
337 localTime.wYear = (short)input.year;
338 localTime.wMonth = (short)(input.month + 1);
339 localTime.wDay = (short)input.day;
340 localTime.wHour = (short)input.hour;
341 localTime.wMinute = (short)input.minute;
342 localTime.wSecond = (short)input.second;
343 localTime.wMilliseconds = 0;
346 SystemTimeToFileTime(&localTime, &fileTime);
347 LocalFileTimeToFileTime(&fileTime, &localFileTime);
348 FileTimeToSystemTime(&localFileTime, &systemTime);
351 _TzSpecificLocalTimeToSystemTime(null, &localTime, &systemTime);
353 global.year = systemTime.wYear;
354 global.month = (Month)(systemTime.wMonth - 1);
355 global.day = systemTime.wDay;
356 global.hour = systemTime.wHour;
357 global.minute = systemTime.wMinute;
358 global.second = systemTime.wSecond;
364 time_t t = MakeTimeT(this);
365 // gmtime_r((time_t *)&this, &tm);
367 global.year = tm.tm_year + 1900;
368 global.month = (Month)tm.tm_mon;
369 global.day = tm.tm_mday;
370 global.hour = tm.tm_hour;
371 global.minute = tm.tm_min;
372 global.second = tm.tm_sec;
373 global.dayInTheYear = tm.tm_yday;
374 global.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
379 property SecSince1970 local
383 #if defined(__WIN32__)
384 SYSTEMTIME systemTime, localTime;
389 systemTime.wYear = (short)utc.year;
390 systemTime.wMonth = (short)(utc.month + 1);
391 systemTime.wDay = (short)utc.day;
392 systemTime.wHour = (short)utc.hour;
393 systemTime.wMinute = (short)utc.minute;
394 systemTime.wSecond = (short)utc.second;
395 systemTime.wMilliseconds = 0;
397 SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
399 local.year = localTime.wYear;
400 local.month = (Month)(localTime.wMonth - 1);
401 local.day = localTime.wDay;
402 local.hour = localTime.wHour;
403 local.minute = localTime.wMinute;
404 local.second = localTime.wSecond;
405 local.dayOfTheWeek = (DayOfTheWeek)localTime.wDayOfWeek;
407 local.FixDayOfYear();
412 time_t t = MakeTimeT(this);
413 //localtime_r((time_t *)&this, &tm);
414 localtime_r(&t, &tm);
415 local.year = tm.tm_year + 1900;
416 local.month = (Month)tm.tm_mon;
417 local.day = tm.tm_mday;
418 local.hour = tm.tm_hour;
419 local.minute = tm.tm_min;
420 local.second = tm.tm_sec;
421 local.dayInTheYear = tm.tm_yday;
422 local.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
429 public class TimeStamp32 : uint32
432 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
434 return ((DateTime)(TimeStamp)this).OnGetString(tempString, fieldData, needClass);
438 int OnCompare(TimeStamp32 data2)
445 else if(this < data2)
452 public class TimeStamp : SecSince1970
454 public property SecSince1970 {};
456 public enum DayOfTheWeek { sunday, monday, tuesday, wednesday, thursday, friday, saturday };
457 public struct DateTime
461 int day, hour, minute, second;
462 DayOfTheWeek dayOfTheWeek;
467 #if defined(__WIN32__)
468 SYSTEMTIME systemTime;
469 ::GetLocalTime(&systemTime);
471 year = systemTime.wYear;
472 month = (Month)(systemTime.wMonth - 1);
473 day = systemTime.wDay;
474 hour = systemTime.wHour;
475 minute = systemTime.wMinute;
476 second = systemTime.wSecond;
480 Date date { year, month, day };
481 dayOfTheWeek = date.dayOfTheWeek;
485 time_t currentTime = time(null);
486 localtime_r(¤tTime, &tm);
488 year = tm.tm_year + 1900;
489 month = (Month)tm.tm_mon;
494 dayInTheYear = tm.tm_yday;
495 dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
503 dayInTheYear = daysInAYearBeforeMonth[ISLEAP(year)][month] + day - 1;
507 property DateTime global
509 set { this = value.local; }
512 #if defined(__WIN32__)
513 SYSTEMTIME localTime, systemTime;
514 FILETIME fileTime, localFileTime;
516 localTime.wYear = (short)year;
517 localTime.wMonth = (short)(month + 1);
518 localTime.wDay = (short)day;
519 localTime.wHour = (short)hour;
520 localTime.wMinute = (short)minute;
521 localTime.wSecond = (short)second;
522 localTime.wMilliseconds = 0;
524 SystemTimeToFileTime(&localTime, &fileTime);
525 LocalFileTimeToFileTime(&fileTime, &localFileTime);
526 FileTimeToSystemTime(&localFileTime, &systemTime);
528 value.year = systemTime.wYear;
529 value.month = (Month)(systemTime.wMonth - 1);
530 value.day = systemTime.wDay;
531 value.hour = systemTime.wHour;
532 value.minute = systemTime.wMinute;
533 value.second = systemTime.wSecond;
536 //time_t t = (time_t)(SecSince1970)this;
537 time_t t = MakeTimeTfromDT(this);
539 value.year = tm.tm_year + 1900;
540 value.month = (Month)tm.tm_mon;
541 value.day = tm.tm_mday;
542 value.hour = tm.tm_hour;
543 value.minute = tm.tm_min;
544 value.second = tm.tm_sec;
545 value.dayInTheYear = tm.tm_yday;
546 value.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
550 property DateTime local
552 set { this = value.global; }
555 #if defined(__WIN32__)
556 SYSTEMTIME systemTime, localTime;
558 systemTime.wYear = (short)year;
559 systemTime.wMonth = (short)(month + 1);
560 systemTime.wDay = (short)day;
561 systemTime.wHour = (short)hour;
562 systemTime.wMinute = (short)minute;
563 systemTime.wSecond = (short)second;
564 systemTime.wMilliseconds = 0;
566 SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
568 value.year = localTime.wYear;
569 value.month = (Month)(localTime.wMonth - 1);
570 value.day = localTime.wDay;
571 value.hour = localTime.wHour;
572 value.minute = localTime.wMinute;
573 value.second = localTime.wSecond;
574 value.dayOfTheWeek = (DayOfTheWeek)localTime.wDayOfWeek;
576 value.FixDayOfYear();
579 // time_t t = (time_t)(SecSince1970)this;
580 time_t t = MakeTimeTfromDT(this);
581 localtime_r(&t, &tm);
582 value.year = tm.tm_year + 1900;
583 value.month = (Month)tm.tm_mon;
584 value.day = tm.tm_mday;
585 value.hour = tm.tm_hour;
586 value.minute = tm.tm_min;
587 value.second = tm.tm_sec;
588 value.dayInTheYear = tm.tm_yday;
589 value.dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
593 property SecSince1970
600 days = value / SECS_PER_DAY;
601 rem = (int)(value % SECS_PER_DAY);
603 while(rem < 0) { rem += SECS_PER_DAY; days--; }
604 while(rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; days++; }
606 hour = rem / SECS_PER_HOUR;
608 rem %= SECS_PER_HOUR;
612 dayOfTheWeek = (EPOCH_WEEKDAY + days) % 7;
617 while(days < 0 || days >= daysInAYearBeforeMonth[ISLEAP(y)][12])
619 int64 yg = y + days / 365 - (days % 365 < 0);
620 days -= ((yg - y) * 365 + LEAPS_THRU_END_OF(yg - 1) - LEAPS_THRU_END_OF(y - 1));
625 const int * daysBeforeMonth = daysInAYearBeforeMonth[ISLEAP(y)];
626 dayInTheYear = (int)days;
627 for(y = 11; days < daysBeforeMonth[y]; y--);
628 days -= daysBeforeMonth[y];
630 day = (int)(days + 1);
636 int month = this.month;
637 int monthRemainder = month % 12;
638 bool negativeMonthRemainder = monthRemainder < 0;
639 int monthYears = month / 12 - negativeMonthRemainder;
640 int year = this.year + monthYears;
643 int a4 = (year / 4) - !(year & 3);
644 int b4 = (EPOCH_YEAR / 4) - !(EPOCH_YEAR & 3);
645 int a100 = a4 / 25 - (a4 % 25 < 0);
646 int b100 = b4 / 25 - (b4 % 25 < 0);
649 int leapDays = (a4 - b4) - (a100 - b100) + (a400 - b400);
650 int64 days = 365 * (year - EPOCH_YEAR) + leapDays;
651 month = monthRemainder + 12 * negativeMonthRemainder;
652 days += daysInAYearBeforeMonth[ISLEAP(year)][month] + day - 1;
653 return 60 * (60 * (24 * days + hour) + minute) + second;
669 get { value = Date { year, month, day }; }
672 const char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
674 static const char ampm[2][3] = { "AM", "PM" };
675 int hour = this.hour;
677 if(hour > 12) { hour -= 12; pm = true; }
678 else if(hour == 12) pm = true;
681 if(!year && !day && !month && !this.hour && !minute && !second)
684 sprintf(stringOutput, "%s %s %2d %2d:%02d:%02d %s %04d",
685 shortDaysNames[dayOfTheWeek], shortMonthsNames[month], day, hour, minute, second, ampm[pm], year);
690 bool OnGetDataFromString(const char * string)
692 char * s = CopyString(string);
694 int count = TokenizeWith(s, 20, tokens, " ", false);
696 bool foundDayOfTheWeek = false;
697 bool foundDate = false;
698 DayOfTheWeek dayOfTheWeek = 0;
705 for(c = 0; c < count; c++)
709 if(!strcmpi(tokens[c], shortDaysNames[i]) || !strcmpi(tokens[c], longDaysNames[i]) ||
710 !strcmpi(tokens[c], enShortDaysNames[i]) || !strcmpi(tokens[c], enLongDaysNames[i]))
712 if(i < 7) { dayOfTheWeek = (DayOfTheWeek)i; foundDayOfTheWeek = true; continue; }
714 for(i = 0; i<12; i++)
715 if(!strcmpi(tokens[c], shortMonthsNames[i]) || !strcmpi(tokens[c], longMonthsNames[i]) ||
716 !strcmpi(tokens[c], enShortMonthsNames[i]) || !strcmpi(tokens[c], enLongMonthsNames[i]))
718 if(i < 12) { month = (Month)i; continue; }
720 if(strchr(tokens[c], ':'))
722 char * subTokens[20];
723 int sCount = TokenizeWith(tokens[c], 20, subTokens, " :", false);
725 bool pm = false, am = false;
726 for(t = 0; t<sCount; t++)
728 if(!strcmpi(subTokens[t], "am")) am = true;
729 else if(!strcmpi(subTokens[t], "pm")) pm = true;
730 else if(t-am-pm == 0) hour = atoi(subTokens[t]);
731 else if(t-am-pm == 1) minute = atoi(subTokens[t]);
732 else if(t-am-pm == 2) second = atoi(subTokens[t]);
737 if(!strcmpi(tokens[c+1], "am")) am = true;
738 else if(!strcmpi(tokens[c+1], "pm")) pm = true;
741 if(am && hour == 12) hour = 0;
742 else if(pm && hour < 12) hour += 12;
749 if(strchr(tokens[c], '/') || strchr(tokens[c], '-'))
752 if(date.OnGetDataFromString(tokens[c]))
775 Date date { year, month, day };
776 this.dayOfTheWeek = date.dayOfTheWeek;
778 this.minute = minute;
779 this.second = second;
783 else if(foundDayOfTheWeek)
787 if(dayOfTheWeek <= this.dayOfTheWeek) dayOfTheWeek += 7;
788 weWant = (SecSince1970)this + (int)(dayOfTheWeek - this.dayOfTheWeek) * 24 * 60 * 60;
789 this = (DateTime)weWant;
791 else if(!strcmpi(s, "today") || !strcmpi(s, $"today") ||
792 !strcmpi(s, "now") || !strcmpi(s, $"now"))
794 else if(!strcmpi(s, "tomorrow") || !strcmpi(s, $"tomorrow"))
798 weWant = (SecSince1970)this + 24 * 60 * 60;
799 this = (DateTime)weWant;
801 else if(!strcmpi(s, "yesterday") || !strcmpi(s, $"yesterday"))
805 weWant = (SecSince1970)this - 24 * 60 * 60;
806 this = (DateTime)weWant;
815 return this.day != 0;
819 public Time GetTime(void)
821 #if defined(__WIN32__)
822 return timeGetTime() / 1000.0;
823 #elif defined(__unix__) || defined(__APPLE__)
826 static int secbase = 0;
828 gettimeofday(&tp, &tzp);
832 secbase = (int)tp.tv_sec;
833 return tp.tv_usec / 1000000.0;
835 return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
839 public void Sleep(Seconds seconds)
841 #if defined(__WIN32__)
842 ::Sleep((uint)(seconds * 1000));
848 // usleep((uint)(seconds * 1000000));
849 struct timeval tv = { (int)seconds, (int)((seconds - (int)seconds) * 1000000) };
850 select(0,null,null,null, &tv);
855 public void RandomSeed(uint seed)
857 #if defined(__linux__) || defined(__DJGPP__)
864 public int GetRandom(int lo, int hi)
868 #if defined(__linux__) || defined(__DJGPP__)
869 // return lo+(int)(((uint)(hi - lo) + 1.0)*random()/(RAND_MAX+1.0));
870 return (int)(lo + ((uint)(hi - lo) + 1.0) * random() / (RAND_MAX + 1.0));
872 // return lo+(int)(((uint)(hi - lo) + 1.0)*rand()/(RAND_MAX+1.0));
873 return (int)(lo + ((uint)(hi - lo) + 1.0) * rand() / (RAND_MAX + 1.0));