Contributor: BRIAN STARK              


(***************************************************************************)
(* UNIX DATE Version 1.01                                                  *)
(* This unit provides access to UNIX date related functions and procedures *)
(* A UNIX date is the number of seconds from January 1, 1970. This unit    *)
(* may be freely used. If you modify the source code, please do not        *)
(* distribute your enhancements.                                           *)
(* (C) 1991-1993 by Brian Stark.                                           *)
(* This is a programming release from Digital Illusions                    *)
(* FidoNet 1:289/27.2 + Columbia, MO - USA                                 *)
(* Revision History                                                        *)
(* ----------------------------------------------------------------------- *)
(* 06-13-1993 1.02 | Minor code cleanup                                    *)
(* 05-23-1993 1.01 | Added a few more routines for use with ViSiON BBS     *)
(* ??-??-1991 1.00 | First release                                         *)
(* ----------------------------------------------------------------------- *)
(***************************************************************************)

INTERFACE

Uses
   DOS;

Function  GetTimeZone : ShortInt;
  {Returns the value from the enviroment variable "TZ". If not found, UTC is
   assumed, and a value of zero is returned}
Function  IsLeapYear(Source : Word) : Boolean;
  {Determines if the year is a leap year or not}
Function  Norm2Unix(Y, M, D, H, Min, S : Word) : LongInt;
  {Convert a normal date to its UNIX date. If environment variable "TZ" is
   defined, then the input parameters are assumed to be in **LOCAL TIME**}
Procedure Unix2Norm(Date : LongInt; Var Y, M, D, H, Min, S : Word);
  {Convert a UNIX date to its normal date counterpart. If the environment
   variable "TZ" is defined, then the output will be in **LOCAL TIME**}

Function  TodayInUnix : LongInt;
  {Gets today's date, and calls Norm2Unix}
{
 Following returns a string and requires the TechnoJock totSTR unit.
Function  Unix2Str(N : LongInt) : String;
}
Const
  DaysPerMonth :
    Array[1..12] of ShortInt = (031,028,031,030,031,030,031,031,030,031,030,031);
  DaysPerYear  :
    Array[1..12] of Integer  = (031,059,090,120,151,181,212,243,273,304,334,365);
  DaysPerLeapYear :
    Array[1..12] of Integer  = (031,060,091,121,152,182,213,244,274,305,335,366);
  SecsPerYear      : LongInt  = 31536000;
  SecsPerLeapYear  : LongInt  = 31622400;
  SecsPerDay       : LongInt  = 86400;
  SecsPerHour      : Integer  = 3600;
  SecsPerMinute    : ShortInt = 60;

IMPLEMENTATION

Function GetTimeZone : ShortInt;
Var
  Environment : String;
  Index : Integer;
Begin
  GetTimeZone := 0;                            {Assume UTC}
  Environment := GetEnv('TZ');       {Grab TZ string}
  For Index := 1 To Length(Environment) Do
    Environment[Index] := Upcase(Environment[Index]);
(*
  NOTE: I have yet to find a complete list of the ISO table of time zone
        abbreviations. The following is excerpted from the Opus-Cbcs
        documentation files.
*)
  If Environment =  'EST05'    Then GetTimeZone := -05; {USA EASTERN}
  If Environment =  'EST05EDT' Then GetTimeZone := -06;
  If Environment =  'CST06'    Then GetTimeZone := -06; {USA CENTRAL}
  If Environment =  'CST06CDT' Then GetTimeZone := -07;
  If Environment =  'MST07'    Then GetTimeZone := -07; {USA MOUNTAIN}
  If Environment =  'MST07MDT' Then GetTimeZone := -08;
  If Environment =  'PST08'    Then GetTimeZone := -08;
  If Environment =  'PST08PDT' Then GetTimeZone := -09;
  If Environment =  'YST09'    Then GetTimeZone := -09;
  If Environment =  'AST10'    Then GetTimeZone := -10;
  If Environment =  'BST11'    Then GetTimeZone := -11;
  If Environment =  'CET-1'    Then GetTimeZone :=  01;
  If Environment =  'CET-01'   Then GetTimeZone :=  01;
  If Environment =  'EST-10'   Then GetTimeZone :=  10;
  If Environment =  'WST-8'    Then GetTimeZone :=  08; {Perth, Western Austrailia}
  If Environment =  'WST-08'   Then GetTimeZone :=  08;
End;

Function IsLeapYear(Source : Word) : Boolean;
Begin
(*
  NOTE: This is wrong!
*)
  If (Source Mod 4 = 0) Then
    IsLeapYear := True
  Else
    IsLeapYear := False;
End;

Function Norm2Unix(Y,M,D,H,Min,S : Word) : LongInt;
Var
  UnixDate : LongInt;
  Index    : Word;
Begin
  UnixDate := 0;                                                 {initialize}
  Inc(UnixDate,S);                                              {add seconds}
  Inc(UnixDate,(SecsPerMinute * Min));                          {add minutes}
  Inc(UnixDate,(SecsPerHour * H));                                {add hours}
  (*************************************************************************)
  (* If UTC = 0, and local time is -06 hours of UTC, then                  *)
  (* UTC := UTC - (-06 * SecsPerHour)                                      *)
  (* Remember that a negative # minus a negative # yields a positive value *)
  (*************************************************************************)
  UnixDate := UnixDate - (GetTimeZone * SecsPerHour);            {UTC offset}

  If D > 1 Then                                 {has one day already passed?}
    Inc(UnixDate,(SecsPerDay * (D-1)));

  If IsLeapYear(Y) Then
    DaysPerMonth[02] := 29
  Else
    DaysPerMonth[02] := 28;                             {Check for Feb. 29th}

  Index := 1;
  If M > 1 Then For Index := 1 To (M-1) Do    {has one month already passed?}
    Inc(UnixDate,(DaysPerMonth[Index] * SecsPerDay));

  While Y > 1970 Do
  Begin
    If IsLeapYear((Y-1)) Then
      Inc(UnixDate,SecsPerLeapYear)
    Else
      Inc(UnixDate,SecsPerYear);
    Dec(Y,1);
  End;

  Norm2Unix := UnixDate;
End;

Procedure Unix2Norm(Date : LongInt; Var Y, M, D, H, Min, S : Word);
{}
Var
  LocalDate : LongInt;
  Done      : Boolean;
  X         : ShortInt;
  TotDays   : Integer;
Begin
  Y   := 1970;
  M   := 1;
  D   := 1;
  H   := 0;
  Min := 0;
  S   := 0;
  LocalDate := Date + (GetTimeZone * SecsPerHour);         {Local time date}
 (*************************************************************************)
 (* Sweep out the years...                                                *)
 (*************************************************************************)
  Done := False;
  While Not Done Do
  Begin
    If LocalDate >= SecsPerYear Then
    Begin
      Inc(Y,1);
      Dec(LocalDate,SecsPerYear);
    End
    Else
      Done := True;

    If (IsLeapYear(Y+1)) And (LocalDate >= SecsPerLeapYear) And
       (Not Done) Then
    Begin
      Inc(Y,1);
      Dec(LocalDate,SecsPerLeapYear);
    End;
  End;
  (*************************************************************************)
  M := 1;
  D := 1;
  Done := False;
  TotDays := LocalDate Div SecsPerDay;
  If IsLeapYear(Y) Then
  Begin
    DaysPerMonth[02] := 29;
    X := 1;
    Repeat
      If (TotDays <= DaysPerLeapYear[x]) Then
      Begin
        M := X;
        Done := True;
        Dec(LocalDate,(TotDays * SecsPerDay));
        D := DaysPerMonth[M]-(DaysPerLeapYear[M]-TotDays) + 1;
      End
      Else
        Done := False;
      Inc(X);
    Until (Done) or (X > 12);
  End
  Else
  Begin
    DaysPerMonth[02] := 28;
    X := 1;
    Repeat
      If (TotDays <= DaysPerYear[x]) Then
      Begin
        M := X;
        Done := True;
        Dec(LocalDate,(TotDays * SecsPerDay));
        D := DaysPerMonth[M]-(DaysPerYear[M]-TotDays) + 1;
      End
      Else
        Done := False;
      Inc(X);
    Until Done = True or (X > 12);
  End;
  H := LocalDate Div SecsPerHour;
    Dec(LocalDate,(H * SecsPerHour));
  Min := LocalDate Div SecsPerMinute;
    Dec(LocalDate,(Min * SecsPerMinute));
  S := LocalDate;
End;

Function  TodayInUnix : LongInt;
Var
  Year, Month, Day, DayOfWeek: Word;
  Hour, Minute, Second, Sec100: Word;
Begin
  GetDate(Year, Month, Day, DayOfWeek);
  GetTime(Hour, Minute, Second, Sec100);
  TodayInUnix := Norm2Unix(Year,Month,Day,Hour,Minute,Second);
End;

Function  Unix2Str(N : LongInt) : String;
Var
  Year, Month, Day, DayOfWeek  : Word;
  Hour, Minute, Second, Sec100 : Word;
  T : String;
Begin
  Unix2Norm(N, Year, Month, Day, Hour, Minute, Second);
  T := PadRight(IntToStr(Month),2,'0')+'-'+PadRight(IntToStr(Day),2,'0')+'-'+
       PadRight(IntToStr(Year),2,'0')+' '+ PadRight(IntToStr(Hour),2,'0')+':'+
       PadRight(IntToStr(Minute),2,'0')+':'+PadRight(IntToStr(Second),2,'0');
  If Hour > 12 Then
    T := T + ' PM'
  Else
    T := T + ' AM';
  Unix2Str := T;
End;


END.