Mega Code Archive

 
Categories / Delphi / Examples
 

Calendardates

THREE DIFFERENT EXAMPLES OF CODE TO PLAY WITH CALENDAR DATES (eg first monday in month etc) -THE 2ND AND 3RD EXAMPLES LOOK GOOD. see also Data&Time.txt **************************************************************************** For those who want a shorter Last Day of the Month routine. [Than everything below!] EncodeDate(year, month, MonthDays[IsLeapYear(year), month]); MonthDays and IsLeapYear are defined in SysUtils ***************************************************************************** Here's some code I wrote to find the first, second, third, and fourth Monday of the month. I'm sure you can easily adapt it for other days. var i, vday: integer; vstartdate,vmonday:tdatetime; if CBfreq.text='MONTHLY1' then begin for i:= 1 to 8 do begin vstartdate:=vstartdate-day(vstartdate)+1; vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); //I populate a combo box with a series of first Mondays vstartdate:=changemonth(vstartdate,1); end; //for end;//monthly if CBfreq.text='MONTHLY2' then begin for i:= 1 to 8 do begin vstartdate:=vstartdate-day(vstartdate)+1; vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; vmonday:=vmonday+7; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); vstartdate:=changemonth(vstartdate,1); end; //for end;//monthly 2nd Monday if CBfreq.text='MONTHLY3' then begin vstartdate:=vstartdate-day(vstartdate)+1; for i:= 1 to 8 do begin vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; vmonday:=vmonday+14; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); vstartdate:=changemonth(vstartdate,1); end;//for i end;//month3 if CBfreq.text='MONTHLY4' then begin for i:= 1 to 8 do begin vstartdate:=vstartdate-day(vstartdate)+1; vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; vmonday:=vmonday+21; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); vstartdate:=changemonth(vstartdate,1); end; //for end;//monthly 4th Monday if CBfreq.text='BI-MONTHLY' then begin for i:= 1 to 8 do begin vstartdate:=vstartdate-day(vstartdate)+1; vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); vstartdate:=changemonth(vstartdate,2); end; //for end;//bi-monthly if CBfreq.text='TRI-MONTHLY' then begin for i:= 1 to 8 do begin vstartdate:=vstartdate-day(vstartdate)+1; vday:=dayofweek(vstartdate); if vday=1 then vmonday:=vstartdate+1; if vday=2 then vmonday:=vstartdate; if vday=3 then vmonday:=vstartdate+6; if vday=4 then vmonday:=vstartdate+5; if vday=5 then vmonday:=vstartdate+4; if vday=6 then vmonday:=vstartdate+3; if vday=7 then vmonday:=vstartdate+2; if vmonday>=date then CBnext.items.add(datetostr(vmonday)); vstartdate:=changemonth(vstartdate,3); end; //for end;//tri-monthly end; //if _______________________________________________ Delphi mailing list -> Delphi@elists.org http://www.elists.org/mailman/listinfo/delphi ****************************************************************************** The following is from our ESBPCS: type TESBDOMType = (domFirst, domSecond, domThird, domFourth, domLast); {: Returns the Given Occurrence (Day of Month) of a Day of Week in a given Month/Year. Thus can be used to find the first Wednesday, Last Monday, etc. DOMType can be one of the following:<p> domFirst - First occurrence in a Month.<p> domSecond - Second occurrence in a Month.<p> domThird - Third occurrence in a Month.<p> domFourth - Fourth occurrence in a Month.<p> domLast - Last occurrence in a Month. @param DOMType the desired Day of Month Type. @param DOW the Day of Week, 1 = Sunday, 7 = Saturady. @param Month the month of the year, 1 = Jan, 12 = Dec. @param Year 4-digit year such as 1999. @returns the Date uniquely defined by the above. @cat DTMath @cat MonthMath } function DayOfMonth2Date (const DOMType: TESBDOMType; const DOW: Byte; const Month, Year: Word): TDateTime; var Ofs: Integer; DT: TDateTime; begin if DOMType < domLast then begin DT := GetFirstDayOfMonth (Month, Year); Ofs := DOW - DayOfWeek (DT); if Ofs < 0 then Ofs := Ofs + 7; Result := DT + Ofs + 7 * Integer (DOMType); end else begin DT := GetLastDayOfMonth (Month, Year); Ofs := DayofWeek (DT) - DOW; if Ofs < 0 then Ofs := Ofs + 7; Result := DT - Ofs; end; end; You will need routines to return the First and Last Days of the Month/Year for the above... You may also want to check out our FREE ESBDates which also includes GPTimeZone which includes another way of doing the above :) HTH Glenn Crouch mailto:glenn@esbconsult.com.au ICQ:36017076 ESB Consultancy, http://www.esbconsult.com.au Home of ESBPCS, ESBStats, ESBPDF Analysis & ESBCalc Kalgoorlie-Boulder, Western Australia (TeamND, TeamOE, Addict Support, eLists.org Management) ******************************************************************************** unit RelDate; interface uses Controls; type TDayOfWeek = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday); function RelativeDate(Date: TDate; WeekDay: TDayOfWeek; Which: integer): TDate; implementation uses SysUtils; function FindDay(Date: TDate; WeekDay: TDayOfWeek; Delta: integer): TDate; var Count: longint; begin Count := Trunc(Date) + Delta; Result := (Count - ((Count - Ord(WeekDay) + 6) mod 7)) * 1.0; end; function RelativeDate(Date: TDate; WeekDay: TDayOfWeek; Which: integer): TDate; {e.g. RelativeDate(Now, Wednesday, 1) will find the first Wednesday in the current month RelativeDate(Now, Sunday, -1) will find the last Sunday in the current month RelativeDate(Now, Monday, -2) will find the penultimate Monday in the current month } var Year, Month, Day: word; Count: longint; Delta: shortint; begin DecodeDate(Date, Year, Month, Day); if Which > 0 then begin Count := Trunc(Date) - Day + 7; Delta := -1; end else begin Count := Trunc(Date) - Day + MonthDays[IsLeapYear(Year), Month]; Delta := 1; end; Result := (FindDay(Count * 1.0, WeekDay, 0) + ((Which + Delta) * 7)) * 1.0; end; end. Regards, Russell Hewitt *************************************************************************** Glenn Crouch - ESB wrote: > > function GetLastDayOfMonth(Mo, Yr: Word): TDateTime; > > begin > > // find first day of subsequent month and subtract a day > > Result := EncodeDate(Yr, Mo + 1, 1) - 1.0; > > end; > > Not good option for December (Mo = 12) ... But basically yes :) Ooops, good point, seems like I always miss those wrap-around situations, how about: function GetLastDayOfMonth(Mo, Yr: Word): TDateTime; var TempYr, TempMo: Word; begin // find first day of subsequent month and subtract a day TempYr := Yr; TempMo := Mo + 1; if TempMo = 13 then begin // Whoa Nellie, next month is next year! TempMo := 1; // January Inc(TempYr); // subsequent year end; Result := EncodeDate(TempYr, TempMo, 1) - 1.0; end; Thanks for catching that! ;-) Of course an even more robust solution would check that Mo was in the range 1..12 to begin with, which I haven't done. What is a sensible "bad date" value to return on an error like that? Since TDateTime is a type alias for an IEEE double, one could use NaN I guess? Stephen Posey slposey@concentric.net ******************************************************* Glenn Crouch - ESB wrote: > > The following is from our ESBPCS: Interesting, I note that your definition only implicitly includes the fifth occurence of a day via the domLast value; there's no way to explicitly ask for the 5th occurence and perhaps get some kind of exception or an error value back indicating that it doesn't exist, you'd have to ask for both domFourth and domLast and check whether they were the same. E.g. for January 2001: DayOfMonth2Date(domFourth, 4, 1, 2001) will return Jan. 24 DayOfMonth2Date(domLast, 4, 1, 2001) will return Jan. 31 but DayOfMonth2Date(domFourth, 5, 1, 2001) and DayOfMonth2Date(domLast, 5, 1, 2001) will both return Jan. 25 > type > TESBDOMType = (domFirst, domSecond, domThird, domFourth, domLast); > > {: Returns the Given Occurrence (Day of Month) of a Day of Week in a given > Month/Year. Thus can be used to find the first Wednesday, Last Monday, > etc. DOMType can be one of the following:<p> > domFirst - First occurrence in a Month.<p> > domSecond - Second occurrence in a Month.<p> > domThird - Third occurrence in a Month.<p> > domFourth - Fourth occurrence in a Month.<p> > domLast - Last occurrence in a Month. > > @param DOMType the desired Day of Month Type. > @param DOW the Day of Week, 1 = Sunday, 7 = Saturady. > @param Month the month of the year, 1 = Jan, 12 = Dec. > @param Year 4-digit year such as 1999. > @returns the Date uniquely defined by the above. > @cat DTMath > @cat MonthMath > } > function DayOfMonth2Date (const DOMType: TESBDOMType; const DOW: Byte; > const Month, Year: Word): TDateTime; > var > Ofs: Integer; > DT: TDateTime; > begin > if DOMType < domLast then > begin > DT := GetFirstDayOfMonth (Month, Year); > Ofs := DOW - DayOfWeek (DT); > if Ofs < 0 then > Ofs := Ofs + 7; > Result := DT + Ofs + 7 * Integer (DOMType); > end > else > begin > DT := GetLastDayOfMonth (Month, Year); > Ofs := DayofWeek (DT) - DOW; > if Ofs < 0 then > Ofs := Ofs + 7; > Result := DT - Ofs; > end; > end; Hmmmm, is all the ESB code formatted like this? Or is what I'm seeing an artifact of tab conversion in the Email stream somewhere? > You will need routines to return the First and Last Days of the Month/Year > for the above... That's easy enough: function GetFirstDayOfMonth(Mo, Yr: Word): TDateTime; begin // find first day of month Result := EncodeDate(Yr, Mo, 1); end; function GetLastDayOfMonth(Mo, Yr: Word): TDateTime; begin // find first day of subsequent month and subtract a day Result := EncodeDate(Yr, Mo + 1, 1) - 1.0; end;