It seems unlikely that this page will work in many browsers other than MSIE.
Its methods can be used in Windows Scripting Host and in other applications.
VBScript is invoked (with Option Explicit) as the first scripting on this page → ←.
Analogous code, and more, can be found via JavaScript Date and Time.
VBScript days are numbered Sun=1 to Sat=7 (by default). ISO 8601 specifies Mon=1 to Sun=7, for which use WeekDay(D, 2).
Note that the Day-of-Week can always be determined as (DC+X) mod 7 + Y where DC is any daycount and X in 0..6 and Y in 0,1 depend on the day numberings.
Next Monday is seven days ahead, less 0..6 days depending on the current Day Number.
D = Date : D = D + 7 - (D+5) mod 7 '' Next Monday document.write D
DatePart("ww", D) ' Weeks Sun..Sat, Week 1 usually partial
Given what follows, I'd check even that rather carefully before using it.
By ISO 8601, every week has seven days, numbered Monday=1 to Sunday=7. The first Thursday of a Gregorian Calendar Year has Week Number 01 of that Year Number, and weeks are numbered 01 to 52 or 53. A week numbering date should be written yyyy-Www-d.
This firstly, using function YearWeekDay(Y, M, D), gives the correct ISO 8601:2004 Year, Week and Day Numbers of a date, as a string yyyy-Www-d, and secondly, using function YearMonthDay(YWD), converts the (editable) YWD string to a CDate for display :-
To see my code, use View Source. Only basic date functions are used; the result does not depend on what the authors of VBScript think Week Numbers should be.
For a discussion of appropriate algorithms, see Week Calculation, including Week Number to/from DayCount.
For ISO 8601 YYYY-WW, start at WW-1 weeks after YYYY-Jan-01, then move by ±3 days to the nearest Monday.
YYYY = 2004 : WW = 44 D = DateSerial(YYYY, 1, 1+7*(WW-1)) document.write D + 3 - (D+1) mod 7
Note that the corresponding Year Number is also needed; it can differ from that of the Calendar Year, and there seems to be no direct provision for that. So if December and WN=1 then increment the year; and if January and WN≥52 then decrement the year.
I understand that VBScript and WSH share a DLL to provide the script engine; therefore they should behave in the same way.
PowerShell may have an equivalent indicated by Get-Date "12/31/2007" -uFormat %V with the same flaw. It also has Calendar.GetWeekOfYear(), apparently defective.
NEW 2007-03-27
I've discovered today that Microsoft have known some of the following for years! Web page BUG: Format or DatePart Functions Can Return Wrong Week Number for Last Monday in Year Article ID : 200299 / Last Review : June 24, 2004 / Revision : 3.0 refers - but only to the error which occurs three times per 28 years.
Their workaround Function WeekNumber seems unduly long and slow.
P.S. 2007-08-21 : Windows Script 5.7, recently released, has the same behaviour as before.
P.S. 2010-02- : So does Windows Script 5.8 (in WinXP sp3?, Windows 7).
VBS DatePart Week Number errors occur in WSH and in MSIE 4, 6, 7, 8, when using function DatePart(,"ww",,). They have been seen in Windows 95, 98, 2000, XP, Vista, and Windows 7. They have been seen in WSH 5.1, 5.6, and 5.8. One type occurs three times per 28 years, another once per 400 years. Those whose browsers do not have VBScript enabled can see a list below in WSH VBS WN Error.
MS TechNet - DatePart : Retrieving Specific Portions of a Date and Time Value, used to imply that the following source line was intended to, or should, give an ISO 8601 Week Number.
W = DatePart("ww", CDate("Dec 29 2003"), vbMonday, vbFirstFourDays)
If so, DatePart is buggy in systems which I have tried, and in Vista and Windows 7.
MS DatePart Function (Visual Basic) does claim compliance with ISO 8601.
The presence of a discrepancy for those parameters suggests that there may well be errors with other combinations of parameters.
Using that code line,
I have VBScript Version 5.8, build 18702 or later.
Below, yyyy-Www-d shows the correct Week Number and WN uses the DatePart of your browser.
The first test should be extended to all 14 types of year, at least; I find one similar error per few years. The second tests only Day 1 of Week 1, for a cycle of year-types.
There are errors for 2003-12-29, 2007-12-31, and 2019-12-30, in IE4, IE6, IE7 & IE8 - intervals 4, 12, 12 years recurring, except across missing Leap Years.
It is reported that Vista and Windows 7 do the same.
Function DoFix tests function WeekNumber from "Workarounds" in the MS BUG page, but slightly adapted for VBScript.
Their workaround code looks, and is, slower than my code.
This detects non-Mondays for which WN does not equal that of the day before (cf. in Windows Scripting Host).
WScript.echo getRuntimeInfo() '' More or less as in source of this page WScript.echo " Date DoW WN XWN" XWN = 52 for CD = #1/1/2000# to #1/1/2200# WN = DatePart("ww", CD, vbMonday, vbFirstFourDays) WD = WeekDayName(Weekday(CD), true) if (WD<>"Mon") and (WN<>XWN) then _ WScript.echo CD, " ", WD, " ", Right(WN+100, 2), " ", XWN XWN = WN Next
With the above being in file.vbs, this shows output copied from a "Command Prompt" screen of WinXP sp2, following command CSCRIPT //nologo file.vbs. :-
VBScript Version 5.6.8820 Date DoW WN XWN 2003-12-30 Tue 01 53 2008-01-01 Tue 01 53 2019-12-31 Tue 01 53 2031-12-30 Tue 01 53 2036-01-01 Tue 01 53 2047-12-31 Tue 01 53 2059-12-30 Tue 01 53 2064-01-01 Tue 01 53 2075-12-31 Tue 01 53 2087-12-30 Tue 01 53 2092-01-01 Tue 01 53 2101-01-02 Sun 53 52 2104-01-01 Tue 01 53 2115-12-31 Tue 01 53 2127-12-30 Tue 01 53 2132-01-01 Tue 01 53 2143-12-31 Tue 01 53 2155-12-30 Tue 01 53 2160-01-01 Tue 01 53 2171-12-31 Tue 01 53 2183-12-30 Tue 01 53 2188-01-01 Tue 01 53 2199-12-31 Tue 01 53
That revised test now also shows the 2101 error.
There is also WSH VBS test code in Windows Scripting Host, under "Behaviour in DatePart".
Sub wn() MsgBox _ DatePart("ww", #12/30/2007#, vbMonday, vbFirstFourDays) & " " & _ DatePart("ww", #12/31/2007#, vbMonday, vbFirstFourDays) & " " & _ DatePart("ww", #1/1/2008#, vbMonday, vbFirstFourDays) End Sub
That, as a MS Office 2003 Word Macro, shows 52 53 1 , indicating that the same happens in Word. Likewise in Excel; and, I suppose, also in other parts of Office.
With a similar definition,
For Weekday differences, taking Weekdays as being Mon-Fri, subtract absolute weekday counts (see source). These should start with an arbitrary early Monday being Weekday 0; 1900-01-01 seems suitable :-
Weekdays Difference is now just the difference in WDC; Weekdays Ahead requires CDW, the inverse function to WDC.
Use a similar approach, allowing for holidays/time.
There is no need to include a month-length table, or leap-year rules; type CDate can do all that.
If Year and Month are known, Day(DateSerial(Yr, Mn+1, 0)) .
If a Date variable within the month is known :-
function LoM(ByVal D) '' Length of Month containing Date D LoM = 32 - Day(D-Day(D)+32) end function for KK = 1 to 15 : D0 = DateSerial(2004, KK, 17) document.write "<br> ", D0, " ", LoM(D0) : next
The last SomeDay of a month is invariably seven days before a SomeDay whose day-of-month number is less than 8. Testing for the last Sunday of the current month :-
F = Int(GNow) + 7 : OK = Weekday(F)=1 and Day(F)<8 document.write " Date+7 : ", F, "; DayOfWeek : ", Weekday(F), _ "; DayOfMonth : ", Day(F), "; OK : ", Cstr(OK)
For the last-but-one, add 14, etc.; for the third, subtract 14, etc.
To test whether the date is within the N'th week of the month, omit the Weekday test.
For the final Tuesday of next month :-
document.write "New Method : " W = DateSerial(Year(GNow), Month(GNow)+2, 1) '' Two months ahead D = W - 1 - (WeekDay(W)+3) mod 7 '' 3=Tue, Back off, answer as a Date document.write Day(D), " ", Ucase(MonthName(Month(D),1)), " ", Year(D)
More generally, the following gives the N'th SomeDay (Sun=1 .. Sat=7) of the month A months Away; A can be zero or negative. Note that the last SomeDay of A is the zeroth of A+1.
To step D, the first X-day of a month, add 35 days to D, and if the day-of-month is greater than 7 then go back a week.
To step D, the last X-day of a month, which is the zeroth of the next month, set NM = Month(D) mod 12 + 1, D = D + 35, and if Month(D)<>NM then D = D - 7.
For other days, step the first or last X-day, and offset the result by weeks.
Events don't get scheduled for the 5th X-day of a month.
ISO - Multi- nationalised Terminology? |
To exceed VBScript's limited date range, adjust the year used for calculation by a multiple of 400 into the range 2000-2399.
Check the Day of Feb 29, which will be Feb 29 or Mar 1. But (Year and 3) = 0 suffices until 2100.
Functions for the date of Easter Sunday :-
The Gregorian Easter pattern repeats after 5,700,000 years.
To convert Day-of-March to CDate, use DateSerial(YR, 3, DoM).
Subroutine Pascha was largely taken from a News post of the last third of May 2003; partly tested by me. It gives Julian Easter before 1583, otherwise Gregorian. (window.status shows progress, if enabled.)
Function ZEG1885 was adapted from the corresponding JavaScript function; see via The Calendrical Works of Rektor Chr. Zeller : The Day-of-Week and Easter, and seems likely to be fast.
Function BCPEaster was adapted from The Calculation of Easter Sunday from the Book of Common Prayer; it is valid for 1900-2199 only.
Function JRSEaster was adapted from the full routine in The Calculation of Easter Sunday from the Book of Common Prayer.
Function CPnEaster was adapted from an Excel routine in Holidays by Pearson Software Consulting, LLC; it is valid for 1900-2099 only.
There is spreadsheet Easter material in PCW March 2006 pp.152-3, which I may look into; though BCPEaster seems better.
BCPEaster is fully traceable, and JRSEaster is virtually traceable, through the Book of Common Prayer of the Church of England to the Calendar (New Style) Act (1750 c. 23) (but see Pages Annexed to the Calendar Act about the UK Statute Law Database).
Zeller is known to be reliable.
Pascha is a recognised algorithm.
In the March 2006 issue of (UK) Personal Computer World (PCW), pages 152-3, there is code for Easter Sunday said to work in Excel from 1900 to 2058. Tested in this page in MS IE4, IE6 & IE7, and with command-prompt CScript, the code agrees with mine for the full CDate range 0100-9999. In fact, it seems full-range in Excel too.
window.status shows progress, if enabled.
For Last Modified in general, including the transmitted format, see in JavaScript Date and Time 2 : Demonstrations; the HTTP header is fully unambiguous, and uses explicit GMT. JavaScript page Test Page for JavaScript lastModified will LATER show reading the HTTP header by an XMLHttpRequest call.
In some systems, such as my Win98/MSIE4 and WinXP/MSIE6 VBScript, the document.LastModified string is in an alien format, and would be misleading if displayed as a string.
The string gives (as far as I've seen) no indication of the zone of the time; my MSIE4 gave GMT, and an IE6 (SP1) in Indianapolis (UTC-5) gave local time.
For this Web page, document.LastModified represents the time of upload to the server, by the server's clock.
Its possible formats are too various for my previous approach to be tenable.
I now postulate that it is always a string LM that can be read correctly, including the century, by CDate(LM) .
That will fail if a 2-digit year is incorrectly windowed.
It would also fail if LastModified were M/D/Y and preference of D/M/Y was honoured, or vice versa.
I also postulate that it will usually be in Local Time.
To determine your Time Zone Offset, see in VBScript Date and Time 1. To determine my time, which is GMT or GMT+1, see Summer Time.
This is from JavaScript, which sets NowOffset :-
and the rest is VBScript :-
Compare that with the date at the head of this page, which is the UK Civil Date of editing the master copy.
I can only properly test the offset from GMT during UK Summer Time.
If this section has given a Script Error or other fault, please send me details.
Viewed locally, without HTTP, the VBScript string in my system is in GMT. The time zone of the string should be considered uncertain.
Results shown locally may differ in nature from those shown over the Web. To be continued ... ?