1##########################################################################
2#
3#	File:	Project/Gantt/DateUtils.pm
4#
5#	Author:	Alexander Westholm
6#
7#	Purpose: Collection of utility functions for manipulating
8#		Class::Date objects. Contains functions for getting the
9#		number of hours/days/months between two dates, getting
10#		the end and beginning of hours/days/months, and looking
11#		up the string name of a day of the week or month.
12#
13#	Client: CPAN
14#
15#	CVS: $Id: DateUtils.pm,v 1.4 2004/08/03 17:56:52 awestholm Exp $
16#
17##########################################################################
18package Project::Gantt::DateUtils;
19use strict;
20use warnings;
21use Exporter ();
22use vars qw[@EXPORT_OK %EXPORT_TAGS @ISA];
23
24@ISA	= qw[Exporter];
25
26@EXPORT_OK = qw[hourBegin
27		hourEnd
28		dayBegin
29		dayEnd
30		monthBegin
31		monthEnd
32		getMonth
33		getDay
34		monthsBetween
35		hoursBetween
36		daysBetween
37	];
38
39%EXPORT_TAGS = (
40	compare		=>	[qw(
41				monthsBetween
42				daysBetween
43				hoursBetween)],
44	round		=>	[qw(
45				hourEnd
46				hourBegin
47				dayEnd
48				dayBegin
49				monthEnd
50				monthBegin)],
51	lookup		=>	[qw(
52				getDay
53				getMonth)] );
54
55##########################################################################
56#
57#	Function: monthsBetween(date1, date2)
58#
59#	Purpose: Calculates the number of months spanned by two dates.
60#		This is inclusive of the rest of the months.
61#
62##########################################################################
63sub monthsBetween {
64	my $date1 = shift;
65	my $date2 = shift;
66
67    # Peter Weatherdon Jan 25, 2005
68    # Used new monthEarly and monthLate functions instead of monthBegin and
69    # monthEnd because Class::Date has some problems calculating date
70    # differences at the boundaries.  For example if date1=2005-01-31 23:59:59
71    # and date2=2005-12-01 01:00:00 then the difference in months is
72    # 9.95640678332187 instead of the expected 10 plus a bit.
73	$date1	= monthEarly($date1);
74	$date2	= monthLate($date2);
75	my $rough = ($date2-$date1)->month;
76	return int($rough)+1;
77}
78
79##########################################################################
80#
81#	Function: daysBetween(date1, date2)
82#
83#	Purpose: Inclusive calculation of the number of days between two
84#		Class::Date objects.
85#
86##########################################################################
87sub daysBetween {
88	my $date1 = shift;
89	my $date2 = shift;
90	$date1	= dayEnd($date1);
91	$date2	= dayBegin($date2);
92	my $rough = int(($date2-$date1)->day);
93	return $rough+2;
94}
95
96##########################################################################
97#
98#	Function: hoursBetween(date1, date2)
99#
100#	Purpose: Inclusive calculation of the number of hours between two
101#		Class::Date objects.
102#
103##########################################################################
104sub hoursBetween {
105	my $date1 = shift;
106	my $date2 = shift;
107	$date1	= hourEnd($date1);
108	$date2	= hourBegin($date2);
109	my $rough = int(($date2-$date1)->hour);
110	return $rough+2;
111}
112
113##########################################################################
114#
115#	Function: hourBegin(date)
116#
117#	Purpose: Returns the date object, reset to the beginning of the
118#		hour.
119#
120##########################################################################
121sub hourBegin {
122	my $date = shift;
123	$date	-= ($date->min() - 1)."m" if $date->min > 0;
124	$date	-= ($date->sec() - 1)."s" if $date->sec > 0;
125	return $date;
126}
127
128##########################################################################
129#
130#	Function: hourEnd(date)
131#
132#	Purpose: Returns the date object, reset to the end of the hour.
133#
134##########################################################################
135sub hourEnd {
136	my $date = shift;
137	$date	+= (59 - $date->min)."m" if $date->min < 59;
138	$date	+= (59 - $date->sec)."s" if $date->sec < 59;
139	return $date;
140}
141
142##########################################################################
143#
144#	Function: dayBegin(date)
145#
146#	Purpose: Returns the date object, reset to the beginning of the
147#		day.
148#
149##########################################################################
150sub dayBegin {
151	my $date = shift;
152	$date	-= ($date->hour() - 1)."h" if $date->hour > 0;
153	$date	= hourBegin($date);
154	return $date;
155}
156
157##########################################################################
158#
159#	Function: dayEnd(date)
160#
161#	Purpose: Returns the date object, reset to the end of the day.
162#
163##########################################################################
164sub dayEnd {
165	my $date = shift;
166	$date	+= (23 - $date->hour)."h" if $date->hour < 23;
167	$date	= hourEnd($date);
168	return $date;
169}
170
171##########################################################################
172#
173#	Function: monthBegin(date)
174#
175#	Purpose: Returns the date, reset to the beginning of the month.
176#		Differs from similar function provided by Class::Date by
177#		going to the very beginning of the month, and not just
178#		the first day along with whatever hour was origionally
179#		used.
180#
181##########################################################################
182sub monthBegin {
183	my $date= shift;
184	$date	= $date->month_begin();
185	$date	= dayBegin($date);
186	return $date;
187}
188
189##########################################################################
190#
191#	Function: monthEnd(date)
192#
193#	Purpose: Returns the date, reset to the end of the month. Similar
194#		Differs from the function provided by Class::Date in a
195#		similar manner to the function above.
196#
197##########################################################################
198sub monthEnd {
199	my $date= shift;
200	$date	= $date->month_end();
201	$date	= dayEnd($date);
202	return $date;
203}
204
205
206##########################################################################
207#
208#   Function: monthEarly(date)
209#
210#   Author: Peter Weatherdon
211#
212#   Purpose: Returns the date, reset to the 5th of the month.
213#
214##########################################################################
215sub monthEarly {
216    my $date = shift;
217    return new Class::Date ($date->year . "-" . $date->month . "-" . "05");
218}
219
220
221##########################################################################
222#
223#   Function: monthLate(date)
224#
225#   Author: Peter Weatherdon
226#
227#   Purpose: Returns the date, reset to the 25th of the month.
228#
229##########################################################################
230sub monthLate {
231    my $date = shift;
232    return new Class::Date ($date->year . "-" . $date->month . "-" . "25");
233}
234
235##########################################################################
236#
237#	Function: getDay(date)
238#
239#	Purpose: Returns the string representation of the day of the week
240#		for the date passed in.
241#
242##########################################################################
243sub getDay {
244	my $day		= shift;
245	my @days;
246	$days[1]	= 'Sunday';
247	$days[2]	= 'Monday';
248	$days[3]	= 'Tuesday';
249	$days[4]	= 'Wednesday';
250	$days[5]	= 'Thursday';
251	$days[6]	= 'Friday';
252	$days[7]	= 'Saturday';
253	return $days[$day];
254}
255
256##########################################################################
257#
258#	Function: getMonth(date)
259#
260#	Purpose: Returns the string representation of the month for the
261#		date passed in.
262#
263##########################################################################
264sub getMonth {
265	my $month	= shift;
266	my @months;
267	$months[1]	= 'January';
268	$months[2]	= 'February';
269	$months[3]	= 'March';
270	$months[4]	= 'April';
271	$months[5]	= 'May';
272	$months[6]	= 'June';
273	$months[7]	= 'July';
274	$months[8]	= 'August';
275	$months[9]	= 'September';
276	$months[10]	= 'October';
277	$months[11]	= 'November';
278	$months[12]	= 'December';
279	return $months[$month];
280}
281
2821;
283