© J R Stockton, ≥ 2010-11-03

Date Arithmetic.

Links within this site :-

**Merlyn Home Page**- Site Index, E-Mail, Copying**JavaScript**:-- Index and Introduction - with About This Site, Code Re-use, Links
- Include Files
- Date and Time Introduction - with Index and Examples
- Date and Time 0 - Date Object Information
- Date and Time 2 - Demonstrations
- Date and Time 3 - Input and Lengths
- Date and Time 4 - Validation
- Date and Time 5 - Date and Time Elsewhere
- Date and Time 6 - Date and Time Choosers
- Date and Time 7 - Working with Weeks
- Date and Time 8 - Enhancing the Object
- Date and Time 9 - Output Formatting
- Date and Time X - Troubles
- JavaScript : Object DATE2
- Calendars and Clocks - Demos
**This Page**:-- Further JavaScript pages :-

- There are links in JavaScript Date and Time Introduction to my other Date and Time Pages (much further date/time material is linked from those).

**See** "About This JavaScript Site" in
JavaScript Index and Introduction.

**See** "General Date/Time Introduction" in
JavaScript Date and Time Introduction.

See also in Field Rollover.

Date methods can be slow, so be careful not to repeatedly recalculate anything that can be remembered.

I find that the JavaScript UTC methods can be somewhat faster than the corresponding non-UTC ones. In hindsight, that should be expected. Unless actual date/times are needed, for repetitive work such as calendar display it should be noticeably better to use the UTC methods.

This shows generation of a Date Object set by UTC literals and
generation of a Date Object representing UTC `YMDhms` from a Date
Object value representing the same civil `YMDhms` :-

It can be quicker to use, instead of Date Objects, algorithms using efficient Day Count conversion routines; this is done in some of Week Number Calculation.

Normally, a Date Object will always be created with a particular value required : "now", or given by parameters.

Otherwise, for `N` being numeric, `new Date(N)` should
be faster than `new Date()` since, while both create an Object,
the former only needs to load it with `N` while the latter must
consult the system clock and maybe the locality settings. Moreover, with
the former, the value is reproducible. So, unless the current date/time
is needed, the former is better.

Obj = new Date() // if "now" is needed Obj = new Date(0) // otherwise better

To load UTC YMD into a Date Object, use, as above :-

Obj = new Date(Date.UTC(Y, M-1, D)) // also h m s ms

To copy or clone a Date Object `D1` consider :-

D2 = new Date(+D1) or D2 = new Date(D1.valueOf())

in which the `+` calls for the transfer of a Number rather
than allowing a String (properties other than the date/time will not be
copied).

Remember to allow for possible Summer Time and Time Zone changes, except when using GMT/UTC. Much code presented elsewhere ignores these, and is therefore in error part of the time. If UTC functions can be used, the overheads and errors can be avoided.

Otherwise, if Days are specified, then work directly with Days, rather than with milliseconds from 1970, as civil days are not always 24 hours long, but can be 23 or 25 hours. Likewise, both Months and Years have varying numbers of Days. Always test over a Summer Time change.

Anything containing 1000*60*60*24 or 86400000 or 864e5 is suspect, unless it is used in conjunction with UTC functions or there is appropriate rounding or offset adjustment. Note that in general it will be the user's settings that matter; on the Web, Summer Time remains significant even for Polar and Equatorial authors.

Where that number is used, it is better written as `864e5`
since that form is less prone to error.

The addition of 24 hours of actual time has advanced the EU civil time by only 23 hours; the inverse occurs in Spring.

Opera 10.51 has a peculiar problem.

SEE ALSO my Date and Day Count which is largely developed from Zeller's work.

JavaScript and UNIX Day 0 was GMT 1970-01-01 Thu; MJD 0 was GMT 1858-11-17 Wed; the difference is 40587 days. Day 0 for Delphi 2+ and compatible spreadsheets, etc., was Civil 1899-12-30, 25569 days before UNIX Day 0. See Date Miscellany I and Date and Time Scales.

Remember that a browser's local time is likely not to be GMT/UTC;
so `getTimezoneOffset` may be
needed.

Parts of this uses similar methods to those of The Calendrical Works of Rektor Chr. Zeller : The Day-of-Week and Easter and Date and Day Count.

Given a Date Object, divide by 864e5 and take the integer part.

Given a Date Object (or string), go to 0000h GMT and divide; or work with the internal value of a Date Object.

Note that `new Date(D)` where D is a Date Object is not
reliable for years before A.D. 100. If `D` is known to be a
Date Object, use `+D` which will also often be quicker.

For differencing, Standard Time Zone (but not offset change) can be ignored. The UNIX Epoch date is a Thursday; adding three to put the base at the start of a week can be useful.

Tests - all days in :
(slow)
Use Back to return.

Lines should end 0 0 1.

Again, remember Summer Time and Time Zone; days are not all the same length. Do not attempt date shifting in time units, or month/year shifting in days; direct functions are provided.

Any attempt to deal with civil days by using milliseconds is pure folly - though JavaScript GMT/UTC days should be constant in length (being specified (ECMA-262 3rd Edn Sec 15.9.1.1) as having no Leap Seconds).

**Note :** The clock change, Spring and Autumn, can
occur on the 31st of the month; so, for example, 86400 seconds before
April 1st can be late in March 30th (*e.g.* EU, one year in 7)
instead of being the last day of March.

Set as many components as possible in a single method call (the optional parameters were introduced in JavaScript 1.3)

setFullYear(yearValue[, monthValue, dayValue]) setMonth(monthValue[, dayValue]) setDate(dayValue) setHours(hoursValue[, minutesValue, secondsValue, msValue]) setMinutes(minutesValue[, secondsValue, msValue]) setSeconds(secondsValue[, msValue]) setMilliseconds(msValue)

Use such as

which always give the present civil time tomorrow (strictly, there is one hour in Spring during which this is not possible, for places with Summer Time); as usual, month and year will be changed if necessary.

For tomorrow (maybe to see if today is the end of the month) :-

Note that incrementing/decrementing in Months can, in the first instance, get to the 29th, 30th or 31st of a month that does not have that date; in that case, the Object enters the following month, which may or may not be appropriate (see also 0: Date Object Information).

Starting with January 31st of successive years, that correctly gives for leap years Feb 29th, else Feb 28th. Similarly for altering the Year and avoiding a non-existent Feb 29th.

To step continuously along month-ends, step the beginnings of each following month, and go back one day each time.

Once more, remember Summer Time and Time Zone.

One must decide whether the difference is to use days each of 24 hours, or is to use days of local time.

Mere comparison is easy (apart from the autumnal ambiguous hour); compare the fields in order of diminishing significance, and return at the first difference; or use Date objects and compare their values.

To determine whether one date is within a given number of days of another, it may be easier or safer to increment/decrement one of the dates and then compare the result with the other date than it is to work by subtraction.

If Date Objects are provided, one must consider possible effects of their time components on comparisons.

Note : In Opera 9.2x, `new Date("Y/M/D")` gives `NaN`
for `Y` after 9999.

See in datefmts for ISO 8601.

The above function is used in the code below.

For the difference of dates in days, set the local dates into date objects, subtract the values, divide by 864e5, and then round to integer; this should accommodate Summer Time transitions.

Alternatively, set the dates as GMT into date objects or
use `Date.UTC`.

Depending on your definition of "between", perhaps increment or decrement the result.

A difference in days, whether or not accompanied by months and/or
years, can readily be converted to weeks and days :- `W =
(D-(D%=7))/7` ; think about needs for `D<0` . To
reverse, `D += 7*W` .

Difference in Years, Months and Days is somewhat arbitrary, as years and months vary in length.

See also Thirty-Day Months in JavaScript Date and Time 3 : Input and Lengths and Date Miscellany II.

If avoidable (it may be needed for formal administrative purposes), do not attempt to subtract date/time in Y-M-D h:m:s; all that borrowing is tiresome and error-prone. Think about the exact requirements; check management expectations and needs. For people's ages, however, it seems often necessary to work in Y-M-D, with care.

Since there are always 12 months in a year, one can for simplicity work with M' = 12×Y+M; and for subtraction one can ignore month numbers being 1..12 rather than 0..11. Similarly, hh:mm:ss can be converted to seconds, if Summer Time transitions are ignored.

Frequently, either the initial or the final date will be fixed, and the other will be the current date.

A sequence of differences is obtained by keeping one date fixed and stepping the other date by one day at a time.

A sequence of differences should always look plausible. Requirements include :-

- when Y, M, D match, the result must be 0, 0, 0
- when M, D match, the result must be dY, 0, 0
- when D matches, the result must be dY, dM, 0
- when either date shifts by one day, the days part of the result usually changes by one, or jumps between 0 and 27/28/29/30.

I doubt whether all of those can be achieved at once!

Consider Apr 4 to May 6 must be one month and two days; also May 4 to Jun 6. Step the start daily to May 4; 30 steps, as Apr has 30 days. Step the close daily to Jun 6; 31 steps, as May has 31 days. Thus there cannot be a 1:1 correspondence between the two sets of intermediate differences; there must be an omission or a repeat.

Consider Apr 4 to Jun 3; 1 month gets to May 4, then -4+31+3 = 30 days. Jun 3 back to Apr 4; 1 month gets to May 3, then +3+30-4 = 29 days. In the first case the "borrow" is of May, in the second it is of April.

First convert BC dates to astronomer's notation, in which years go ... -2 -1 0 +1 +2 ... ; and, if necessary, consider past calendar reforms. The following uses only Gregorian AD dates.

Convert the years and months to just months, and subtract. Subtract the dates; if negative, first "borrow" the length in days of an appropriate month, with allowance for its year if it is February. Convert months back to years and months.

**Increasing Interval** - Borrow from the month before the
moving date, as Feb 01 == Jan 32.
**Decreasing Interval** - Borrow from the month with the
moving date, as Feb 00 == Jan 31.

Note that with inputs of 2001-03-01 & 2001-01-30 the result that DiffDateC gives is 0,1,-1 and one may wish to put a lower bound of 0 on the Days, or borrow two months.

Another way would be to determine the difference in days, divide by 365.25/12 or 365.2425/12 and round down to get integer months, after which the rest is simple.

However, that makes the effects of varying month- and year- lengths rather conspicuous.

This has some of the problems of Difference in Years, Months and Days.

It is tricky, in respect of February 29th :-

For the difference in years alone :-

Non-optimal code :-

Remember, though, Summer Time, and those born on February 29th.

Again, remember Summer Time and location.

One can subtract seconds; if negative, borrow a minute; then subtract minutes, etc.

If days, hours, minutes, seconds are needed, then set the
start and finish date/times into a date object (`new Date()`
creates an object for the current date/time), and take
`valueOf()` for each, and subtract these to get the difference in
milliseconds. If only times are given, use a dummy date, *e.g.*
`T = "12:34:56" ; D = new Date("1/1/70 "+T)` ,
possibly appending UTC.

Or, for start and finish, multiply days by 24, add hours, multiply by 60, add minutes, multiply by 60, add seconds; and subtract.

After subtracting, use Mod & Div to convert to days .. seconds :-

a mod b = a % b a div b = Math.floor(a/b) = (a-(a%b))/b //may need Math.roundSec = ms div 1000 // ms = ms mod 1000 Min = Sec div 60 ; Sec = Sec mod 60 Hr = Min div 60 ; Min = Min mod 60 Days = Hr div 24 ; Hr = Hr mod 24

It normally does not make a great deal of sense to convert time differences from days to months and years, which are of variable lengths.