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.