📄 iddatetimestamp.pas
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence }
{ Team Coherence is Copyright 2002 by Quality Software Components }
{ }
{ For further information / comments, visit our WEB site at }
{ http://www.TeamCoherence.com }
{**********************************************************************}
{}
{ $Log: 10119: IdDateTimeStamp.pas
{
{ Rev 1.0 2002.11.12 10:34:48 PM czhower
}
unit IdDateTimeStamp;
{
ToDo: Allow localisation date / time strings generated (i.e., to zone name).
ToDo: Rework SetFromRFC822 as it is (marginally) limited by it's
conversion to TDateTime.
ToDo: Conversion between Time Zones.
}
{
2002-Feb-07 Pete Mee
- Modified interface: GetAsRFC882 is now GetAsRFC822. ;-)
- Fixed GetAsTTimeStamp (was way out).
2001-Nov-10 Pete Mee
- Added SetFromDOSDateTime.
2001-Mar-29 Pete Mee
- Fixed bug in SetFromRFC822. As luck would have it, my PC has changed
to BST from GMT, so I caught the error. Change use of GMTToLocalDateTime
to StrInternetToDateTime.
2001-Mar-27 Pete Mee
- Added GetTimeZoneHour, GetTimeZoneMinutes, GetTimeZoneAsString and
corresponding properties, TimeZoneHour, TimeZoneMinutes and TimeZoneAsString.
- Added SetFromRFC822 and SetFromISO8601.
2001-Mar-26 Pete Mee
- Fixed bug in AddDays. Was adding an extra day in the wrong centuary.
- Fixed bug in AddDays. Was not altering the year with large additions.
2001-Mar-23 Pete Mee
- Fixed bug in SubtractMilliseconds.
- GetBeatOfDay is more accurate (based on milliseconds instead of seconds).
2001-Mar-21 Pete Mee
- Altered Day, Seond and Millisecond properties to use their respective
Set methods.
- Added SetTimeZone, Zero, ZeroTime and ZeroDate.
- Altered SetYear and SetDay to cope with the value 0.
2000-Sep-16 Pete Mee
- SetYear no longer accepts zero but instead simply exits.
2000-Aug-01 Pete Mee
- Fix bugs in AddDays & SubtractDays. Depending on the day of the year, the
calculations could have been incorrect. Now 'rounds off' to the nearest year
before any other calculation.
2000-Jul-28 Pete Mee
- Fix bugs in AddDays & SubtractDays. 3 days in 400 years lost, 1 day in 100
years lost.
2000-May-11 Pete Mee
- Added GetAsRFC822, GetAsISO8601
2000-May-03 Pete Mee
- Added detection of Day, Week and Month (various formats).
2000-May-02 Pete Mee
- Started TIdDateTimeStamp
}
{
Development notes:
The Calendar used is the Gregorian Calendar (modern western society). This
Calendar's use started somtime in the 1500s but wasn't adopted by some countries
until the early 1900s. No attempt is made to cope with any other Calendars.
No attempt is made to cope with any Atomic time quantity less than a leap
year (i.e., an exact number of seconds per day and an exact number of days
per year / leap year - no leap seconds, no 1/4 days, etc).
The implementation revolves around the Milliseconds, Seconds, Days and Years.
The heirarchy is as follows:
Milliseconds modify seconds. (0-999 Milliseconds)
Seconds modify days. (0-59 Seconds)
Days modify years. (1-365/366 Days)
Years modify years. (..., -2, -1, 1, ...)
All other time units are translated into necessary component parts. I.e.,
a week is 7 days, and hour is 3600 seconds, a minute is 60 seconds, etc...
The implementation could be easily expanded to represent decades, centuries,
nanoseconds, and beyond in both directions. Milliseconds are included to
provide easy conversion from TTimeStamp and back (and hence TDateTime). The
current component is designed to give good functionality for the majority (if
not all) of Internet component requirements (including Swatch's Internet Time).
It is also not limited to the 2038 bug of many of today's OSs (32-bit signed
number of seconds from 1st Jan 1970 = 19th Jan 2038 03:14:07, or there abouts).
NB: This implementation is factors slower than those of the TDateTime and
TTimeStamp components of standard Delphi. It's main use lies in the conversion
to / from ISO 8601 and RFC 822 formats as well as dates ranging beyond 2037 and
before 1970 (though TTimeStamp is capable here). It's also the only date component
I'm aware of that complies with RFC 2550 "Y10K and Beyond"... one of those RFCs in
the same category as RFC 1149, IP over Avian Carriers. ;-)
Pete Mee
}
interface
uses
Classes,
IdBaseComponent,
SysConst {Import strings for days & months}, SysUtils ;
const
// Some basic constants
IdMilliSecondsInSecond = 1000;
IdSecondsInMinute = 60;
IdMinutesInHour = 60;
IdHoursInDay = 24;
IdDaysInWeek = 7;
IdDaysInYear = 365;
IdDaysInLeapYear = 366;
IdYearsInShortLeapYearCycle = 4;
IdDaysInShortLeapYearCycle = IdDaysInLeapYear + (IdDaysInYear * 3);
IdDaysInShortNonLeapYearCycle = IdDaysInYear * IdYearsInShortLeapYearCycle;
IdDaysInFourYears = IdDaysInShortLeapYearCycle;
IdYearsInCentury = 100;
IdDaysInCentury = (25 * IdDaysInFourYears) - 1;
IdDaysInLeapCentury = IdDaysInCentury + 1;
IdYearsInLeapYearCycle = 400;
IdDaysInLeapYearCycle = IdDaysInCentury * 4 + 1;
IdMonthsInYear = 12;
// Beat time is Swatch's "Internet Time" http://www.swatch.com/ {Do not Localize}
IdBeatsInDay = 1000;
// Some compound constants
IdHoursInHalfDay = IdHoursInDay div 2;
IdSecondsInHour = IdSecondsInMinute * IdMinutesInHour;
IdSecondsInDay = IdSecondsInHour * IdHoursInDay;
IdSecondsInHalfDay = IdSecondsInHour * IdHoursInHalfDay;
IdSecondsInWeek = IdDaysInWeek * IdSecondsInDay;
IdSecondsInYear = IdSecondsInDay * IdDaysInYear;
IdSecondsInLeapYear = IdSecondsInDay * IdDaysInLeapYear;
IdMillisecondsInMinute = IdSecondsInMinute * IdMillisecondsInSecond;
IdMillisecondsInHour = IdSecondsInHour * IdMillisecondsInSecond;
IdMillisecondsInDay = IdSecondsInDay * IdMillisecondsInSecond;
IdMillisecondsInWeek = IdSecondsInWeek * IdMillisecondsInSecond;
IdDaysInMonth : array[1..IdMonthsInYear] of byte =
(
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
);
IdMonthNames : array[0..IdMonthsInYear] of string =
( '', {Do not Localize}
SLongMonthNameJan, SLongMonthNameFeb, SLongMonthNameMar,
SLongMonthNameApr, SLongMonthNameMay, SLongMonthNameJun,
SLongMonthNameJul, SLongMonthNameAug, SLongMonthNameSep,
SLongMonthNameOct, SLongMonthNameNov, SLongMonthNameDec );
IdMonthShortNames : array[0..IdMonthsInYear] of string =
( '', // Used for GetMonth {Do not Localize}
SShortMonthNameJan, SShortMonthNameFeb, SShortMonthNameMar,
SShortMonthNameApr, SShortMonthNameMay, SShortMonthNameJun,
SShortMonthNameJul, SShortMonthNameAug, SShortMonthNameSep,
SShortMonthNameOct, SShortMonthNameNov, SShortMonthNameDec );
IdDayNames : array[0..IdDaysInWeek] of string =
( '', SLongDayNameSun, SLongDayNameMon, SLongDayNameTue, {Do not Localize}
SLongDayNameWed, SLongDayNameThu, SLongDayNameFri,
SLongDayNameSat );
IdDayShortNames : array[0..IdDaysInWeek] of string =
( '', SShortDayNameSun, SShortDayNameMon, SShortDayNameTue, {Do not Localize}
SShortDayNameWed, SShortDayNameThu, SShortDayNameFri,
SShortDayNameSat );
// Area Time Zones
TZ_NZDT = 13; // New Zealand Daylight Time
TZ_IDLE = 12; // International Date Line East
TZ_NZST = TZ_IDLE;// New Zealand Standard Time
TZ_NZT = TZ_IDLE; // New Zealand Time
TZ_EADT = 11; // Eastern Australian Daylight Time
TZ_GST = 10; // Guam Standard Time / Russia Zone 9
TZ_JST = 9; // Japan Standard Time / Russia Zone 8
TZ_CCT = 8; // China Coast Time / Russia Zone 7
TZ_WADT = TZ_CCT; // West Australian Daylight Time
TZ_WAST = 7; // West Australian Standard Time / Russia Zone 6
TZ_ZP6 = 6; // Chesapeake Bay / Russia Zone 5
TZ_ZP5 = 5; // Chesapeake Bay / Russia Zone 4
TZ_ZP4 = 4; // Russia Zone 3
TZ_BT = 3; // Baghdad Time / Russia Zone 2
TZ_EET = 2; // Eastern European Time / Russia Zone 1
TZ_MEST = TZ_EET; // Middle European Summer Time
TZ_MESZ = TZ_EET; // Middle European Summer Zone
TZ_SST = TZ_EET; // Swedish Summer Time
TZ_FST = TZ_EET; // French Summer Time
TZ_CET = 1; // Central European Time
TZ_FWT = TZ_CET; // French Winter Time
TZ_MET = TZ_CET; // Middle European Time
TZ_MEWT = TZ_CET; // Middle European Winter Time
TZ_SWT = TZ_CET; // Swedish Winter Time
TZ_GMT = 0; // Greenwich Meanttime
TZ_UT = TZ_GMT; // Universla Time
TZ_UTC = TZ_GMT; // Universal Time Co-ordinated
TZ_WET = TZ_GMT; // Western European Time
TZ_WAT = -1; // West Africa Time
TZ_BST = TZ_WAT; // British Summer Time
TZ_AT = -2; // Azores Time
TZ_ADT = -3; // Atlantic Daylight Time
TZ_AST = -4; // Atlantic Standard Time
TZ_EDT = TZ_AST; // Eastern Daylight Time
TZ_EST = -5; // Eastern Standard Time
TZ_CDT = TZ_EST; // Central Daylight Time
TZ_CST = -6; // Central Standard Time
TZ_MDT = TZ_CST; // Mountain Daylight Time
TZ_MST = -7; // Mountain Standard Time
TZ_PDT = TZ_MST; // Pacific Daylight Time
TZ_PST = -8; // Pacific Standard Time
TZ_YDT = TZ_PST; // Yukon Daylight Time
TZ_YST = -9; // Yukon Standard Time
TZ_HDT = TZ_YST; // Hawaii Daylight Time
TZ_AHST = -10; // Alaska-Hawaii Standard Time
TZ_CAT = TZ_AHST;// Central Alaska Time
TZ_HST = TZ_AHST; // Hawaii Standard Time
TZ_EAST = TZ_AHST;// East Australian Standard Time
TZ_NT = -11; // -None-
TZ_IDLW = -12; // International Date Line West
// Military Time Zones
TZM_A = TZ_WAT;
TZM_Alpha = TZM_A;
TZM_B = TZ_AT;
TZM_Bravo = TZM_B;
TZM_C = TZ_ADT;
TZM_Charlie = TZM_C;
TZM_D = TZ_AST;
TZM_Delta = TZM_D;
TZM_E = TZ_EST;
TZM_Echo = TZM_E;
TZM_F = TZ_CST;
TZM_Foxtrot = TZM_F;
TZM_G = TZ_MST;
TZM_Golf = TZM_G;
TZM_H = TZ_PST;
TZM_Hotel = TZM_H;
TZM_J = TZ_YST;
TZM_Juliet = TZM_J;
TZM_K = TZ_AHST;
TZM_Kilo = TZM_K;
TZM_L = TZ_NT;
TZM_Lima = TZM_L;
TZM_M = TZ_IDLW;
TZM_Mike = TZM_M;
TZM_N = TZ_CET;
TZM_November = TZM_N;
TZM_O = TZ_EET;
TZM_Oscar = TZM_O;
TZM_P = TZ_BT;
TZM_Papa = TZM_P;
TZM_Q = TZ_ZP4;
TZM_Quebec = TZM_Q;
TZM_R = TZ_ZP5;
TZM_Romeo = TZM_R;
TZM_S = TZ_ZP6;
TZM_Sierra = TZM_S;
TZM_T = TZ_WAST;
TZM_Tango = TZM_T;
TZM_U = TZ_CCT;
TZM_Uniform = TZM_U;
TZM_V = TZ_JST;
TZM_Victor = TZM_V;
TZM_W = TZ_GST;
TZM_Whiskey = TZM_W;
TZM_X = TZ_NT;
TZM_XRay = TZM_X;
TZM_Y = TZ_IDLE;
TZM_Yankee = TZM_Y;
TZM_Z = TZ_GMT;
TZM_Zulu = TZM_Z;
type
{ TODO: I'm sure these are stored in a unit elsewhere... need to find out } {Do not Localize}
TDays = (TDaySun, TDayMon, TDayTue, TDayWed, TDayThu, TDayFri, TDaySat);
TMonths = (TMthJan, TMthFeb, TMthMar, TMthApr, TMthMay, TMthJun,
TMthJul, TMthAug, TMthSep, TMthOct, TMthNov, TMthDec);
TIdDateTimeStamp = class(TIdBaseComponent)
protected
FDay : Integer;
FIsLeapYear : Boolean;
FMillisecond : Integer;
FSecond : Integer;
FTimeZone : Integer; // Number of minutes + / - from GMT / UTC
FYear : Integer;
procedure CheckLeapYear;
procedure SetDateFromISO8601(AString : String);
procedure SetTimeFromISO8601(AString : String);
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure AddDays(ANumber : Cardinal);
procedure AddHours(ANumber : Cardinal);
procedure AddMilliseconds(ANumber : Cardinal);
procedure AddMinutes(ANumber : Cardinal);
procedure AddMonths(ANumber : Cardinal);
procedure AddSeconds(ANumber : Cardinal);
procedure AddTDateTime(ADateTime : TDateTime);
procedure AddTIdDateTimeStamp(AIdDateTime : TIdDateTimeStamp);
procedure AddTTimeStamp(ATimeStamp : TTimeStamp);
procedure AddWeeks(ANumber : Cardinal);
procedure AddYears(ANumber : Cardinal);
function GetAsISO8601Calendar : String;
function GetAsISO8601Ordinal : String;
function GetAsISO8601Week : String;
function GetAsRFC822 : String;
{TODO : function GetAsRFC977DateTime : String;}
function GetAsTDateTime : TDateTime;
function GetAsTTimeStamp : TTimeStamp;
function GetAsTimeOfDay : String; // HH:MM:SS
function GetBeatOfDay : Integer;
function GetDaysInYear : Integer;
function GetDayOfMonth : Integer;
function GetDayOfWeek : Integer;
function GetDayOfWeekName : String;
function GetDayOfWeekShortName : String;
function GetHourOf12Day : Integer;
function GetHourOf24Day : Integer;
function GetIsMorning : Boolean;
function GetMinuteOfDay : Integer;
function GetMinuteOfHour : Integer;
function GetMonthOfYear : Integer;
function GetMonthName : String;
function GetMonthShortName : String;
function GetSecondsInYear : Integer;
function GetSecondOfMinute : Integer;
function GetTimeZoneAsString: String;
function GetTimeZoneHour: Integer;
function GetTimeZoneMinutes: Integer;
function GetWeekOfYear : Integer;
procedure SetFromDOSDateTime(ADate, ATime : Word);
procedure SetFromISO8601(AString : String);
procedure SetFromRFC822(AString : String);
procedure SetFromTDateTime(ADateTime : TDateTime);
procedure SetFromTTimeStamp(ATimeStamp : TTimeStamp);
procedure SetDay(ANumber : Integer);
procedure SetMillisecond(ANumber : Integer);
procedure SetSecond(ANumber : Integer);
procedure SetTimeZone(const Value: Integer);
procedure SetYear(ANumber : Integer);
procedure SubtractDays(ANumber : Cardinal);
procedure SubtractHours(ANumber : Cardinal);
procedure SubtractMilliseconds(ANumber : Cardinal);
procedure SubtractMinutes(ANumber : Cardinal);
procedure SubtractMonths(ANumber : Cardinal);
procedure SubtractSeconds(ANumber : Cardinal);
procedure SubtractTDateTime(ADateTime : TDateTime);
procedure SubtractTIdDateTimeStamp(AIdDateTime : TIdDateTimeStamp);
procedure SubtractTTimeStamp(ATimeStamp : TTimeStamp);
procedure SubtractWeeks(ANumber : Cardinal);
procedure SubtractYears(ANumber : Cardinal);
procedure Zero;
procedure ZeroDate;
procedure ZeroTime;
property AsISO8601Calendar : String read GetAsISO8601Calendar;
property AsISO8601Ordinal : String read GetAsISO8601Ordinal;
property AsISO8601Week : String read GetAsISO8601Week;
property AsRFC822 : String read GetAsRFC822;
property AsTDateTime : TDateTime read GetAsTDateTime;
property AsTTimeStamp : TTimeStamp read GetAsTTimeStamp;
property AsTimeOfDay : String read GetAsTimeOfDay;
property BeatOfDay : Integer read GetBeatOfDay;
property Day : Integer read FDay write SetDay;
property DaysInYear : Integer read GetDaysInYear;
property DayOfMonth : Integer read GetDayOfMonth;
property DayOfWeek : Integer read GetDayOfWeek;
property DayOfWeekName : String read GetDayOfWeekName;
property DayOfWeekShortName : String read GetDayOfWeekShortName;
property HourOf12Day : Integer read GetHourOf12Day;
property HourOf24Day : Integer read GetHourOf24Day;
property IsLeapYear : Boolean read FIsLeapYear;
property IsMorning : Boolean read GetIsMorning;
property Millisecond : Integer read FMillisecond write SetMillisecond;
property MinuteOfDay : Integer read GetMinuteOfDay;
property MinuteOfHour : Integer read GetMinuteOfHour;
property MonthOfYear : Integer read GetMonthOfYear;
property MonthName : String read GetMonthName;
property MonthShortName : String read GetMonthShortName;
property Second : Integer read FSecond write SetSecond;
property SecondsInYear : Integer read GetSecondsInYear;
property SecondOfMinute : Integer read GetSecondOfMinute;
property TimeZone : Integer read FTimeZone write SetTimeZone;
property TimeZoneHour : Integer read GetTimeZoneHour;
property TimeZoneMinutes : Integer read GetTimeZoneMinutes;
property TimeZoneAsString : String read GetTimeZoneAsString;
property Year : Integer read FYear write SetYear;
property WeekOfYear : Integer read GetWeekOfYear;
end;
implementation
uses
IdGlobal,
IdStrings;
const
MaxWeekAdd : Cardinal = $FFFFFFFF div IdDaysInWeek;
MaxMinutesAdd : Cardinal = $FFFFFFFF div IdSecondsInMinute;
DIGITS : String = '0123456789'; {Do not Localize}
/////////////
// IdDateTime
/////////////
constructor TIdDateTimeStamp.Create;
begin
inherited Create(AOwner);
Zero;
FTimeZone := 0;
end;
destructor TIdDateTimeStamp.Destroy;
begin
inherited;
end;
procedure TIdDateTimeStamp.AddDays;
var
i : Integer;
begin
// First 'round off' the current day of the year. This is done to prevent {Do not Localize}
// miscalculations in leap years and also as an optimisation for small
// increments.
if (ANumber > Cardinal(DaysInYear - FDay)) and (not (FDay = 1)) then begin
ANumber := ANumber - Cardinal(DaysInYear - FDay);
FDay := 0;
AddYears(1);
end else begin
// The number of days added is contained within this year.
FDay := FDay + Integer(ANumber);
if (FDay > DaysInYear) then
begin
ANumber := FDay;
FDay := 0;
AddDays(ANumber);
end;
Exit;
end;
if ANumber >= IdDaysInLeapYearCycle then begin
i := ANumber div IdDaysInLeapYearCycle;
AddYears(i * IdYearsInLeapYearCycle);
ANumber := ANumber - Cardinal(i * IdDaysInLeapYearCycle);
end;
if ANumber >= IdDaysInLeapCentury then begin
while ANumber >= IDDaysInLeapCentury do begin
i := FYear div 100;
if i mod 4 = 3 then begin
// Going forward through a 'leap' century {Do not Localize}
AddYears(IdYearsInCentury);
ANumber := ANumber - Cardinal(IdDaysInLeapCentury);
end else begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -