1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 namespace System
  7 {
  8     public class TimePoint
  9     {
 10         public nothrow TimePoint() : nanosecs(0)
 11         {
 12         }
 13         public explicit nothrow TimePoint(long nanosecs_) : nanosecs(nanosecs_)
 14         {
 15         }
 16         public inline nothrow long Rep() const
 17         {
 18             return nanosecs;
 19         }
 20         private long nanosecs;
 21     }
 22 
 23     public class Duration
 24     {
 25         public nothrow Duration() : nanosecs(0)
 26         {
 27         }
 28         public explicit nothrow Duration(long nanosecs_) : nanosecs(nanosecs_)
 29         {
 30         }
 31         public nothrow long Hours() const
 32         {
 33             return nanosecs / (3600 * long(1000000000));
 34         }
 35         public nothrow long Minutes() const
 36         {
 37             return nanosecs / (60 * long(1000000000));
 38         }
 39         public nothrow long Seconds() const
 40         {
 41             return nanosecs / long(1000000000);
 42         }
 43         public nothrow long Milliseconds() const
 44         {
 45             return nanosecs / long(1000000);
 46         }
 47         public nothrow long Microseconds() const
 48         {
 49             return nanosecs / long(1000);
 50         }
 51         public nothrow long Nanoseconds() const
 52         {
 53             return nanosecs;
 54         }
 55         public static nothrow Duration FromHours(long hours)
 56         {
 57             return Duration(3600 * long(1000000000) * hours);
 58         }
 59         public static nothrow Duration FromMinutes(long minutes)
 60         {
 61             return Duration(60 * long(1000000000) * minutes);
 62         }
 63         public static nothrow Duration FromSeconds(long seconds)
 64         {
 65             return Duration(long(1000000000) * seconds);
 66         }
 67         public static nothrow Duration FromMilliseconds(long milliseconds)
 68         {
 69             return Duration(long(1000000) * milliseconds);
 70         }
 71         public static nothrow Duration FromMicroseconds(long microseconds)
 72         {
 73             return Duration(long(1000) * microseconds);
 74         }
 75         public static nothrow Duration FromNanoseconds(long nanoseconds)
 76         {
 77             return Duration(nanoseconds);
 78         }
 79         public inline nothrow long Rep() const
 80         {
 81             return nanosecs;
 82         }
 83         private long nanosecs;
 84     }
 85 
 86     public inline nothrow bool operator==(const Duration& leftconst Duration& right)
 87     {
 88         return left.Rep() == right.Rep();
 89     }
 90 
 91     public inline nothrow bool operator<(const Duration& leftconst Duration& right)
 92     {
 93         return left.Rep() < right.Rep();
 94     }
 95 
 96     public inline nothrow bool operator==(const TimePoint& leftconst TimePoint& right)
 97     {
 98         return left.Rep() == right.Rep();
 99     }
100 
101     public inline nothrow bool operator<(const TimePoint& leftconst TimePoint& right)
102     {
103         return left.Rep() < right.Rep();
104     }
105 
106     public inline nothrow Duration operator+(const Duration& leftconst Duration& right)
107     {
108         return Duration(left.Rep() + right.Rep());
109     }
110 
111     public inline nothrow Duration operator-(const Duration& leftconst Duration& right)
112     {
113         return Duration(left.Rep() - right.Rep());
114     }
115 
116     public inline nothrow Duration operator*(const Duration& leftconst Duration& right)
117     {
118         return Duration(left.Rep() * right.Rep());
119     }
120 
121     public inline nothrow Duration operator/(const Duration& leftconst Duration& right)
122     {
123         return Duration(left.Rep() / right.Rep());
124     }
125 
126     public inline nothrow Duration operator%(const Duration& leftconst Duration& right)
127     {
128         return left.Rep() % right.Rep();
129     }
130 
131     public inline nothrow Duration operator-(const TimePoint& leftconst TimePoint& right)
132     {
133         long diff = left.Rep() - right.Rep();
134         return Duration(diff);
135     }
136 
137     public inline nothrow TimePoint operator+(const TimePoint& tpconst Duration& d)
138     {
139         return TimePoint(tp.Rep() + d.Rep());
140     }
141 
142     public inline nothrow TimePoint operator+(const Duration& dconst TimePoint& tp)
143     {
144         return TimePoint(tp.Rep() + d.Rep());
145     }
146 
147     public inline nothrow TimePoint operator-(const TimePoint& tpconst Duration& d)
148     {
149         return TimePoint(tp.Rep() - d.Rep());
150     }
151 
152     public nothrow TimePoint Now()
153     {
154         return TimePoint(RtNow());
155     }
156 
157     public nothrow void Sleep(const Duration& duration)
158     {
159         RtSleep(duration.Rep());
160     }
161 
162     public nothrow string DurationStr(const Duration& duration)
163     {
164         string s;
165         long hh = duration.Hours() % 24;
166         s.Append(cast<char>(cast<byte>('0') + cast<byte>(hh / 10 % 10)));
167         s.Append(cast<char>(cast<byte>('0') + cast<byte>(hh % 10)));
168         s.Append(':');
169         long mm = duration.Minutes() % 60;
170         s.Append(cast<char>(cast<byte>('0') + cast<byte>(mm / 10 % 10)));
171         s.Append(cast<char>(cast<byte>('0') + cast<byte>(mm % 10)));
172         s.Append(':');
173         long ss = duration.Seconds() % 60;
174         s.Append(cast<char>(cast<byte>('0') + cast<byte>(ss / 10 % 10)));
175         s.Append(cast<char>(cast<byte>('0') + cast<byte>(ss % 10)));
176         s.Append('.');
177         long ms = duration.Milliseconds() % 1000;
178         s.Append(cast<char>(cast<byte>('0') + cast<byte>(ms / 100 % 10)));
179         s.Append(cast<char>(cast<byte>('0') + cast<byte>(ms / 10 % 10)));
180         s.Append(cast<char>(cast<byte>('0') + cast<byte>(ms % 10)));
181         s.Append('.');
182         long us = duration.Microseconds() % 1000;
183         s.Append(cast<char>(cast<byte>('0') + cast<byte>(us / 100 % 10)));
184         s.Append(cast<char>(cast<byte>('0') + cast<byte>(us / 10 % 10)));
185         s.Append(cast<char>(cast<byte>('0') + cast<byte>(us % 10)));
186         return s;
187     }
188 
189     public enum Month : sbyte
190     {
191          january = 1februarymarchaprilmayjunejulyaugustseptemberoctobernovemberdecember
192     }
193 
194     public const int[] monthDays =  ;
195     
196     public nothrow int GetMonthDays(Month monthint year)
197     {
198         if (month == Month.february && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
199         {
200             return 29;
201         }
202         return monthDays[cast<sbyte>(month)];
203     }
204 
205     public class Date
206     {
207         public nothrow Date() : year(0)month(Month.january)day(1)
208         {
209         }
210         public nothrow Date(short year_Month month_sbyte day_) : year(year_)month(month_)day(day_)
211         {
212         }
213         public inline nothrow short Year() const
214         {
215             return year;
216         }
217         public inline nothrow Month GetMonth() const
218         {
219             return month;
220         }
221         public inline nothrow sbyte Day() const
222         {
223             return day;
224         }
225         public nothrow Date AddDays(int n)
226         {
227             if (n > 0)
228             {
229                 int d = day + n;
230                 Month m = month;
231                 short y = year;
232                 int md = GetMonthDays(my);
233                 while (d > md)
234                 {
235                     d = d - md;
236                     if (m == Month.december)
237                     {
238                         m = Month.january;
239                         ++y;
240                     }
241                     else
242                     {
243                         m = cast<Month>(cast<sbyte>(m) + 1);
244                     }
245                     md = GetMonthDays(my);
246                 }
247                 return Date(ymcast<sbyte>(d));
248             }
249             else if (n < 0)
250             {
251                 int d = day + n;
252                 Month m = month;
253                 short y = year;
254                 while (d < 1)
255                 {
256                     if (m == Month.january)
257                     {
258                         m = Month.december;
259                         --y;
260                     }
261                     else
262                     {
263                         m = cast<Month>(cast<sbyte>(m) - 1);
264                     }
265                     d = d + GetMonthDays(my);
266                 }
267                 return Date(ymcast<sbyte>(d));
268             }
269             else
270             {
271                 return *this;
272             }
273         }
274         public nothrow Date AddMonths(int n)
275         {
276             if (n > 0)
277             {
278                 int m = cast<int>(cast<sbyte>(month)) + n;
279                 short y = year;
280                 int d = day;
281                 while (m > 12)
282                 {
283                     m = m - 12;
284                     ++y;
285                 }
286                 Month mnth = cast<Month>(cast<sbyte>(m));
287                 int md = GetMonthDays(mnthy);
288                 if (d > md)
289                 {
290                     d = md;
291                 }
292                 return Date(ymnthcast<sbyte>(d));
293             }
294             else if (n < 0)
295             {
296                 int m = cast<int>(cast<sbyte>(month)) + n;
297                 short y = year;
298                 int d = day;
299                 while (m < 1)
300                 {
301                     m = m + 12;
302                     --y;
303                 }
304                 Month mnth = cast<Month>(cast<sbyte>(m));
305                 int md = GetMonthDays(mnthy);
306                 if (d > md)
307                 {
308                     d = md;
309                 }
310                 return Date(ymnthcast<sbyte>(d));
311             }
312             else
313             {
314                 return *this;
315             }
316         }
317         public nothrow Date AddYears(short n)
318         {
319             short y = year + n;
320             int d = day;
321             int md = GetMonthDays(monthy);
322             if (d > md)
323             {
324                 d = md;
325             }
326             return Date(ymonthcast<sbyte>(d));
327         }
328         public nothrow string ToString() const
329         {
330             return this->ToString(false);
331         }
332         public nothrow string ToString(bool omitDashes) const
333         {
334             string date;
335             date.Append(cast<char>(cast<short>('0') + ((year / 1000) % 10)));
336             date.Append(cast<char>(cast<short>('0') + ((year / 100) % 10)));
337             date.Append(cast<char>(cast<short>('0') + ((year / 10) % 10)));
338             date.Append(cast<char>(cast<short>('0') + (year % 10)));
339             if (!omitDashes)
340             {
341                 date.Append('-');
342             }
343             date.Append(cast<char>(cast<sbyte>('0') + ((cast<sbyte>(month) / 10) % 10)));
344             date.Append(cast<char>(cast<sbyte>('0') + (cast<sbyte>(month) % 10)));
345             if (!omitDashes)
346             {
347                 date.Append('-');
348             }
349             date.Append(cast<char>(cast<sbyte>('0') + ((day / 10) % 10)));
350             date.Append(cast<char>(cast<sbyte>('0') + (day % 10)));
351             return date;
352         }
353         private short year;
354         private Month month;
355         private sbyte day;
356     }
357 
358     public nothrow Date GetCurrentDate()
359     {
360         short y;
361         sbyte m;
362         sbyte d;
363         RtGetCurrentDate(&y&m&d);
364         return Date(ycast<Month>(m)d);
365     }
366 
367     public nothrow bool operator==(const Date& leftconst Date& right)
368     {
369         return left.Year() == right.Year() && left.GetMonth() == right.GetMonth() && left.Day() == right.Day();
370     }
371 
372     public nothrow bool operator<(const Date& leftconst Date& right)
373     {
374         if (left.Year() < right.Year()) return true;
375         if (left.Year() > right.Year()) return false;
376         if (left.GetMonth() < right.GetMonth()) return true;
377         if (left.GetMonth() > right.GetMonth()) return false;
378         return left.Day() < right.Day();
379     }
380 
381     public class DateTime
382     {
383         public nothrow DateTime() : date()secs(0)
384         {
385         }
386         public nothrow DateTime(Date date_) : date(date_)secs(0)
387         {
388         }
389         public nothrow DateTime(Date date_int secs_) : date(date_)secs(secs_)
390         {
391         }
392         public inline nothrow Date GetDate() const
393         {
394             return date;
395         }
396         public inline nothrow int Hours() const
397         {
398             return secs / 3600;
399         }
400         public inline nothrow int Minutes() const
401         {
402             return secs / 60;
403         }
404         public inline nothrow int Seconds() const
405         {
406             return secs;
407         }
408         public nothrow string TimeString() const
409         {
410             string timeString;
411             int hh = Hours() % 24;
412             int mm = Minutes() % 60;
413             int ss = Seconds() % 60;
414             timeString.Append(cast<char>(cast<int>('0') + ((hh / 10) % 10)));
415             timeString.Append(cast<char>(cast<int>('0') + (hh % 10)));
416             timeString.Append(':');
417             timeString.Append(cast<char>(cast<int>('0') + ((mm / 10) % 10)));
418             timeString.Append(cast<char>(cast<int>('0') + (mm % 10)));
419             timeString.Append(':');
420             timeString.Append(cast<char>(cast<int>('0') + ((ss / 10) % 10)));
421             timeString.Append(cast<char>(cast<int>('0') + (ss % 10)));
422             return timeString;
423         }
424         public nothrow string ToString()
425         {
426             return this->ToString(falsefalsefalsefalse);
427         }
428         public nothrow string ToString(bool omitDashesbool omitColonsbool omitMinsbool omitSecs)
429         {
430             string dateTime;
431             dateTime.Append(date.ToString(omitDashes));
432             dateTime.Append('T');
433             int hh = Hours() % 24;
434             int mm = Minutes() % 60;
435             int ss = Seconds() % 60;
436             dateTime.Append(cast<char>(cast<int>('0') + ((hh / 10) % 10)));
437             dateTime.Append(cast<char>(cast<int>('0') + (hh % 10)));
438             if (!omitMins)
439             {
440                 if (!omitColons)
441                 {
442                     dateTime.Append(':');
443                 }
444                 dateTime.Append(cast<char>(cast<int>('0') + ((mm / 10) % 10)));
445                 dateTime.Append(cast<char>(cast<int>('0') + (mm % 10)));
446                 if (!omitSecs)
447                 {
448                     if (!omitColons)
449                     {
450                         dateTime.Append(':');
451                     }
452                     dateTime.Append(cast<char>(cast<int>('0') + ((ss / 10) % 10)));
453                     dateTime.Append(cast<char>(cast<int>('0') + (ss % 10)));
454                 }
455             }
456             return dateTime;
457         }
458         private Date date;
459         private int secs;
460     }
461 
462     public const int secsInDay = cast<int>(24) * 3600;
463 
464     public nothrow DateTime GetCurrentDateTime()
465     {
466         short y;
467         sbyte m;
468         sbyte d;
469         int secs;
470         RtGetCurrentDateTime(&y&m&d&secs);
471         return DateTime(Date(ycast<Month>(m)d)secs);
472     }
473 
474     public nothrow bool operator==(const DateTime& leftconst DateTime& right)
475     {
476         return left.GetDate() == right.GetDate() && left.Seconds() == right.Seconds();
477     }
478 
479     public nothrow bool operator<(const DateTime& leftconst DateTime& right)
480     {
481         if (left.GetDate() < right.GetDate()) return true;
482         if (left.GetDate() > right.GetDate()) return false;
483         return left.Seconds() < right.Seconds();
484     }
485 
486     public class Timestamp
487     {
488         public nothrow Timestamp() : dateTime()nanosecs()
489         {
490         }
491         public nothrow Timestamp(const DateTime& dateTime_int nanosecs_) : dateTime(dateTime_)nanosecs(nanosecs_)
492         {
493         }
494         public nothrow const DateTime& GetDateTime() const
495         {
496             return dateTime;
497         }
498         public nothrow int GetNanoseconds() const
499         {
500             return nanosecs;
501         }
502         public nothrow string ToString() const
503         {
504             string s(dateTime.ToString());
505             s.Append('.').Append(Format(ToString(nanosecs)9FormatWidth.exactFormatJustify.right'0'));
506             return s;
507         }
508         private DateTime dateTime;
509         private int nanosecs;
510     }
511 
512     public nothrow bool operator==(const Timestamp& leftconst Timestamp& right)
513     {
514         return left.GetDateTime() == right.GetDateTime() && left.GetNanoseconds() == right.GetNanoseconds();
515     }
516 
517     public nothrow bool operator<(const Timestamp& leftconst Timestamp& right)
518     {
519         if (left.GetDateTime() < right.GetDateTime()) return true;
520         if (left.GetDateTime() > right.GetDateTime()) return false;
521         return left.GetNanoseconds() < right.GetNanoseconds();
522     }
523 
524     public class TimestampProvider
525     {
526         static nothrow TimestampProvider() : instance(new TimestampProvider())
527         {
528         }
529         public static nothrow TimestampProvider& Instance()
530         {
531             return *instance;
532         }
533         private nothrow TimestampProvider()
534         {
535             Reset();
536         }
537         public nothrow Timestamp GetCurrentTimestamp()
538         {
539             if (GetCurrentDate() != startDateTime.GetDate())
540             {
541                 Reset();
542             }
543             Duration elapsed = Now() - startTimePoint;
544             long elapsedNanosecs = elapsed.Nanoseconds();
545             int elapsedSecs = cast<int>(elapsedNanosecs / cast<long>(1000000000));
546             int nanosecs = cast<int>(elapsedNanosecs % cast<long>(1000000000));
547             Date date = startDateTime.GetDate();
548             int secs = startDateTime.Seconds() + elapsedSecs;
549             if (secs >= secsInDay)
550             {
551                 date = date.AddDays(1);
552                 secs = secs - secsInDay;
553             }
554             Timestamp timestamp(DateTime(datesecs)nanosecs);
555             return timestamp;
556         }
557         private nothrow void Reset()
558         {
559             startDateTime = GetCurrentDateTime();
560             startTimePoint = Now();
561         }
562         private static UniquePtr<TimestampProvider> instance;
563         private DateTime startDateTime;
564         private TimePoint startTimePoint;
565     }
566 
567     public nothrow Timestamp GetCurrentTimestamp()
568     {
569         return TimestampProvider.Instance().GetCurrentTimestamp();
570     }
571 }