Calculating with dates and times presents a number of possible pitfalls, described on relevant associated pages. Some of them occur more generally than there described. This is a comparatively simple list, to serve as a reminder :-
What have I forgotten?
One must distinguish between the numerical resolution of the stored quantity and its update interval.
The MS-DOS timer at 40:6C is incremented 1800B0h times per 24 hours, which is 18.2 Hz & 54.9 ms. The DOS time-of-day call therefore returns centiseconds increasing in steps of 5 and 6. Many systems use this timer, even under Win98+ where it may be possible to do better.
Floating-point day counts represent time-of-day inexactly; beware of rounding errors : see Delphi Date and Time, VBScript Date and Time.
In JavaScript, time is stored as integer milliseconds (from 1970.0 UTC); but is not necessarily updated that often.
My Borland Pascal Time and Date also refers to MS-DOS on the PC.
Avoid unnecessary work :-
Simplify :-
In calculating with just Y & M, it can be easier to work with 12×Y+M or 12×Y+M-1, and convert back with div and mod.
It is often useful to have available a routine to accept, in Y M D, out-of-range M & D and convert to a standard date or a daycount. Some languages have these built-in - JavaScript new Date(Y, M', D) and Date.UTC(Y, M', D) ; VBScript DateSerial for example.
Julian | Years | Gregorian | ||
---|---|---|---|---|
Seconds | Days | Days | Seconds | |
31536000 | 365 | 1 | 365 | 31536000 |
31622400 | 366 | 366 | 31622400 | |
126230400 | 1461 | 4 | 1460 | 126144000 |
1461 | 126230400 | |||
3155760000 | 36525 | 100 | 36524 | 3155673600 |
36525 | 3155760000 | |||
12623040000 | 146100 | 400 | 146097 | 12622780800 |
315576000000 | 3652500 | 10000 | 3652425 | 315569520000 |
For the Gregorian Calendar, without Summer Time or Leap Seconds.
To calculate with a long interval, first reduce the interval by a multiple of 400 years (all such are the same length) then use the remainder with due regard to the positioning of Leap Years.
For the Julian Calendar, first reduce by a multiple of 4 years.
I have read, from a presumed American :-
..., although they are ambiguous, "bi-weekly" and "semi-monthly" are fairly standard terms for pay schedules in my part of the world. bi-weekly : every two weeks, typically on Friday. semi-monthly : every half month, eg, 15th and last day.
These programs and units are written with BP7, are compilable with TP7, and also work with Delphi 3 in console mode in a Win 98 or XP DOS box, using "DCC32 -cc progname" to compile. All are in my programs/ Web directory, generally with EXE, ZIP, and sometimes TXT files.
Unit DATEPROX.PAS provides many Gregorian/Julian/Civil date routines, derived from first principles; it is tested by MJD_DATE.PAS, and agrees with others. Also, for Leap Years, see LEAPYEAR.PAS, which checks and compares a score of methods; and also see Leap Years.
The following presume the Gregorian calendar.
const DiM : array [1..12] of byte = (31,28,31,30,31,30,31,31,30,31,30,31) ; function ValidDateGreg1(const Yr : word ; const Mo, Dy : byte) : boolean ; begin (* assume, or set, {$B+} *) ValidDateGreg1 := (Mo in [1..12]) and (Dy>0) and ( (Dy<=DiM[Mo]) or ( (Dy=29) and Leap(Yr) ) ) ; end {ValidDateGreg1} ; For the last day in the Gregorian month, maybe function UltiMo(const Yr : word ; const Mo : byte) : byte ; begin UltiMo := DiM[Mo] + Ord((Mo=2) and Leap(Yr)) end {UltiMo} ; function ValidDateGreg2(const Yr : word ; const Mo, Dy : byte) : boolean ; begin (* assume, or set, {$B+} *) ValidDateGreg2 := (Mo in [1..12]) and (Dy>0) and (Dy<=UltiMo(Yr, Mo) ) ; end {ValidDateGreg2} ;
These are, slightly, tested.
Program LONGCALC.PAS also does date/time arithmetic, with vast integers; PASCHAL.PAS has Easter routines; NOWMINUS.PAS sets date information into the Environment.
Program HEBCLNDR.PAS contains code for the Molod and the start of a given Hebrew Calendar Year, and performs various tests and investigations.
These are Win32 console mode programs (PAS & EXE, in ZIP), compiled with Delphi 3 as above, for running at an MS-DOS prompt.
STD_TIME.PAS - redirect to a batch file, and execute that, to set these environment variables :-
SET CMJD=53428 SET MJD=53428 SET GMT=2005-02-27T12:17:43 SET time_t=1109506663
TZ-CHECK.PAS - test and demonstration of some Win32 Date/Time system routines.