lazarus-ccr/components/orpheus/ovcdate.pas
2007-01-16 02:17:08 +00:00

997 lines
27 KiB
ObjectPascal

{*********************************************************}
{* OVCDATE.PAS 4.06 *}
{*********************************************************}
{* ***** BEGIN LICENSE BLOCK ***** *}
{* Version: MPL 1.1 *}
{* *}
{* The contents of this file are subject to the Mozilla Public License *}
{* Version 1.1 (the "License"); you may not use this file except in *}
{* compliance with the License. You may obtain a copy of the License at *}
{* http://www.mozilla.org/MPL/ *}
{* *}
{* Software distributed under the License is distributed on an "AS IS" basis, *}
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
{* for the specific language governing rights and limitations under the *}
{* License. *}
{* *}
{* The Original Code is TurboPower Orpheus *}
{* *}
{* The Initial Developer of the Original Code is TurboPower Software *}
{* *}
{* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *}
{* TurboPower Software Inc. All Rights Reserved. *}
{* *}
{* Contributor(s): *}
{* *}
{* ***** END LICENSE BLOCK ***** *}
{$I OVC.INC}
{$IFDEF VERSION7}
{$IFNDEF FPC}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CAST OFF}
{$ENDIF}
{$ENDIF}
{For BCB 3.0 package support.}
{$IFDEF VER110}
{$ObjExportAll On}
{$ENDIF}
{---Global compiler defines for Delphi 2.0---}
{$A+} {Word Align Data}
{$H+} {Huge string support}
{$Q-} {Overflow check}
{$R-} {Range check}
{$S-} {Stack check}
{$T-} {Typed @ check}
{$V-} {Var strings}
unit ovcdate; {formerly StDate}
{-Date and time manipulation}
interface
uses
{$IFNDEF LCL} Windows, {$ELSE} LclIntf, {$ENDIF} SysUtils;
type
TStDate = LongInt;
{In STDATE, dates are stored in long integer format as the number of days
since January 1, 1600}
TDateArray = array[0..(MaxLongInt div SizeOf(TStDate))-1] of TStDate;
{Type for StDate open array}
TStDayType = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
{An enumerated type used when representing a day of the week}
TStBondDateType = (bdtActual, bdt30E360, bdt30360, bdt30360psa);
{An enumerated type used for calculating bond date differences}
TStTime = LongInt;
{STDATE handles time in a manner similar to dates, representing a given
time of day as the number of seconds since midnight}
TStDateTimeRec =
record
{This record type simply combines the two basic date types defined by
STDATE, Date and Time}
D : TStDate;
T : TStTime;
end;
const
MinYear = 1600; {Minimum valid year for a date variable}
MaxYear = 3999; {Maximum valid year for a date variable}
Mindate = $00000000; {Minimum valid date for a date variable - 01/01/1600}
Maxdate = $000D6025; {Maximum valid date for a date variable - 12/31/3999}
Date1900 = $0001AC05; {This constant contains the Julian date for 01/01/1900}
Date1980 = $00021E28; {This constant contains the Julian date for 01/01/1980}
Date2000 = $00023AB1; {This constant contains the Julian date for 01/01/2000}
{This value is used to represent an invalid date, such as 12/32/1992}
BadDate = LongInt($FFFFFFFF);
DeltaJD = $00232DA8; {Days between 1/1/-4173 and 1/1/1600}
MinTime = 0; {Minimum valid time for a time variable - 00:00:00 am}
MaxTime = 86399; {Maximum valid time for a time variable - 23:59:59 pm}
{This value is used to represent an invalid time of day, such as 12:61:00}
BadTime = LongInt($FFFFFFFF);
SecondsInDay = 86400; {Number of seconds in a day}
SecondsInHour = 3600; {Number of seconds in an hour}
SecondsInMinute = 60; {Number of seconds in a minute}
HoursInDay = 24; {Number of hours in a day}
MinutesInHour = 60; {Number of minutes in an hour}
MinutesInDay = 1440; {Number of minutes in a day}
var
DefaultYear : Integer; {default year--used by DateStringToDMY}
DefaultMonth : ShortInt; {default month}
{-------julian date routines---------------}
function CurrentDate : TStDate;
{-returns today's date as a Julian date}
function ValidDate(Day, Month, Year, Epoch : Integer) : Boolean;
{-Verify that day, month, year is a valid date}
function DMYtoStDate(Day, Month, Year, Epoch : Integer) : TStDate;
{-Convert from day, month, year to a Julian date}
procedure StDateToDMY(Julian : TStDate; var Day, Month, Year : Integer);
{-Convert from a Julian date to day, month, year}
function IncDate(Julian : TStDate; Days, Months, Years : Integer) : TStDate;
{-Add (or subtract) the number of days, months, and years to a date}
function IncDateTrunc(Julian : TStDate; Months, Years : Integer) : TStDate;
{-Add (or subtract) the specified number of months and years to a date}
procedure DateDiff(Date1, Date2 : TStDate;
var Days, Months, Years : Integer);
{-Return the difference in days, months, and years between two valid Julian
dates}
function BondDateDiff(Date1, Date2 : TStDate; DayBasis : TStBondDateType) : TStDate;
{-Return the difference in days between two valid Julian
dates using a specific financial basis}
function WeekOfYear(Julian : TStDate) : Byte;
{-Returns the week number of the year given the Julian Date}
function AstJulianDate(Julian : TStDate) : Double;
{-Returns the Astronomical Julian Date from a TStDate}
function AstJulianDatetoStDate(AstJulian : Double; Truncate : Boolean) : TStDate;
{-Returns a TStDate from an Astronomical Julian Date.
Truncate TRUE Converts to appropriate 0 hours then truncates
FALSE Converts to appropriate 0 hours, then rounds to
nearest;}
function AstJulianDatePrim(Year, Month, Date : Integer; UT : TStTime) : Double;
{-Returns an Astronomical Julian Date for any year, even those outside
MinYear..MaxYear}
function DayOfWeek(Julian : TStDate) : TStDayType;
{-Return the day of the week for a Julian date}
function DayOfWeekDMY(Day, Month, Year, Epoch : Integer) : TStDayType;
{-Return the day of the week for the day, month, year}
function IsLeapYear(Year : Integer) : Boolean;
{-Return True if Year is a leap year}
function DaysInMonth(Month : Integer; Year, Epoch : Integer) : Integer;
{-Return the number of days in the specified month of a given year}
function ResolveEpoch(Year, Epoch : Integer) : Integer;
{-Convert 2 digit year to 4 digit year according to Epoch}
{-------time routines---------------}
function ValidTime(Hours, Minutes, Seconds : Integer) : Boolean;
{-Return True if Hours:Minutes:Seconds is a valid time}
procedure StTimeToHMS(T : TStTime;
var Hours, Minutes, Seconds : Byte);
{-Convert a time variable to hours, minutes, seconds}
function HMStoStTime(Hours, Minutes, Seconds : Byte) : TStTime;
{-Convert hours, minutes, seconds to a time variable}
function CurrentTime : TStTime;
{-Return the current time in seconds since midnight}
procedure TimeDiff(Time1, Time2 : TStTime;
var Hours, Minutes, Seconds : Byte);
{-Return the difference in hours, minutes, and seconds between two times}
function IncTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime;
{-Add the specified hours, minutes, and seconds to a given time of day}
function DecTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime;
{-Subtract the specified hours, minutes, and seconds from a given time of day}
function RoundToNearestHour(T : TStTime; Truncate : Boolean) : TStTime;
{-Given a time, round it to the nearest hour, or truncate minutes and
seconds}
function RoundToNearestMinute(const T : TStTime; Truncate : Boolean) : TStTime;
{-Given a time, round it to the nearest minute, or truncate seconds}
{-------- routines for DateTimeRec records ---------}
procedure DateTimeDiff(DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec;
var Days : LongInt; var Secs : LongInt);
{-Return the difference in days and seconds between two points in time}
procedure IncDateTime(DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec;
Days : Integer; Secs : LongInt);
{-Increment (or decrement) a date and time by the specified number of days
and seconds}
function DateTimeToStDate(DT : TDateTime) : TStDate;
{-Convert Delphi TDateTime to TStDate}
function DateTimeToStTime(DT : TDateTime) : TStTime;
{-Convert Delphi TDateTime to TStTime}
function StDateToDateTime(D : TStDate) : TDateTime;
{-Convert TStDate to TDateTime}
function StTimeToDateTime(T : TStTime) : TDateTime;
{-Convert TStTime to TDateTime}
function Convert2ByteDate(TwoByteDate : Word) : TStDate;
{-Convert an Object Professional two byte date into a SysTools date}
function Convert4ByteDate(FourByteDate : TStDate) : Word;
{-Convert a SysTools date into an Object Professional two byte date}
implementation
const
First2Months = 59; {1600 was a leap year}
FirstDayOfWeek = Saturday; {01/01/1600 was a Saturday}
DateLen = 40; {maximum length of Picture strings}
MaxMonthName = 15;
MaxDayName = 15;
type
{ DateString = string[DateLen];}
SString = string[255];
function IsLeapYear(Year : Integer) : Boolean;
{-Return True if Year is a leap year}
begin
Result := (Year mod 4 = 0) and (Year mod 4000 <> 0) and
((Year mod 100 <> 0) or (Year mod 400 = 0));
end;
function IsLastDayofMonth(Day, Month, Year : Integer) : Boolean;
{-Return True if date is the last day in month}
var
Epoch : Integer;
begin
Epoch := (Year div 100) * 100;
if ValidDate(Day + 1, Month, Year, Epoch) then
Result := false
else
Result := true;
end;
function IsLastDayofFeb(Date : TStDate) : Boolean;
{-Return True if date is the last day in February}
var
Day, Month, Year : Integer;
begin
StDateToDMY(Date, Day, Month, Year);
if (Month = 2) and IsLastDayOfMonth(Day, Month, Year) then
Result := true
else
Result := false;
end;
{$IFDEF NoAsm}
procedure ExchangeLongInts(var I, J : LongInt);
var
Temp : LongInt;
begin
Temp := I;
I := J;
J := Temp;
end;
// ExchangeStructs not needed - see the one place where called below.
{$ELSE}
procedure ExchangeLongInts(var I, J : LongInt);
register;
asm
mov ecx, [eax]
push ecx
mov ecx, [edx]
mov [eax], ecx
pop ecx
mov [edx], ecx
end;
procedure ExchangeStructs(var I, J; Size : Cardinal);
register;
asm
push edi
push ebx
push ecx
shr ecx, 2
jz @@LessThanFour
@@AgainDWords:
mov ebx, [eax]
mov edi, [edx]
mov [edx], ebx
mov [eax], edi
add eax, 4
add edx, 4
dec ecx
jnz @@AgainDWords
@@LessThanFour:
pop ecx
and ecx, $3
jz @@Done
mov bl, [eax]
mov bh, [edx]
mov [edx], bl
mov [eax], bh
inc eax
inc edx
dec ecx
jz @@Done
mov bl, [eax]
mov bh, [edx]
mov [edx], bl
mov [eax], bh
inc eax
inc edx
dec ecx
jz @@Done
mov bl, [eax]
mov bh, [edx]
mov [edx], bl
mov [eax], bh
@@Done:
pop ebx
pop edi
end;
{$ENDIF}
function ResolveEpoch(Year, Epoch : Integer) : Integer;
{-Convert 2-digit year to 4-digit year according to Epoch}
var
EpochYear,
EpochCent : Integer;
begin
if Word(Year) < 100 then begin
EpochYear := Epoch mod 100;
EpochCent := (Epoch div 100) * 100;
if (Year < EpochYear) then
Inc(Year,EpochCent+100)
else
Inc(Year,EpochCent);
end;
Result := Year;
end;
function CurrentDate : TStDate;
{-Returns today's date as a julian}
var
Year, Month, Date : Word;
begin
DecodeDate(Now,Year,Month,Date);
Result := DMYToStDate(Date,Month,Year,0);
end;
function DaysInMonth(Month : integer; Year, Epoch : Integer) : Integer;
{-Return the number of days in the specified month of a given year}
begin
Year := ResolveEpoch(Year, Epoch);
if (Year < MinYear) OR (Year > MaxYear) then
begin
Result := 0;
Exit;
end;
case Month of
1, 3, 5, 7, 8, 10, 12 :
Result := 31;
4, 6, 9, 11 :
Result := 30;
2 :
Result := 28+Ord(IsLeapYear(Year));
else
Result := 0;
end;
end;
function ValidDate(Day, Month, Year, Epoch : Integer) : Boolean;
{-Verify that day, month, year is a valid date}
begin
Year := ResolveEpoch(Year, Epoch);
if (Day < 1) or (Year < MinYear) or (Year > MaxYear) then
Result := False
else case Month of
1..12 :
Result := Day <= DaysInMonth(Month, Year, Epoch);
else
Result := False;
end
end;
function DMYtoStDate(Day, Month, Year, Epoch : Integer) : TStDate;
{-Convert from day, month, year to a julian date}
begin
Year := ResolveEpoch(Year, Epoch);
if not ValidDate(Day, Month, Year, Epoch) then
Result := BadDate
else if (Year = MinYear) and (Month < 3) then
if Month = 1 then
Result := Pred(Day)
else
Result := Day+30
else begin
if Month > 2 then
Dec(Month, 3)
else begin
Inc(Month, 9);
Dec(Year);
end;
Dec(Year, MinYear);
Result :=
((LongInt(Year div 100)*146097) div 4)+
((LongInt(Year mod 100)*1461) div 4)+
(((153*Month)+2) div 5)+Day+First2Months;
end;
end;
function WeekOfYear(Julian : TStDate) : Byte;
{-Returns the week number of the year given the Julian Date}
var
Day, Month, Year : Integer;
FirstJulian : TStDate;
begin
if (Julian < MinDate) or (Julian > MaxDate) then
begin
Result := 0;
Exit;
end;
Julian := Julian + 3 - ((6 + Ord(DayOfWeek(Julian))) mod 7);
StDateToDMY(Julian,Day,Month,Year);
FirstJulian := DMYToStDate(1,1,Year,0);
Result := 1 + (Julian - FirstJulian) div 7;
end;
function AstJulianDate(Julian : TStDate) : Double;
{-Returns the Astronomical Julian Date from a TStDate}
begin
{Subtract 0.5d since Astronomical JD starts at noon
while TStDate (with implied .0) starts at midnight}
Result := Julian - 0.5 + DeltaJD;
end;
function AstJulianDatePrim(Year, Month, Date : Integer; UT : TStTime) : Double;
var
A, B : integer;
LY,
GC : Boolean;
begin
Result := -MaxLongInt;
if (not (Month in [1..12])) or (Date < 1) then
Exit
else if (Month in [1, 3, 5, 7, 8, 10, 12]) and (Date > 31) then
Exit
else if (Month in [4, 6, 9, 11]) and (Date > 30) then
Exit
else if (Month = 2) then begin
LY := IsLeapYear(Year);
if ((LY) and (Date > 29)) or (not (LY) and (Date > 28)) then
Exit;
end else if ((UT < 0) or (UT >= SecondsInDay)) then
Exit;
if (Month <= 2) then begin
Year := Year - 1;
Month := Month + 12;
end;
A := abs(Year div 100);
if (Year > 1582) then
GC := True
else if (Year = 1582) then begin
if (Month > 10) then
GC := True
else if (Month < 10) then
GC := False
else begin
if (Date >= 15) then
GC := True
else
GC := False;
end;
end else
GC := False;
if (GC) then
B := 2 - A + abs(A div 4)
else
B := 0;
Result := Trunc(365.25 * (Year + 4716))
+ Trunc(30.6001 * (Month + 1))
+ Date + B - 1524.5
+ UT / SecondsInDay;
end;
function AstJulianDatetoStDate(AstJulian : Double; Truncate : Boolean) : TStDate;
{-Returns a TStDate from an Astronomical Julian Date.
Truncate TRUE Converts to appropriate 0 hours then truncates
FALSE Converts to appropriate 0 hours, then rounds to
nearest;}
begin
{Convert to TStDate, adding 0.5d for implied .0d of TStDate}
AstJulian := AstJulian + 0.5 - DeltaJD;
if (AstJulian < MinDate) OR (AstJulian > MaxDate) then
begin
Result := BadDate;
Exit;
end;
if Truncate then
Result := Trunc(AstJulian)
else
Result := Trunc(AstJulian + 0.5);
end;
procedure StDateToDMY(Julian : TStDate; var Day, Month, Year : Integer);
{-Convert from a julian date to month, day, year}
var
I, J : LongInt;
begin
if Julian = BadDate then begin
Day := 0;
Month := 0;
Year := 0;
end else if Julian <= First2Months then begin
Year := MinYear;
if Julian <= 30 then begin
Month := 1;
Day := Succ(Julian);
end else begin
Month := 2;
Day := Julian-30;
end;
end else begin
I := (4*LongInt(Julian-First2Months))-1;
J := (4*((I mod 146097) div 4))+3;
Year := (100*(I div 146097))+(J div 1461);
I := (5*(((J mod 1461)+4) div 4))-3;
Day := ((I mod 153)+5) div 5;
Month := I div 153;
if Month < 10 then
Inc(Month, 3)
else begin
Dec(Month, 9);
Inc(Year);
end;
Inc(Year, MinYear);
end;
end;
function IncDate(Julian : TStDate; Days, Months, Years : Integer) : TStDate;
{-Add (or subtract) the number of months, days, and years to a date.
Months and years are added before days. No overflow/underflow
checks are made}
var
Day, Month, Year, Day28Delta : Integer;
begin
StDateToDMY(Julian, Day, Month, Year);
Day28Delta := Day-28;
if Day28Delta < 0 then
Day28Delta := 0
else
Day := 28;
Inc(Year, Years);
Inc(Year, Months div 12);
Inc(Month, Months mod 12);
if Month < 1 then begin
Inc(Month, 12);
Dec(Year);
end
else if Month > 12 then begin
Dec(Month, 12);
Inc(Year);
end;
Julian := DMYtoStDate(Day, Month, Year,0);
if Julian <> BadDate then begin
Inc(Julian, Days);
Inc(Julian, Day28Delta);
end;
Result := Julian;
end;
function IncDateTrunc(Julian : TStDate; Months, Years : Integer) : TStDate;
{-Add (or subtract) the specified number of months and years to a date}
var
Day, Month, Year : Integer;
MaxDay, Day28Delta : Integer;
begin
StDateToDMY(Julian, Day, Month, Year);
Day28Delta := Day-28;
if Day28Delta < 0 then
Day28Delta := 0
else
Day := 28;
Inc(Year, Years);
Inc(Year, Months div 12);
Inc(Month, Months mod 12);
if Month < 1 then begin
Inc(Month, 12);
Dec(Year);
end
else if Month > 12 then begin
Dec(Month, 12);
Inc(Year);
end;
Julian := DMYtoStDate(Day, Month, Year,0);
if Julian <> BadDate then begin
MaxDay := DaysInMonth(Month, Year,0);
if Day+Day28Delta > MaxDay then
Inc(Julian, MaxDay-Day)
else
Inc(Julian, Day28Delta);
end;
Result := Julian;
end;
procedure DateDiff(Date1, Date2 : TStDate; var Days, Months, Years : Integer);
{-Return the difference in days,months,years between two valid julian dates}
var
Day1, Day2, Month1, Month2, Year1, Year2 : Integer;
begin
{we want Date2 > Date1}
if Date1 > Date2 then
ExchangeLongInts(Date1, Date2);
{convert dates to day,month,year}
StDateToDMY(Date1, Day1, Month1, Year1);
StDateToDMY(Date2, Day2, Month2, Year2);
{days first}
if (Day1 = DaysInMonth(Month1, Year1, 0)) then begin
Day1 := 0;
Inc(Month1); {OK if Month1 > 12}
end;
if (Day2 = DaysInMonth(Month2, Year2, 0)) then begin
Day2 := 0;
Inc(Month2); {OK if Month2 > 12}
end;
if (Day2 < Day1) then begin
Dec(Month2);
if Month2 = 0 then begin
Month2 := 12;
Dec(Year2);
end;
Days := Day2 + DaysInMonth(Month1, Year1, 0) - Day1;
end else
Days := Day2-Day1;
{now months and years}
if Month2 < Month1 then begin
Inc(Month2, 12);
Dec(Year2);
end;
Months := Month2-Month1;
Years := Year2-Year1;
end;
function BondDateDiff(Date1, Date2 : TStDate; DayBasis : TStBondDateType) : TStDate;
{-Return the difference in days between two valid Julian
dates using one a specific accrual method}
var
Day1,
Month1,
Year1,
Day2,
Month2,
Year2 : Integer;
IY : LongInt;
begin
{we want Date2 > Date1}
if Date1 > Date2 then
ExchangeLongInts(Date1, Date2);
if (DayBasis = bdtActual) then
Result := Date2-Date1
else
begin
StDateToDMY(Date1, Day1, Month1, Year1);
StDateToDMY(Date2, Day2, Month2, Year2);
if ((DayBasis = bdt30360PSA) and IsLastDayofFeb(Date1)) or (Day1 = 31) then
Day1 := 30;
if (DayBasis = bdt30E360) then
begin
if (Day2 = 31) then
Day2 := 30
end else
if (Day2 = 31) and (Day1 >= 30) then
Day2 := 30;
IY := 360 * (Year2 - Year1);
Result := IY + 30 * (Month2 - Month1) + (Day2 - Day1);
end;
end;
function DayOfWeek(Julian : TStDate) : TStDayType;
{-Return the day of the week for the date. Returns TStDayType(7) if Julian =
BadDate.}
var
B : Byte;
begin
if Julian = BadDate then begin
B := 7;
Result := TStDayType(B);
end else
Result := TStDayType( (Julian+Ord(FirstDayOfWeek)) mod 7 );
end;
function DayOfWeekDMY(Day, Month, Year, Epoch : Integer) : TStDayType;
{-Return the day of the week for the day, month, year}
begin
Result := DayOfWeek( DMYtoStDate(Day, Month, Year, Epoch) );
end;
procedure StTimeToHMS(T : TStTime; var Hours, Minutes, Seconds : Byte);
{-Convert a Time variable to Hours, Minutes, Seconds}
begin
if T = BadTime then begin
Hours := 0;
Minutes := 0;
Seconds := 0;
end
else begin
Hours := T div SecondsInHour;
Dec(T, LongInt(Hours)*SecondsInHour);
Minutes := T div SecondsInMinute;
Dec(T, LongInt(Minutes)*SecondsInMinute);
Seconds := T;
end;
end;
function HMStoStTime(Hours, Minutes, Seconds : Byte) : TStTime;
{-Convert Hours, Minutes, Seconds to a Time variable}
var
T : TStTime;
begin
Hours := Hours mod HoursInDay;
T := (LongInt(Hours)*SecondsInHour)+(LongInt(Minutes)*SecondsInMinute)+Seconds;
Result := T mod SecondsInDay;
end;
function ValidTime(Hours, Minutes, Seconds : Integer) : Boolean;
{-Return true if Hours:Minutes:Seconds is a valid time}
begin
if (Hours < 0) or (Hours > 23) or
(Minutes < 0) or (Minutes >= 60) or
(Seconds < 0) or (Seconds >= 60) then
Result := False
else
Result := True;
end;
function CurrentTime : TStTime;
{-Returns current time in seconds since midnight}
begin
Result := Trunc(SysUtils.Time * SecondsInDay);
end;
procedure TimeDiff(Time1, Time2 : TStTime; var Hours, Minutes, Seconds : Byte);
{-Return the difference in hours,minutes,seconds between two times}
begin
StTimeToHMS(Abs(Time1-Time2), Hours, Minutes, Seconds);
end;
function IncTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime;
{-Add the specified hours,minutes,seconds to T and return the result}
begin
Inc(T, HMStoStTime(Hours, Minutes, Seconds));
Result := T mod SecondsInDay;
end;
function DecTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime;
{-Subtract the specified hours,minutes,seconds from T and return the result}
begin
Hours := Hours mod HoursInDay;
Dec(T, HMStoStTime(Hours, Minutes, Seconds));
if T < 0 then
Result := T+SecondsInDay
else
Result := T;
end;
function RoundToNearestHour(T : TStTime; Truncate : Boolean) : TStTime;
{-Round T to the nearest hour, or Truncate minutes and seconds from T}
var
Hours, Minutes, Seconds : Byte;
begin
StTimeToHMS(T, Hours, Minutes, Seconds);
Seconds := 0;
if not Truncate then
if Minutes >= (MinutesInHour div 2) then
Inc(Hours);
Minutes := 0;
Result := HMStoStTime(Hours, Minutes, Seconds);
end;
function RoundToNearestMinute(const T : TStTime; Truncate : Boolean) : TStTime;
{-Round T to the nearest minute, or Truncate seconds from T}
var
Hours, Minutes, Seconds : Byte;
begin
StTimeToHMS(T, Hours, Minutes, Seconds);
if not Truncate then
if Seconds >= (SecondsInMinute div 2) then
Inc(Minutes);
Seconds := 0;
Result := HMStoStTime(Hours, Minutes, Seconds);
end;
procedure DateTimeDiff(DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec;
var Days : LongInt; var Secs : LongInt);
{-Return the difference in days and seconds between two points in time}
var
tDT1, tDT2 : TStDateTimeRec;
{$IFDEF NoAsm}
Temp : TStDateTimeRec;
{$ENDIF}
begin
tDT1 := DT1;
tDT2 := DT2;
{swap if tDT1 later than tDT2}
if (tDT1.D > tDT2.D) or ((tDT1.D = tDT2.D) and (tDT1.T > tDT2.T)) then
{$IFDEF NoAsm}
begin
Temp := tDT1;
tDT1 := tDT2;
tDT2 := Temp;
end;
{$ELSE}
ExchangeStructs(tDT1, tDT2,sizeof(TStDateTimeRec));
{$ENDIF}
{the difference in days is easy}
Days := tDT2.D-tDT1.D;
{difference in seconds}
if tDT2.T < tDT1.T then begin
{subtract one day, add 24 hours}
Dec(Days);
Inc(tDT2.T, SecondsInDay);
end;
Secs := tDT2.T-tDT1.T;
end;
function DateTimeToStDate(DT : TDateTime) : TStDate;
{-Convert Delphi TDateTime to TStDate}
var
Day, Month, Year : Word;
begin
DecodeDate(DT, Year, Month, Day);
Result := DMYToStDate(Day, Month, Year, 0);
end;
function DateTimeToStTime(DT : TDateTime) : TStTime;
{-Convert Delphi TDateTime to TStTime}
var
Hour, Min, Sec, MSec : Word;
begin
DecodeTime(DT, Hour, Min, Sec, MSec);
Result := HMSToStTime(Hour, Min, Sec);
end;
function StDateToDateTime(D : TStDate) : TDateTime;
{-Convert TStDate to TDateTime}
var
Day, Month, Year : Integer;
begin
Result := 0;
if D <> BadDate then begin
StDateToDMY(D, Day, Month, Year);
Result := EncodeDate(Year, Month, Day);
end;
end;
function StTimeToDateTime(T : TStTime) : TDateTime;
{-Convert TStTime to TDateTime}
var
Hour, Min, Sec : Byte;
begin
Result := 0;
if T <> BadTime then begin
StTimeToHMS(T, Hour, Min, Sec);
Result := EncodeTime(Hour, Min, Sec, 0);
end;
end;
procedure IncDateTime(DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec; Days : Integer; Secs : LongInt);
{-Increment (or decrement) DT1 by the specified number of days and seconds
and put the result in DT2}
begin
DT2 := DT1;
{date first}
Inc(DT2.D, LongInt(Days));
if Secs < 0 then begin
{change the sign}
Secs := -Secs;
{adjust the date}
Dec(DT2.D, Secs div SecondsInDay);
Secs := Secs mod SecondsInDay;
if Secs > DT2.T then begin
{subtract a day from DT2.D and add a day's worth of seconds to DT2.T}
Dec(DT2.D);
Inc(DT2.T, SecondsInDay);
end;
{now subtract the seconds}
Dec(DT2.T, Secs);
end
else begin
{increment the seconds}
Inc(DT2.T, Secs);
{adjust date if necessary}
Inc(DT2.D, DT2.T div SecondsInDay);
{force time to 0..SecondsInDay-1 range}
DT2.T := DT2.T mod SecondsInDay;
end;
end;
function Convert2ByteDate(TwoByteDate : Word) : TStDate;
begin
Result := LongInt(TwoByteDate) + Date1900;
end;
function Convert4ByteDate(FourByteDate : TStDate) : Word;
begin
Result := Word(FourByteDate - Date1900);
end;
procedure SetDefaultYear;
{-Initialize DefaultYear and DefaultMonth}
var
Month, Day, Year : Word;
T : TDateTime;
begin
T := Now;
DecodeDate(T, Year, Month, Day);
DefaultYear := Year;
DefaultMonth := Month;
end;
initialization
{initialize DefaultYear and DefaultMonth}
SetDefaultYear;
end.