(* DateTime, solyga@gmx.de, 2025-03-02 *)
DEFINITION MODULE DT;

TYPE
  TDate = LONGINT;   (* days since 0000-01-01 *)
  TTime = LONGCARD;  (* milliseconds since midnight *)

  TWeekDay = ( wdMon, wdTue, wdWed, wdThu, wdFri, wdSat, wdSun );  (* following ISO 8601 *)

CONST
  refDate  = 0;
  refYear  = 0;
  refMonth = 1;
  refDay   = 1;

  refDateWeekDay = wdSat;    (* 1990-01-01 was a Monday *)

CONST
  perY = 400;                (* calendar period in years *)
  period = perY * 365 + 97;  (* calendar period in days = 146097 *)

  count = 5000;  (* expressible periods, MAX(TDate) DIV 366 DIV 2 DIV perY = 7334 *)

  maxDate = count * period - 1;
  minDate = - ( count * period );

  maxYear = count * perY - 1;  (* ( MAX(TDate) DIV 366 ) DIV 2 = 2933720 *)
  minYear = - ( count * perY );

  minMonth = 1;
  maxMonth = 12;

  minDay = 1;
  maxDay = 31;

TYPE
  TYear  = [ minYear  .. maxYear  ];
  TMonth = [ minMonth .. maxMonth ];
  TDay   = [ minDay   .. maxDay   ];

  THour   = [ 0 ..  23 ];
  TMinute = [ 0 ..  59 ];
  TSecond = [ 0 ..  59 ];
  TFrag   = [ 0 .. 999 ];

CONST
  msPerDay = 24 * 60 * 60 * 1000;
  maxTime = msPerDay - 1;

TYPE
  TCalWeek = [ 1 .. 53 ];


PROCEDURE IsValidDate( y: LONGINT; m, d: CARDINAL ): BOOLEAN;
PROCEDURE PackDate( y: LONGINT; m, d: CARDINAL ): TDate;               (* invalid dates map to refDate *)
PROCEDURE UnpackDate( x: TDate; VAR y: LONGINT; VAR m, d: CARDINAL );  (* invalid dates map to refYear, refMonth, refDay *)

PROCEDURE WeekDay( d: TDate ): TWeekDay;
PROCEDURE CalWeek( d: TDate ): TCalWeek;

PROCEDURE IsValidTime( h, m, s, f: CARDINAL ): BOOLEAN;
PROCEDURE PackTime( h, m, s, f: CARDINAL ): TTime;          (* invalid times map to 0 *)
PROCEDURE UnpackTime( t: TTime; VAR h, m, s, f: CARDINAL ); (* all t map to valid times, all t > maxTime treated as beeing 0 *)

TYPE
  TDateTime = LONGREAL;  (* days (incl. fractions) since 0000-01-01 *)

PROCEDURE Combine( d: TDate; t: TTime ): TDateTime;
PROCEDURE Split( x: TDateTime; VAR d: TDate; VAR t: TTime );

END DT.
