1 /*
2  * Osmo - a handy personal organizer
3  *
4  * Copyright (C) 2007-2009 Tomasz Maka <pasp@users.sourceforge.net>
5  *               2007-2009 Piotr Maka <silloz@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "i18n.h"
23 #include "utils.h"
24 #include "utils_date.h"
25 
26 /*============================================================================*/
27 
28 GDate *
utl_date_new_current(void)29 utl_date_new_current (void)
30 {
31 	GDate *d = g_date_new ();
32 	g_date_set_time_t (d, time (NULL));
33 
34 	return d;
35 }
36 
37 /*============================================================================*/
38 
39 guint
utl_date_get_current_day(void)40 utl_date_get_current_day (void)
41 {
42 	GDate *d = utl_date_new_current ();
43 	guint day = g_date_get_day (d);
44 	g_date_free (d);
45 
46 	return day;
47 }
48 
49 /*============================================================================*/
50 
51 guint
utl_date_get_current_month(void)52 utl_date_get_current_month (void)
53 {
54 	GDate *d = utl_date_new_current ();
55 	guint month = g_date_get_month (d);
56 	g_date_free (d);
57 
58 	return month;
59 }
60 
61 /*============================================================================*/
62 
63 guint
utl_date_get_current_year(void)64 utl_date_get_current_year (void)
65 {
66 	GDate *d = utl_date_new_current ();
67 	guint year = g_date_get_year (d);
68 	g_date_free (d);
69 
70 	return year;
71 }
72 
73 /*============================================================================*/
74 
75 guint32
utl_date_get_current_julian(void)76 utl_date_get_current_julian (void)
77 {
78 	GDate *d = utl_date_new_current ();
79 	guint32 julian = g_date_get_julian (d);
80 	g_date_free (d);
81 
82 	return julian;
83 }
84 
85 /*============================================================================*/
86 
87 void
utl_date_get_current_dmy(gint * day,gint * month,gint * year)88 utl_date_get_current_dmy (gint *day, gint *month, gint *year)
89 {
90 	GDate *d = utl_date_new_current ();
91 
92 	if (day != NULL) *day = g_date_get_day (d);
93 	if (month != NULL) *month = g_date_get_month (d);
94 	if (year != NULL) *year = g_date_get_year (d);
95 
96 	g_date_free (d);
97 }
98 
99 /*============================================================================*/
100 
101 guint
utl_date_get_days_in_month(const GDate * date)102 utl_date_get_days_in_month (const GDate *date)
103 {
104 	g_return_val_if_fail (g_date_valid (date), 0);
105 
106 	return g_date_get_days_in_month (g_date_get_month (date), g_date_get_year (date));
107 }
108 
109 /*============================================================================*/
110 
111 gboolean
utl_date_set_valid_day(GDate * date,gint day)112 utl_date_set_valid_day (GDate *date, gint day)
113 {
114     gint days = utl_date_get_days_in_month (date);
115 
116     if (day > days) {
117         g_date_set_day (date, days);
118 		return TRUE;
119 	}
120 
121 	g_date_set_day (date, day);
122 	return FALSE;
123 }
124 
125 /*============================================================================*/
126 
127 gboolean
utl_date_set_valid_dmy(gint * day,gint month,gint year)128 utl_date_set_valid_dmy (gint *day, gint month, gint year)
129 {
130     gint days = g_date_get_days_in_month (month, year);
131 
132     if (*day > days) {
133         *day = days;
134 		return TRUE;
135 	}
136 
137 	return FALSE;
138 }
139 
140 /*============================================================================*/
141 
142 void
utl_date_diff(const GDate * date1,const GDate * date2,gint * day,gint * month,gint * year)143 utl_date_diff (const GDate *date1, const GDate *date2, gint *day, gint *month, gint *year)
144 {
145 	g_return_if_fail (g_date_valid (date1));
146 	g_return_if_fail (g_date_valid (date2));
147 	g_return_if_fail (g_date_compare (date1, date2) <= 0);
148 
149     *day = g_date_get_day (date2) - g_date_get_day (date1);
150     *month = g_date_get_month (date2) - g_date_get_month (date1);
151     *year = g_date_get_year (date2) - g_date_get_year (date1);
152 
153     if (*day < 0) {
154         *day += utl_date_get_days_in_month (date1);
155 		*month -= 1;
156     }
157 
158     if (*month < 0) {
159         *month += 12;
160 		*year -= 1;
161     }
162 }
163 
164 /*============================================================================*/
165 
166 gboolean
utl_date_order(GDate * date1,GDate * date2)167 utl_date_order (GDate *date1, GDate *date2)
168 {
169 	g_return_val_if_fail (g_date_valid (date1), FALSE);
170 	g_return_val_if_fail (g_date_valid (date2), FALSE);
171 
172 	if (g_date_compare (date1, date2) > 0)
173 	{
174 		GDate tmp = *date1;
175 		*date1 = *date2;
176 		*date2 = tmp;
177 		return TRUE;
178 	} else
179 		return FALSE;
180 }
181 
182 /*============================================================================*/
183 
184 void
utl_date_set_nearest_weekday(GDate * date,gint weekdays,gboolean month_mode)185 utl_date_set_nearest_weekday (GDate *date, gint weekdays, gboolean month_mode)
186 {
187 	gint day, start_day, days_in_month;
188 	gint i, j;
189 
190 	if (weekdays == D_WEEK) return;
191 	g_return_if_fail (weekdays > D_BAD_DAY && weekdays <= D_WEEK);
192 	g_return_if_fail (g_date_valid (date));
193 
194 	day = g_date_get_weekday (date) - 1;
195 
196 	if (month_mode == TRUE) {
197 
198 		days_in_month = utl_date_get_days_in_month (date);
199 		start_day = g_date_get_day (date);
200 
201 		for (i = 0; i < 7; i++) {
202 			if (weekdays & (1 << ((day + i) % 7))) break;
203 		}
204 
205 		for (j = 0; j < 7; j++) {
206 			if (weekdays & (1 << ((day + 7 - j) % 7))) break;
207 		}
208 
209 		if (start_day + i > days_in_month) i = 7;
210 		if (start_day - j < 1) j = 7;
211 
212 		if (i <= j) {
213 			if (i > 0) g_date_add_days (date, i);
214 		} else {
215 			if (j > 0) g_date_subtract_days (date, j);
216 		}
217 
218 	} else {
219 
220 		for (i = 0; i < 7; i++) {
221 			if (weekdays & (1 << ((day + i) % 7))) break;
222 		}
223 		if (i > 0) g_date_add_days (date, i);
224 
225 	}
226 
227 }
228 
229 /*============================================================================*/
230 
231 gchar *
utl_date_print(const GDate * d,gint date_format,gint override_locale)232 utl_date_print (const GDate *d, gint date_format, gint override_locale)
233 {
234 	gchar date_str[BUFFER_SIZE], *format;
235 
236 	g_return_val_if_fail (g_date_valid (d), NULL);
237 
238 	format = utl_date_get_format_str (date_format, override_locale);
239 	g_date_strftime (date_str, BUFFER_SIZE, format, d);
240 
241 	return g_strdup (date_str);
242 }
243 
244 /*============================================================================*/
245 
246 gchar *
utl_date_print_j(guint32 julian,gint date_format,gint override_locale)247 utl_date_print_j (guint32 julian, gint date_format, gint override_locale)
248 {
249 	gchar *date_str;
250 
251 	if (g_date_valid_julian (julian)) {
252 		GDate *d = g_date_new_julian (julian);
253 		date_str = utl_date_print (d, date_format, override_locale);
254 		g_date_free (d);
255 	} else
256 		date_str = g_strdup (_("No date"));
257 
258 	return date_str;
259 }
260 
261 /*============================================================================*/
262 
263 gchar *
utl_date_get_format_str(gint date_format,gint override_locale)264 utl_date_get_format_str (gint date_format, gint override_locale)
265 {
266 	gchar *date_format_str[] = {
267 		"%d-%m-%Y", "%m-%d-%Y", "%Y-%m-%d", "%Y-%d-%m", "%e %B", "%A", "%e %B %Y", "%x"
268 	};
269 
270 	if (!override_locale)
271 		return date_format_str[DATE_LOCALE];
272 
273 	g_return_val_if_fail (date_format >= DATE_DD_MM_YYYY &&
274 	                      date_format <= DATE_FULL, NULL);
275 
276 	return date_format_str[date_format];
277 }
278 
279 /*============================================================================*/
280 
281 void
utl_date_get_dmy(const GDate * date,gint * day,gint * month,gint * year)282 utl_date_get_dmy (const GDate *date, gint *day, gint *month, gint *year)
283 {
284 	g_return_if_fail (g_date_valid (date));
285 
286 	if (day != NULL) *day = g_date_get_day (date);
287 	if (month != NULL) *month = g_date_get_month (date);
288 	if (year != NULL) *year = g_date_get_year (date);
289 }
290 
291 /*============================================================================*/
292 
293 void
utl_date_julian_to_dmy(guint32 julian,gint * day,gint * month,gint * year)294 utl_date_julian_to_dmy (guint32 julian, gint *day, gint *month, gint *year)
295 {
296 	g_return_if_fail (g_date_valid_julian (julian));
297 
298 	GDate *d = g_date_new_julian (julian);
299 	if (day != NULL) *day = g_date_get_day (d);
300 	if (month != NULL) *month = g_date_get_month (d);
301 	if (year != NULL) *year = g_date_get_year (d);
302 
303 	g_date_free (d);
304 }
305 
306 /*============================================================================*/
307 
308 guint32
utl_date_dmy_to_julian(guint day,guint month,guint year)309 utl_date_dmy_to_julian (guint day, guint month, guint year)
310 {
311 	g_return_val_if_fail (g_date_valid_dmy (day, month, year), 0);
312 
313 	GDate *d = g_date_new_dmy (day, month, year);
314 	guint32 julian = g_date_get_julian (d);
315 	g_date_free (d);
316 
317 	return julian;
318 }
319 
320 /*============================================================================*/
321 /*
322  * lib_date routines
323  * Copyright (c) 1995, 1996, 1997, 1998 by Steffen Beyer
324  *
325  */
326 
327 guint
utl_get_month_length(guint leap_year,guint month)328 utl_get_month_length (guint leap_year, guint month) {
329 
330 const guint month_length[2][13] = {
331     { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
332     { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
333 };
334 
335 	return month_length[leap_year][month];
336 }
337 
338 guint
utl_get_days_in_months(guint leap_year,guint month)339 utl_get_days_in_months (guint leap_year, guint month) {
340 
341 const guint days_in_months[2][14] = {
342     { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
343     { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
344 };
345 
346 	return days_in_months[leap_year][month];
347 }
348 
349 glong
utl_year_to_days(guint year)350 utl_year_to_days (guint year) {
351     return( year * 365L + (year / 4) - (year / 100) + (year / 400) );
352 }
353 
354 glong
utl_calc_days(guint year,guint mm,guint dd)355 utl_calc_days (guint year, guint mm, guint dd) {
356 
357 	gboolean lp;
358 
359     if (year < 1) return(0L);
360     if ((mm < 1) || (mm > 12)) return(0L);
361     if ((dd < 1) || (dd > utl_get_month_length((lp = g_date_is_leap_year(year)), mm))) return(0L);
362 
363 	return( utl_year_to_days(--year) + utl_get_days_in_months(lp, mm) + dd );
364 }
365 
366 glong
utl_dates_difference(guint year1,guint mm1,guint dd1,guint year2,guint mm2,guint dd2)367 utl_dates_difference (guint year1, guint mm1, guint dd1,
368 					  guint year2, guint mm2, guint dd2) {
369 
370     return (utl_calc_days(year2, mm2, dd2) - utl_calc_days(year1, mm1, dd1));
371 }
372 
373 guint
utl_day_of_week(guint year,guint mm,guint dd)374 utl_day_of_week (guint year, guint mm, guint dd) {
375 
376 	glong  days;
377 
378     days = utl_calc_days(year, mm, dd);
379     if (days > 0L) {
380         days--;
381         days %= 7L;
382         days++;
383     }
384     return( (guint) days );
385 }
386 
387 guint
utl_weeks_in_year(guint year)388 utl_weeks_in_year (guint year) {
389     return(52 + ((utl_day_of_week(year, 1, 1) == 4) || (utl_day_of_week(year, 12, 31) == 4)));
390 }
391 
392 guint
utl_get_week_number(guint year,guint mm,guint dd)393 utl_get_week_number (guint year, guint mm, guint dd) {
394 
395 	guint first;
396 
397     first = utl_day_of_week(year,1,1) - 1;
398     return( (guint) ( (utl_dates_difference(year,1,1, year,mm,dd) + first) / 7L ) +
399             (first < 4) );
400 }
401 
402 gboolean
utl_week_of_year(guint * week,guint * year,guint mm,guint dd)403 utl_week_of_year (guint *week, guint *year, guint mm, guint dd) {
404 
405 	if (g_date_valid_dmy (dd, mm, *year)) {
406         *week = utl_get_week_number(*year, mm, dd);
407         if (*week == 0)
408             *week = utl_weeks_in_year(--(*year));
409         else if (*week > utl_weeks_in_year(*year)) {
410             *week = 1;
411             (*year)++;
412         }
413         return TRUE;
414     }
415     return FALSE;
416 }
417 
418 /*------------------------------------------------------------------------------*/
419 
420