Create Unix dates

This unit provides access to UNIX date related functions and procedures

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.

 

Share this article!

Follow us!

Find more helpful articles: