ecere: Initial Emscripten support
[sdk] / ecere / src / sys / Time.ec
1 namespace sys;
2
3 #define _Noreturn
4
5 #define set _set
6 #define Date _Date
7 #define uint _uint
8 #define Method _Method
9 #define FileName _FileName
10 #define Instance _Instance
11 #define Size _Size
12 #define File _File
13 #define byte _byte
14 #define int64 _int64
15 #define uint64 _uint64
16 #define Alignment _Alignment
17
18 #undef __BLOCKS__
19
20 #if defined(__WIN32__)
21 #define WIN32_LEAN_AND_MEAN
22 #define String String_
23 #include <windows.h>
24 #undef String
25 #include <mmsystem.h>
26 #elif defined(__unix__) || defined(__APPLE__)
27 #include <sys/time.h>
28 #include <sched.h>
29 #include <unistd.h>
30 #endif
31 #include <time.h>
32 #include <stdlib.h>
33
34 #undef set
35 #undef uint
36 #undef int64
37 #undef uint64
38 #undef byte
39 #undef Method
40 #undef Alignment
41 #undef FileName
42 #undef Instance
43 #undef File
44 #undef Size
45 #undef Date
46
47 import "instance"
48
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;
53
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))))
57
58 const int daysInAYearBeforeMonth[2][13] =
59 {
60    // Normal years.
61    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
62    // Leap years.
63    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
64 };
65
66 int monthLengths[2][12] =
67 {
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 }
70 };
71
72 #if defined(__WIN32__)
73
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 ;
76
77 static int TIME_DayLightCompareDate(const SYSTEMTIME *date, const SYSTEMTIME *compareDate)
78 {
79    int limit_day, dayinsecs;
80
81    if(date->wMonth < compareDate->wMonth) return -1;
82    if(date->wMonth > compareDate->wMonth) return 1;
83
84    if(compareDate->wDayOfWeek <= 6)
85    {
86       WORD First;
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])
91          limit_day -= 7;
92    }
93    else
94    {
95       limit_day = compareDate->wDay;
96    }
97
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;
101 }
102
103 static uint TIME_CompTimeZoneID(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal)
104 {
105    int ret;
106    bool beforeStandardDate, afterDaylightDate;
107    DWORD retval = TIME_ZONE_ID_INVALID;
108    LONGLONG llTime = 0;
109    SYSTEMTIME SysTime;
110    FILETIME ftTemp;
111
112    if (pTZinfo->DaylightDate.wMonth != 0)
113    {
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)
119       {
120          SetLastError(ERROR_INVALID_PARAMETER);
121          return TIME_ZONE_ID_INVALID;
122       }
123
124       if (!islocal)
125       {
126          FILETIME2LL( lpFileTime, llTime );
127          llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias ) * (LONGLONG)600000000;
128          LL2FILETIME( llTime, &ftTemp)
129          lpFileTime = &ftTemp;
130       }
131
132       FileTimeToSystemTime(lpFileTime, &SysTime);
133
134       ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
135       if (ret == -2)
136          return TIME_ZONE_ID_INVALID;
137
138       beforeStandardDate = ret < 0;
139
140       if (!islocal)
141       {
142          llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias ) * (LONGLONG)600000000;
143          LL2FILETIME( llTime, &ftTemp)
144          FileTimeToSystemTime(lpFileTime, &SysTime);
145       }
146
147       ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
148       if (ret == -2)
149        return TIME_ZONE_ID_INVALID;
150
151       afterDaylightDate = ret >= 0;
152
153       retval = TIME_ZONE_ID_STANDARD;
154       if( pTZinfo->DaylightDate.wMonth <  pTZinfo->StandardDate.wMonth )
155       {
156          if( beforeStandardDate && afterDaylightDate )
157              retval = TIME_ZONE_ID_DAYLIGHT;
158       }
159       else if( beforeStandardDate || afterDaylightDate )
160          retval = TIME_ZONE_ID_DAYLIGHT;
161    }
162    else
163       retval = TIME_ZONE_ID_UNKNOWN;
164    return retval;
165 }
166
167 static bool TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION *pTZinfo, FILETIME *lpFileTime, bool islocal, LONG *pBias)
168 {
169    LONG bias = pTZinfo->Bias;
170    DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
171
172    if( tzid == TIME_ZONE_ID_INVALID)
173       return false;
174    if (tzid == TIME_ZONE_ID_DAYLIGHT)
175       bias += pTZinfo->DaylightBias;
176    else if (tzid == TIME_ZONE_ID_STANDARD)
177       bias += pTZinfo->StandardBias;
178    *pBias = bias;
179    return true;
180 }
181
182 static bool _TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation, LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime)
183 {
184    FILETIME ft;
185    LONG lBias;
186    LONGLONG t;
187    TIME_ZONE_INFORMATION tzinfo;
188
189    if(lpTimeZoneInformation)
190    {
191       memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
192    }
193    else
194    {
195       if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
196          return false;
197    }
198
199    if (!SystemTimeToFileTime(lpLocalTime, &ft))
200       return false;
201    FILETIME2LL( &ft, t)
202    if (!TIME_GetTimezoneBias(&tzinfo, &ft, true, &lBias))
203       return false;
204
205    t += (LONGLONG)lBias * 600000000;
206    LL2FILETIME( t, &ft)
207    return (bool)FileTimeToSystemTime(&ft, lpUniversalTime);
208 }
209 #endif
210
211 import "System"
212
213 public class Time : double
214 {
215    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
216    {
217       Time time = this;
218       int value;
219       char temp[256];
220       tempString[0] = 0;
221       value = (int)(time / (60 * 60 * 24));
222       if(value)
223       {
224
225          sprintf(temp, "%d:", value);
226          strcat(tempString, temp);
227          time -= value * 60 * 60 * 24;
228       }
229       value = (int)(time / (60 * 60));
230       if(value)
231       {
232          sprintf(temp, "%d:", value);
233          strcat(tempString, temp);
234          time -= value * 60 * 60;
235       }
236
237       value = (int)(time / 60);
238       sprintf(temp, "%d:", value);
239       strcat(tempString, temp);
240       time -= value * 60;
241
242       value = (int)(time);
243       sprintf(temp, "%02d", value);
244       strcat(tempString, temp);
245       time -= value;
246
247       /*if(time > 0.00001)
248       {
249          sprintf(temp, "%f" time);
250          strcat(tempString, temp+1);
251       }*/
252       return tempString;
253    }
254 }
255
256 public class Seconds : Time { public property Time {} };
257
258 #if !defined(__WIN32__)
259 static time_t MakeTimeT(SecSince1970 t)
260 {
261    struct tm tm;
262    time_t result;
263    DateTime dt = t;
264    tm.tm_year = dt.year - 1900;
265    tm.tm_mon = dt.month;
266    tm.tm_mday = dt.day;
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);
273    return result;
274 }
275
276 static time_t MakeTimeTfromDT(DateTime dt)
277 {
278    struct tm tm;
279    time_t result;
280    tm.tm_year = dt.year - 1900;
281    tm.tm_mon = dt.month;
282    tm.tm_mday = dt.day;
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);
289    return result;
290 }
291
292 #endif
293
294 public class SecSince1970 : int64
295 {
296    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
297    {
298       return ((DateTime)this).OnGetString(tempString, fieldData, needClass);
299    }
300
301    bool OnGetDataFromString(const char * string)
302    {
303       DateTime dt { };
304       if(dt.OnGetDataFromString(string))
305       {
306          this = dt;
307          return true;
308       }
309       return false;
310    }
311
312    // Is this required?
313    int OnCompare(SecSince1970 data2)
314    {
315       int result = 0;
316       if(this && data2)
317       {
318          if(this > data2)
319             result = 1;
320          else if(this < data2)
321             result = -1;
322       }
323       return result;
324    }
325 public:
326    property SecSince1970 global
327    {
328       get
329       {
330       #if defined(__WIN32__)
331          SYSTEMTIME localTime, systemTime;
332          //FILETIME fileTime, localFileTime;
333          DateTime input, global;
334
335          input = this;
336
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;
344
345          /*
346          SystemTimeToFileTime(&localTime, &fileTime);
347          LocalFileTimeToFileTime(&fileTime, &localFileTime);
348          FileTimeToSystemTime(&localFileTime, &systemTime);
349          */
350
351          _TzSpecificLocalTimeToSystemTime(null, &localTime, &systemTime);
352
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;
359
360          return global;
361       #else
362          struct tm tm;
363          DateTime global;
364          time_t t = MakeTimeT(this);
365          // gmtime_r((time_t *)&this, &tm);
366          gmtime_r(&t, &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;
375          return global;
376       #endif
377       }
378    };
379    property SecSince1970 local
380    {
381       get
382       {
383 #if defined(__WIN32__)
384          SYSTEMTIME systemTime, localTime;
385          DateTime utc, local;
386
387          utc = this;
388
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;
396
397          SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
398
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;
406
407          local.FixDayOfYear();
408          return local;
409 #else
410          DateTime local;
411          struct tm tm;
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;
423          return local;
424 #endif
425       }
426    };
427 };
428
429 public class TimeStamp32 : uint32
430 {
431 public:
432    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
433    {
434       return ((DateTime)(TimeStamp)this).OnGetString(tempString, fieldData, needClass);
435    }
436
437    // Is this required?
438    int OnCompare(TimeStamp32 data2)
439    {
440       int result = 0;
441       if(this && data2)
442       {
443          if(this > data2)
444             result = 1;
445          else if(this < data2)
446             result = -1;
447       }
448       return result;
449    }
450 };
451
452 public class TimeStamp : SecSince1970
453 {
454    public property SecSince1970 {};
455 };
456 public enum DayOfTheWeek { sunday, monday, tuesday, wednesday, thursday, friday, saturday };
457 public struct DateTime
458 {
459    int year;
460    Month month;
461    int day, hour, minute, second;
462    DayOfTheWeek dayOfTheWeek;
463    int dayInTheYear;
464
465    bool GetLocalTime()
466    {
467    #if defined(__WIN32__)
468       SYSTEMTIME systemTime;
469       ::GetLocalTime(&systemTime);
470
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;
477
478       FixDayOfYear();
479       {
480          Date date { year, month, day };
481          dayOfTheWeek = date.dayOfTheWeek;
482       }
483    #else
484       struct tm tm;
485       time_t currentTime = time(null);
486       localtime_r(&currentTime, &tm);
487
488       year = tm.tm_year + 1900;
489       month = (Month)tm.tm_mon;
490       day = tm.tm_mday;
491       hour = tm.tm_hour;
492       minute = tm.tm_min;
493       second = tm.tm_sec;
494       dayInTheYear = tm.tm_yday;
495       dayOfTheWeek = (DayOfTheWeek)tm.tm_wday;
496    #endif
497
498       return true;
499    }
500
501    bool FixDayOfYear()
502    {
503       dayInTheYear = daysInAYearBeforeMonth[ISLEAP(year)][month] + day - 1;
504       return true;
505    }
506
507    property DateTime global
508    {
509       set { this = value.local; }
510       get
511       {
512       #if defined(__WIN32__)
513          SYSTEMTIME localTime, systemTime;
514          FILETIME fileTime, localFileTime;
515
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;
523
524          SystemTimeToFileTime(&localTime, &fileTime);
525          LocalFileTimeToFileTime(&fileTime, &localFileTime);
526          FileTimeToSystemTime(&localFileTime, &systemTime);
527
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;
534       #else
535          struct tm tm;
536          //time_t t = (time_t)(SecSince1970)this;
537          time_t t = MakeTimeTfromDT(this);
538          gmtime_r(&t, &tm);
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;
547       #endif
548       }
549    };
550    property DateTime local
551    {
552       set { this = value.global; }
553       get
554       {
555       #if defined(__WIN32__)
556          SYSTEMTIME systemTime, localTime;
557
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;
565
566          SystemTimeToTzSpecificLocalTime(null, &systemTime, &localTime);
567
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;
575
576          value.FixDayOfYear();
577       #else
578          struct tm tm;
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;
590       #endif
591       }
592    };
593    property SecSince1970
594    {
595       set
596       {
597          int64 days, y;
598          int rem;
599
600          days = value / SECS_PER_DAY;
601          rem = (int)(value % SECS_PER_DAY);
602
603          while(rem < 0)             { rem += SECS_PER_DAY; days--; }
604          while(rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; days++; }
605
606          hour = rem / SECS_PER_HOUR;
607
608          rem %= SECS_PER_HOUR;
609          minute = rem / 60;
610          second = rem % 60;
611
612          dayOfTheWeek = (EPOCH_WEEKDAY + days) % 7;
613          if(dayOfTheWeek < 0)
614             dayOfTheWeek += 7;
615
616          y = EPOCH_YEAR;
617          while(days < 0 || days >= daysInAYearBeforeMonth[ISLEAP(y)][12])
618          {
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));
621             y = yg;
622          }
623          year = (int)y;
624          {
625             const int * daysBeforeMonth = daysInAYearBeforeMonth[ISLEAP(y)];
626             dayInTheYear = (int)days;
627             for(y = 11; days < daysBeforeMonth[y]; y--);
628             days -= daysBeforeMonth[y];
629             month = (Month)y;
630             day = (int)(days + 1);
631          }
632       }
633
634       get
635       {
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;
641          // if(year >= 1970)
642          {
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);
647             int a400 = a100 / 4;
648             int b400 = b100 / 4;
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;
654          }
655          return 0;
656       }
657    };
658    property Date
659    {
660       set
661       {
662          year = value.year;
663          month = value.month;
664          day = value.day;
665          hour = 0;
666          minute = 0;
667          second = 0;
668       }
669       get { value = Date { year, month, day }; }
670    }
671
672    const char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
673    {
674       static const char ampm[2][3] = { "AM", "PM" };
675       int hour = this.hour;
676       bool pm = false;
677       if(hour > 12) { hour -= 12; pm = true; }
678       else if(hour == 12) pm = true;
679       if(!hour) hour = 12;
680
681       if(!year && !day && !month && !this.hour && !minute && !second)
682          stringOutput[0] = 0;
683       else
684          sprintf(stringOutput, "%s %s %2d %2d:%02d:%02d %s %04d",
685             shortDaysNames[dayOfTheWeek], shortMonthsNames[month], day, hour, minute, second, ampm[pm], year);
686
687       return stringOutput;
688    }
689
690    bool OnGetDataFromString(const char * string)
691    {
692       char * s = CopyString(string);
693       char * tokens[20];
694       int count = TokenizeWith(s, 20, tokens, " ", false);
695       int c;
696       bool foundDayOfTheWeek = false;
697       bool foundDate = false;
698       DayOfTheWeek dayOfTheWeek = 0;
699       int day = 0;
700       int minute = 0;
701       int second = 0;
702       int hour = 0;
703       int year = 0;
704
705       for(c = 0; c < count; c++)
706       {
707          int i;
708          for(i = 0; i<7; i++)
709             if(!strcmpi(tokens[c], shortDaysNames[i]) || !strcmpi(tokens[c], longDaysNames[i]) ||
710                !strcmpi(tokens[c], enShortDaysNames[i]) || !strcmpi(tokens[c], enLongDaysNames[i]))
711                break;
712          if(i < 7) { dayOfTheWeek = (DayOfTheWeek)i; foundDayOfTheWeek = true; continue; }
713
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]))
717                break;
718          if(i < 12) { month = (Month)i; continue; }
719
720          if(strchr(tokens[c], ':'))
721          {
722             char * subTokens[20];
723             int sCount = TokenizeWith(tokens[c], 20, subTokens, " :", false);
724             int t;
725             bool pm = false, am = false;
726             for(t = 0; t<sCount; t++)
727             {
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]);
733             }
734
735             if(c < count - 1)
736             {
737                if(!strcmpi(tokens[c+1], "am")) am = true;
738                else if(!strcmpi(tokens[c+1], "pm")) pm = true;
739             }
740
741             if(am && hour == 12) hour = 0;
742             else if(pm && hour < 12) hour += 12;
743
744             continue;
745          }
746
747          if(!foundDate)
748          {
749             if(strchr(tokens[c], '/') || strchr(tokens[c], '-'))
750             {
751                Date date;
752                if(date.OnGetDataFromString(tokens[c]))
753                {
754                   day = date.day;
755                   year = date.year;
756                   month = date.month;
757                }
758                foundDate = true;
759             }
760             else
761             {
762                i = atoi(tokens[c]);
763                if(i > 31)
764                {
765                   year = i;
766                   continue;
767                }
768                else if(i)
769                   day = i;
770             }
771          }
772       }
773       if(day)
774       {
775          Date date { year, month, day };
776          this.dayOfTheWeek = date.dayOfTheWeek;
777          this.day = day;
778          this.minute = minute;
779          this.second = second;
780          this.hour = hour;
781          this.year = year;
782       }
783       else if(foundDayOfTheWeek)
784       {
785          SecSince1970 weWant;
786          GetLocalTime();
787          if(dayOfTheWeek <= this.dayOfTheWeek) dayOfTheWeek += 7;
788          weWant = (SecSince1970)this + (int)(dayOfTheWeek - this.dayOfTheWeek) * 24 * 60 * 60;
789          this = (DateTime)weWant;
790       }
791       else if(!strcmpi(s, "today") || !strcmpi(s, $"today") ||
792               !strcmpi(s, "now") || !strcmpi(s, $"now"))
793          GetLocalTime();
794       else if(!strcmpi(s, "tomorrow") || !strcmpi(s, $"tomorrow"))
795       {
796          SecSince1970 weWant;
797          GetLocalTime();
798          weWant = (SecSince1970)this + 24 * 60 * 60;
799          this = (DateTime)weWant;
800       }
801       else if(!strcmpi(s, "yesterday") || !strcmpi(s, $"yesterday"))
802       {
803          SecSince1970 weWant;
804          GetLocalTime();
805          weWant = (SecSince1970)this - 24 * 60 * 60;
806          this = (DateTime)weWant;
807       }
808       else if(!s[0])
809       {
810          this = { };
811          delete s;
812          return true;
813       }
814       delete s;
815       return this.day != 0;
816    }
817 };
818
819 public Time GetTime(void)
820 {
821 #if defined(__WIN32__)
822    return timeGetTime() / 1000.0;
823 #elif defined(__unix__) || defined(__APPLE__)
824    struct timeval tp;
825    struct timezone tzp;
826    static int secbase = 0;
827
828    gettimeofday(&tp, &tzp);
829
830    if(!secbase)
831    {
832       secbase = (int)tp.tv_sec;
833       return tp.tv_usec / 1000000.0;
834    }
835    return (tp.tv_sec - secbase) + tp.tv_usec / 1000000.0;
836 #endif
837 }
838
839 public void Sleep(Seconds seconds)
840 {
841 #if defined(__WIN32__)
842    ::Sleep((uint)(seconds * 1000));
843 #else
844    if(!seconds)
845       sched_yield();
846    else
847    {
848       // usleep((uint)(seconds * 1000000));
849       struct timeval tv = { (int)seconds, (int)((seconds - (int)seconds) * 1000000) };
850       select(0,null,null,null, &tv);
851    }
852 #endif
853 }
854
855 public void RandomSeed(uint seed)
856 {
857 #if defined(__linux__) || defined(__DJGPP__)
858    srandom(seed);
859 #else
860    srand(seed);
861 #endif
862 }
863
864 public int GetRandom(int lo, int hi)
865 {
866    if(hi >= lo)
867    {
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));
871 #else
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));
874 #endif
875    }
876    else
877       return lo;
878 }