Log On
Embarcadero Home
QualityCentral
Communities
Articles
Blogs
Resources
Downloads
Help
Quality Central
Delphi-BCB
RTL
Delphi
Arithmetic
ConvUtils
Date - Time
DateUtils
File Management
Format + Float
Input/Output
Math Unit
Memory, Pointer, Address
Null-terminated strings
Other Classes
Other RTL
Pascal Strings
RTL Exceptions
Text Files
Thread support
Typed/Untyped Files
WinAPI
You are not logged in.
Help
Print
Public Report
Report From:
Delphi-BCB/RTL/Delphi/DateUtils
[ Add a report in this area ]
Report #:
57477
Status:
Open
WeekOfTheYear returns wrong week given any non-zero time on any Monday before 1899-12-26.
Project:
Delphi
Build #:
11.0.2902.10471
Version:
11.1
Submitted By:
John Herbster
Report Type:
Basic functionality failure
Date Reported:
1/26/2008 1:26:39 PM
Severity:
Infrequently encountered problem
Last Updated:
1/30/2008 4:25:23 PM
Platform:
All platforms
Internal Tracking #:
257402
Resolution:
None
(Resolution Comments)
Resolved in Build:
:
None
Duplicate of:
None
Voting and Rating
Overall Rating:
No Ratings Yet
0.00 out of 5
Total Votes:
None
Description
DateUtils.WeekOfTheYear returns wrong week number if time is non-zero and day is any Monday before 1899-12-26.
WeekOfTheYear is for ISO 8601 weeks. See Delphi Help and
http://en.wikipedia.org/wiki/ISO_8601>
and
http://en.wikipedia.org/wiki/ISO_week_date
Here are the D7, Build 8.1 results, using the program in Steps:
DT yyyy-mm-dd hh:nn DoW WoY
-6.50 1899-12-24 12:00 Sun 51
-5.00 1899-12-25 00:00 Mon 52
-5.25 1899-12-25 06:00 Mon 51 <== ERROR
-5.50 1899-12-25 12:00 Mon 51 <== ERROR
-5.75 1899-12-25 18:00 Mon 51 <== ERROR
-4.00 1899-12-26 00:00 Tue 52
where WoY is the returned WeekOfTheYear.
The following versions
BDS2006 10.0.2558.35231
CRS2007 Delphi Win32 11.0.2902.10471 (December update)
also give the error.
I am reporting this for Dr. John Stockton:
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v6.05 IE 6
news:comp.lang.javascript FAQ <URL:http://www.jibbering.com/faq/index.html>.
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
.
My thanks to Paul Scott and Pieter Zijlstra for helping to verify the problem still exists.
JohnH, 2008-01-26
Steps to Reproduce:
On a form with a TButton and a TMemo, add the following OnClick handler and run it.
procedure TForm1.Button1Click(Sender: TObject);
{sub}procedure DoTest(DT: TDateTime);
var WoY: word; S, DoW: string;
const DayAbbrs: array [1..7] of string[3] =
('Mon','Tue','Wed','Thr','Fri','Sat','Sun');
begin
S := SysUtils.FormatDateTime('yyyy-mm-dd hh:nn',DT);
DoW := DayAbbrs[DateUtils.DayOfTheWeek(DT)];
WoY := DateUtils.WeekOfTheYear(DT);
Memo1.Lines.Add(Format(' %F %S %S %D',[DT,S,DoW,WoY]));
end;
begin
Memo1.Lines.Add(' DT yyyy-mm-dd hh:nn DoW WoY');
DoTest(-6.50);
DoTest(-5.00);
DoTest(-5.25);
DoTest(-5.50);
DoTest(-5.75);
DoTest(-4.00);
end;
Workarounds
WeekOfTheYear(DT) is sometimes wrong, but not if the value of DT is integer. So WeekOfTheYear(Trunc(DT)) should be right.
--JohnH for JRS.
Attachment
None
Comments
John Herbster at 1/30/2008 4:07:29 PM
-
Here are the routines recommended by Dr. John Stockton
For latest copy see
<http://www.merlyn.demon.co.uk/programs/del_wkno.pas> *
<http://www.merlyn.demon.co.uk/programs/sub_woty.pas>
* May need to add 'uses' whatever unit WeekOfTheYear lives in ?
--
John Stockton
www.merlyn.demon.co.uk/
////// RECOMMENDED ROUTINES
// 2008-01-17 - I derived the following routines from ISO principles
// The "canonical" are directly derived, whence FASTER are optimised
// All ISO weeks have 7 days, DN being Monday = 1 to Sunday = 7
// The ISO YN and WN of any Date are those of its nearest Thursday
// Weeks are numbered 01 to 52/53, week-dates written like YN-wWN-DN
// Definition: Week 01 of YN has the first Thursday of Calendar Year YN
// Therefore, Year January 4th of Y is in Week 01 of YN = Year
// Up to >= 2008-01-26, the FASTER versions have been getting faster
// Round is faster than Trunc
{$DEFINE FASTER} // or not, for which put a space before the $
{$IFDEF FASTER}
function DTofJan1(Yr : word) : TDateTime ;
// This is faster than EncodeDate, since it does not consider M & D
const Base = 2 - 1899*365 - 1899 div 4 + 1899 div 100 - 1899 div 400 ;
begin Dec(Yr) ;
Result := Base + Yr*365 + Yr div 4 - Yr div 100 + Yr div 400 ;
end {DTofJan1} ;
procedure ISODTtoYWD(const DT : TDateTime ; out YN, WN, DN : word) ;
var NThu : TDateTime ; TDT : integer ;
begin // The fast non-canonical version. 1899.5 seems near optimum.
TDT := Trunc(DT) ;
DN := (TDT+7777775) mod 7 + 1 { DT : Mon=1 to Sun=7 } ;
NThu := TDT + 4 - DN { NThu is the Nearest Thursday } ;
YN := Round(1899.5 + NThu/365.2425) { estimated Year Number } ;
if NThu < DTofJan1(YN) then Dec(YN) { corrected Year Number } ;
WN := 1 + Trunc(NThu-DTofJan1(YN)) div 7 { Count of Thursdays } ;
end {ISODTtoYWD} ; // Ideally, this would be a pure function
function ISOYWDtoDT(const YN, WN, DN : word) : TDateTime ;
var DT : TDateTime ; DW : integer ;
begin // The fast non-canonical version.
DT := DTofJan1(YN) + 3 { YN Jan 4, which is in YN Week 1 } ;
DW := (Round(DT)+7777775) mod 7 + 1 { DT : Mon=1 to Sun=7 } ;
DT := DT - DW { DT to day before Week 1 } ;
Result := DT + (WN-1)*7 + DN { increment for Weeks and Days } ;
end {ISOYWDtoDT} ;
{$ELSE}
procedure ISODTtoYWD(const DT : TDateTime ; out YN, WN, DN : word) ;
var X : word ; NThu, Jan1 : TDateTime ;
begin // The canonical version.
DN := 1 + (DayOfWeek(DT)+5) mod 7 { DT : Mon=1 to Sun=7 } ;
NThu := Trunc(DT) + 4 - DN { NThu is the Nearest Thursday } ;
DecodeDate(NThu, YN, X, X) { get Year Number of NThu } ;
Jan1 := EncodeDate(YN, 1, 1) { January 1 of YN } ;
WN := 1 + Trunc(NThu-Jan1) div 7 { Count of Thursdays } ;
end {ISODTtoYWD} ; // Ideally, this would be a pure function
function ISOYWDtoDT(const YN, WN, DN : word) : TDateTime ;
var DT : TDateTime ; DW : integer ;
begin // The canonical version.
DT := EncodeDate(YN, 1, 4) { YN Jan 4, which is in YN Week 1 } ;
DW := 1 + (DayOfWeek(DT)+5) mod 7 { DT : Mon=1 to Sun=7 } ;
DT := DT - DW { DT to day before Week 1 } ;
Result := DT + (WN-1)*7 + DN { increment for Weeks and Days } ;
end {ISOYWDtoDT} ;
{$ENDIF}
////// END RECOMMENDED ROUTINES
View Your Reports
Search
Server Response from: CODE1
Developer Tools
Blackfish SQL
C++Builder
Delphi
Delphi for PHP
Delphi Prism
InterBase
JBuilder
J Optimizer
3rdRail & TurboRuby
Database Tools
Change Manager
DBArtisan
DB Optimizer
ER/Studio
Performance Center
Rapid SQL
Technical Articles
Tutorials
White Papers
Press Releases
Newsletters
Add Content (GetPublished)
Audio
Audio & Video
Video
Bugs & Suggestions (QualityCentral)
Discussion Forums
Examples (CodeCentral)
Tags
Technology Partners
Downloads
Free Trials
Registered User Downloads
Beta Programs
Add Content (GetPublished)
Articles
Blogs
Bugs & Suggestions (QualityCentral)
Chats
Discussion Forums
Examples (CodeCentral)
Member Services
About