|
1 /* GLIB - Library of useful routines for C programming |
|
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
|
3 * Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
4 * |
|
5 * This library is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU Lesser General Public |
|
7 * License as published by the Free Software Foundation; either |
|
8 * version 2 of the License, or (at your option) any later version. |
|
9 * |
|
10 * This library is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 * Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General Public |
|
16 * License along with this library; if not, write to the |
|
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
18 * Boston, MA 02111-1307, USA. |
|
19 */ |
|
20 |
|
21 /* |
|
22 * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
|
23 * file for a list of people on the GLib Team. See the ChangeLog |
|
24 * files for a list of changes. These files are distributed with |
|
25 * GLib at ftp://ftp.gtk.org/pub/gtk/. |
|
26 */ |
|
27 |
|
28 /* |
|
29 * MT safe |
|
30 */ |
|
31 |
|
32 #include "config.h" |
|
33 |
|
34 #define DEBUG_MSG(x) /* */ |
|
35 #ifdef G_ENABLE_DEBUG |
|
36 /* #define DEBUG_MSG(args) g_message args ; */ |
|
37 #endif |
|
38 |
|
39 #include "glib.h" |
|
40 |
|
41 #include <time.h> |
|
42 #include <string.h> |
|
43 #include <stdlib.h> |
|
44 #include <locale.h> |
|
45 |
|
46 #include "galias.h" |
|
47 |
|
48 #ifdef __SYMBIAN32__ |
|
49 #include <glib_wsd.h> |
|
50 #endif /* __SYMBIAN32__ */ |
|
51 |
|
52 #if EMULATOR |
|
53 #define g_thread_functions_for_glib_use (*_g_thread_functions_for_glib_use()) |
|
54 #define g_thread_use_default_impl (*_g_thread_use_default_impl()) |
|
55 #endif /* EMULATOR */ |
|
56 |
|
57 EXPORT_C GDate* |
|
58 g_date_new (void) |
|
59 { |
|
60 GDate *d = g_new0 (GDate, 1); /* happily, 0 is the invalid flag for everything. */ |
|
61 |
|
62 return d; |
|
63 } |
|
64 |
|
65 EXPORT_C GDate* |
|
66 g_date_new_dmy (GDateDay day, GDateMonth m, GDateYear y) |
|
67 { |
|
68 GDate *d; |
|
69 g_return_val_if_fail (g_date_valid_dmy (day, m, y), NULL); |
|
70 |
|
71 d = g_new (GDate, 1); |
|
72 |
|
73 d->julian = FALSE; |
|
74 d->dmy = TRUE; |
|
75 |
|
76 d->month = m; |
|
77 d->day = day; |
|
78 d->year = y; |
|
79 |
|
80 g_assert (g_date_valid (d)); |
|
81 |
|
82 return d; |
|
83 } |
|
84 |
|
85 EXPORT_C GDate* |
|
86 g_date_new_julian (guint32 j) |
|
87 { |
|
88 GDate *d; |
|
89 g_return_val_if_fail (g_date_valid_julian (j), NULL); |
|
90 d = g_new (GDate, 1); |
|
91 |
|
92 d->julian = TRUE; |
|
93 d->dmy = FALSE; |
|
94 |
|
95 d->julian_days = j; |
|
96 |
|
97 g_assert (g_date_valid (d)); |
|
98 |
|
99 return d; |
|
100 } |
|
101 |
|
102 EXPORT_C void |
|
103 g_date_free (GDate *d) |
|
104 { |
|
105 g_return_if_fail (d != NULL); |
|
106 |
|
107 g_free (d); |
|
108 } |
|
109 |
|
110 EXPORT_C gboolean |
|
111 g_date_valid (const GDate *d) |
|
112 { |
|
113 g_return_val_if_fail (d != NULL, FALSE); |
|
114 |
|
115 return (d->julian || d->dmy); |
|
116 } |
|
117 |
|
118 static const guint8 days_in_months[2][13] = |
|
119 { /* error, jan feb mar apr may jun jul aug sep oct nov dec */ |
|
120 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
|
121 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* leap year */ |
|
122 }; |
|
123 |
|
124 static const guint16 days_in_year[2][14] = |
|
125 { /* 0, jan feb mar apr may jun jul aug sep oct nov dec */ |
|
126 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
|
127 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } |
|
128 }; |
|
129 |
|
130 EXPORT_C gboolean |
|
131 g_date_valid_month (GDateMonth m) |
|
132 { |
|
133 return ( (m > G_DATE_BAD_MONTH) && (m < 13) ); |
|
134 } |
|
135 |
|
136 EXPORT_C gboolean |
|
137 g_date_valid_year (GDateYear y) |
|
138 { |
|
139 return ( y > G_DATE_BAD_YEAR ); |
|
140 } |
|
141 |
|
142 EXPORT_C gboolean |
|
143 g_date_valid_day (GDateDay d) |
|
144 { |
|
145 return ( (d > G_DATE_BAD_DAY) && (d < 32) ); |
|
146 } |
|
147 |
|
148 EXPORT_C gboolean |
|
149 g_date_valid_weekday (GDateWeekday w) |
|
150 { |
|
151 return ( (w > G_DATE_BAD_WEEKDAY) && (w < 8) ); |
|
152 } |
|
153 |
|
154 EXPORT_C gboolean |
|
155 g_date_valid_julian (guint32 j) |
|
156 { |
|
157 return (j > G_DATE_BAD_JULIAN); |
|
158 } |
|
159 |
|
160 EXPORT_C gboolean |
|
161 g_date_valid_dmy (GDateDay d, |
|
162 GDateMonth m, |
|
163 GDateYear y) |
|
164 { |
|
165 return ( (m > G_DATE_BAD_MONTH) && |
|
166 (m < 13) && |
|
167 (d > G_DATE_BAD_DAY) && |
|
168 (y > G_DATE_BAD_YEAR) && /* must check before using g_date_is_leap_year */ |
|
169 (d <= (g_date_is_leap_year (y) ? |
|
170 days_in_months[1][m] : days_in_months[0][m])) ); |
|
171 } |
|
172 |
|
173 |
|
174 /* "Julian days" just means an absolute number of days, where Day 1 == |
|
175 * Jan 1, Year 1 |
|
176 */ |
|
177 static void |
|
178 g_date_update_julian (const GDate *const_d) |
|
179 { |
|
180 GDate *d = (GDate *) const_d; |
|
181 GDateYear year; |
|
182 gint index; |
|
183 |
|
184 g_return_if_fail (d != NULL); |
|
185 g_return_if_fail (d->dmy); |
|
186 g_return_if_fail (!d->julian); |
|
187 g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year)); |
|
188 |
|
189 /* What we actually do is: multiply years * 365 days in the year, |
|
190 * add the number of years divided by 4, subtract the number of |
|
191 * years divided by 100 and add the number of years divided by 400, |
|
192 * which accounts for leap year stuff. Code from Steffen Beyer's |
|
193 * DateCalc. |
|
194 */ |
|
195 |
|
196 year = d->year - 1; /* we know d->year > 0 since it's valid */ |
|
197 |
|
198 d->julian_days = year * 365U; |
|
199 d->julian_days += (year >>= 2); /* divide by 4 and add */ |
|
200 d->julian_days -= (year /= 25); /* divides original # years by 100 */ |
|
201 d->julian_days += year >> 2; /* divides by 4, which divides original by 400 */ |
|
202 |
|
203 index = g_date_is_leap_year (d->year) ? 1 : 0; |
|
204 |
|
205 d->julian_days += days_in_year[index][d->month] + d->day; |
|
206 |
|
207 g_return_if_fail (g_date_valid_julian (d->julian_days)); |
|
208 |
|
209 d->julian = TRUE; |
|
210 } |
|
211 |
|
212 static void |
|
213 g_date_update_dmy (const GDate *const_d) |
|
214 { |
|
215 GDate *d = (GDate *) const_d; |
|
216 GDateYear y; |
|
217 GDateMonth m; |
|
218 GDateDay day; |
|
219 |
|
220 guint32 A, B, C, D, E, M; |
|
221 |
|
222 g_return_if_fail (d != NULL); |
|
223 g_return_if_fail (d->julian); |
|
224 g_return_if_fail (!d->dmy); |
|
225 g_return_if_fail (g_date_valid_julian (d->julian_days)); |
|
226 |
|
227 /* Formula taken from the Calendar FAQ; the formula was for the |
|
228 * Julian Period which starts on 1 January 4713 BC, so we add |
|
229 * 1,721,425 to the number of days before doing the formula. |
|
230 * |
|
231 * I'm sure this can be simplified for our 1 January 1 AD period |
|
232 * start, but I can't figure out how to unpack the formula. |
|
233 */ |
|
234 |
|
235 A = d->julian_days + 1721425 + 32045; |
|
236 B = ( 4 *(A + 36524) )/ 146097 - 1; |
|
237 C = A - (146097 * B)/4; |
|
238 D = ( 4 * (C + 365) ) / 1461 - 1; |
|
239 E = C - ((1461*D) / 4); |
|
240 M = (5 * (E - 1) + 2)/153; |
|
241 |
|
242 m = M + 3 - (12*(M/10)); |
|
243 day = E - (153*M + 2)/5; |
|
244 y = 100 * B + D - 4800 + (M/10); |
|
245 |
|
246 #ifdef G_ENABLE_DEBUG |
|
247 if (!g_date_valid_dmy (day, m, y)) |
|
248 { |
|
249 g_warning ("\nOOPS julian: %u computed dmy: %u %u %u\n", |
|
250 d->julian_days, day, m, y); |
|
251 } |
|
252 #endif |
|
253 |
|
254 d->month = m; |
|
255 d->day = day; |
|
256 d->year = y; |
|
257 |
|
258 d->dmy = TRUE; |
|
259 } |
|
260 |
|
261 EXPORT_C GDateWeekday |
|
262 g_date_get_weekday (const GDate *d) |
|
263 { |
|
264 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_WEEKDAY); |
|
265 |
|
266 if (!d->julian) |
|
267 { |
|
268 g_date_update_julian (d); |
|
269 } |
|
270 g_return_val_if_fail (d->julian, G_DATE_BAD_WEEKDAY); |
|
271 |
|
272 return ((d->julian_days - 1) % 7) + 1; |
|
273 } |
|
274 |
|
275 EXPORT_C GDateMonth |
|
276 g_date_get_month (const GDate *d) |
|
277 { |
|
278 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_MONTH); |
|
279 |
|
280 if (!d->dmy) |
|
281 { |
|
282 g_date_update_dmy (d); |
|
283 } |
|
284 g_return_val_if_fail (d->dmy, G_DATE_BAD_MONTH); |
|
285 |
|
286 return d->month; |
|
287 } |
|
288 |
|
289 EXPORT_C GDateYear |
|
290 g_date_get_year (const GDate *d) |
|
291 { |
|
292 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_YEAR); |
|
293 |
|
294 if (!d->dmy) |
|
295 { |
|
296 g_date_update_dmy (d); |
|
297 } |
|
298 g_return_val_if_fail (d->dmy, G_DATE_BAD_YEAR); |
|
299 |
|
300 return d->year; |
|
301 } |
|
302 |
|
303 EXPORT_C GDateDay |
|
304 g_date_get_day (const GDate *d) |
|
305 { |
|
306 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_DAY); |
|
307 |
|
308 if (!d->dmy) |
|
309 { |
|
310 g_date_update_dmy (d); |
|
311 } |
|
312 g_return_val_if_fail (d->dmy, G_DATE_BAD_DAY); |
|
313 |
|
314 return d->day; |
|
315 } |
|
316 |
|
317 EXPORT_C guint32 |
|
318 g_date_get_julian (const GDate *d) |
|
319 { |
|
320 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_JULIAN); |
|
321 |
|
322 if (!d->julian) |
|
323 { |
|
324 g_date_update_julian (d); |
|
325 } |
|
326 g_return_val_if_fail (d->julian, G_DATE_BAD_JULIAN); |
|
327 |
|
328 return d->julian_days; |
|
329 } |
|
330 |
|
331 EXPORT_C guint |
|
332 g_date_get_day_of_year (const GDate *d) |
|
333 { |
|
334 gint index; |
|
335 |
|
336 g_return_val_if_fail (g_date_valid (d), 0); |
|
337 |
|
338 if (!d->dmy) |
|
339 { |
|
340 g_date_update_dmy (d); |
|
341 } |
|
342 g_return_val_if_fail (d->dmy, 0); |
|
343 |
|
344 index = g_date_is_leap_year (d->year) ? 1 : 0; |
|
345 |
|
346 return (days_in_year[index][d->month] + d->day); |
|
347 } |
|
348 |
|
349 EXPORT_C guint |
|
350 g_date_get_monday_week_of_year (const GDate *d) |
|
351 { |
|
352 GDateWeekday wd; |
|
353 guint day; |
|
354 GDate first; |
|
355 |
|
356 g_return_val_if_fail (g_date_valid (d), 0); |
|
357 |
|
358 if (!d->dmy) |
|
359 { |
|
360 g_date_update_dmy (d); |
|
361 } |
|
362 g_return_val_if_fail (d->dmy, 0); |
|
363 |
|
364 g_date_clear (&first, 1); |
|
365 |
|
366 g_date_set_dmy (&first, 1, 1, d->year); |
|
367 |
|
368 wd = g_date_get_weekday (&first) - 1; /* make Monday day 0 */ |
|
369 day = g_date_get_day_of_year (d) - 1; |
|
370 |
|
371 return ((day + wd)/7U + (wd == 0 ? 1 : 0)); |
|
372 } |
|
373 |
|
374 EXPORT_C guint |
|
375 g_date_get_sunday_week_of_year (const GDate *d) |
|
376 { |
|
377 GDateWeekday wd; |
|
378 guint day; |
|
379 GDate first; |
|
380 |
|
381 g_return_val_if_fail (g_date_valid (d), 0); |
|
382 |
|
383 if (!d->dmy) |
|
384 { |
|
385 g_date_update_dmy (d); |
|
386 } |
|
387 g_return_val_if_fail (d->dmy, 0); |
|
388 |
|
389 g_date_clear (&first, 1); |
|
390 |
|
391 g_date_set_dmy (&first, 1, 1, d->year); |
|
392 |
|
393 wd = g_date_get_weekday (&first); |
|
394 if (wd == 7) wd = 0; /* make Sunday day 0 */ |
|
395 day = g_date_get_day_of_year (d) - 1; |
|
396 |
|
397 return ((day + wd)/7U + (wd == 0 ? 1 : 0)); |
|
398 } |
|
399 |
|
400 /** |
|
401 * g_date_get_iso8601_week_of_year: |
|
402 * @date: a valid #GDate |
|
403 * |
|
404 * Returns the week of the year, where weeks are interpreted according |
|
405 * to ISO 8601. |
|
406 * |
|
407 * Returns: ISO 8601 week number of the year. |
|
408 * |
|
409 * Since: 2.6 |
|
410 **/ |
|
411 EXPORT_C guint |
|
412 g_date_get_iso8601_week_of_year (const GDate *d) |
|
413 { |
|
414 guint j, d4, L, d1, w; |
|
415 |
|
416 g_return_val_if_fail (g_date_valid (d), 0); |
|
417 |
|
418 if (!d->julian) |
|
419 g_date_update_julian (d); |
|
420 g_return_val_if_fail (d->julian, 0); |
|
421 |
|
422 /* Formula taken from the Calendar FAQ; the formula was for the |
|
423 * Julian Period which starts on 1 January 4713 BC, so we add |
|
424 * 1,721,425 to the number of days before doing the formula. |
|
425 */ |
|
426 j = d->julian_days + 1721425; |
|
427 d4 = (j + 31741 - (j % 7)) % 146097 % 36524 % 1461; |
|
428 L = d4 / 1460; |
|
429 d1 = ((d4 - L) % 365) + L; |
|
430 w = d1 / 7 + 1; |
|
431 |
|
432 return w; |
|
433 } |
|
434 |
|
435 EXPORT_C gint |
|
436 g_date_days_between (const GDate *d1, |
|
437 const GDate *d2) |
|
438 { |
|
439 g_return_val_if_fail (g_date_valid (d1), 0); |
|
440 g_return_val_if_fail (g_date_valid (d2), 0); |
|
441 |
|
442 return (gint)g_date_get_julian (d2) - (gint)g_date_get_julian (d1); |
|
443 } |
|
444 |
|
445 EXPORT_C void |
|
446 g_date_clear (GDate *d, guint ndates) |
|
447 { |
|
448 g_return_if_fail (d != NULL); |
|
449 g_return_if_fail (ndates != 0); |
|
450 |
|
451 memset (d, 0x0, ndates*sizeof (GDate)); |
|
452 } |
|
453 |
|
454 #if EMULATOR |
|
455 |
|
456 PLS_MACRO(g_date_global,gdate,GStaticMutex) |
|
457 PLS_ARRAY(long_month_names, gdate, gchar *) |
|
458 PLS_ARRAY(short_month_names, gdate, gchar *) |
|
459 PLS(current_locale,gdate, gchar *) |
|
460 PLS_ARRAY(dmy_order, gdate, GDateDMY) |
|
461 PLS(using_twodigit_years,gdate, gboolean) |
|
462 PLS(locale_era_adjust,gdate, gint) |
|
463 |
|
464 #define g__g_date_global_lock (*FUNCTION_NAME_MACRO(g_date_global,gdate)()) |
|
465 #define long_month_names (FUNCTION_NAME(long_month_names,gdate)()) |
|
466 #define short_month_names (FUNCTION_NAME(short_month_names,gdate)()) |
|
467 #define current_locale (*FUNCTION_NAME(current_locale ,gdate)()) |
|
468 #define dmy_order (FUNCTION_NAME(dmy_order,gdate)()) |
|
469 #define using_twodigit_years (*FUNCTION_NAME(using_twodigit_years ,gdate)()) |
|
470 #define locale_era_adjust (*FUNCTION_NAME(locale_era_adjust,gdate)()) |
|
471 |
|
472 #else |
|
473 |
|
474 G_LOCK_DEFINE_STATIC (g_date_global); |
|
475 |
|
476 /* These are for the parser, output to the user should use * |
|
477 * g_date_strftime () - this creates more never-freed memory to annoy |
|
478 * all those memory debugger users. :-) |
|
479 */ |
|
480 |
|
481 static gchar *long_month_names[13] = |
|
482 { |
|
483 "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
|
484 }; |
|
485 |
|
486 static gchar *short_month_names[13] = |
|
487 { |
|
488 "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
|
489 }; |
|
490 |
|
491 /* This tells us if we need to update the parse info */ |
|
492 static gchar *current_locale = NULL; |
|
493 |
|
494 /* order of these in the current locale */ |
|
495 static GDateDMY dmy_order[3] = |
|
496 { |
|
497 G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR |
|
498 }; |
|
499 |
|
500 /* It is impossible to enter a year between 1 AD and 99 AD with this |
|
501 * in effect. |
|
502 */ |
|
503 static gboolean using_twodigit_years = FALSE; |
|
504 |
|
505 /* Adjustment of locale era to AD, non-zero means using locale era |
|
506 */ |
|
507 static gint locale_era_adjust = 0; |
|
508 |
|
509 #endif /* EMULATOR */ |
|
510 |
|
511 /* Where to chop two-digit years: i.e., for the 1930 default, numbers |
|
512 * 29 and below are counted as in the year 2000, numbers 30 and above |
|
513 * are counted as in the year 1900. |
|
514 */ |
|
515 |
|
516 static const GDateYear twodigit_start_year = 1930; |
|
517 |
|
518 struct _GDateParseTokens { |
|
519 gint num_ints; |
|
520 gint n[3]; |
|
521 guint month; |
|
522 }; |
|
523 |
|
524 typedef struct _GDateParseTokens GDateParseTokens; |
|
525 |
|
526 #define NUM_LEN 10 |
|
527 |
|
528 /* HOLDS: g_date_global_lock */ |
|
529 static void |
|
530 g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) |
|
531 { |
|
532 gchar num[4][NUM_LEN+1]; |
|
533 gint i; |
|
534 const guchar *s; |
|
535 |
|
536 /* We count 4, but store 3; so we can give an error |
|
537 * if there are 4. |
|
538 */ |
|
539 num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0'; |
|
540 |
|
541 s = (const guchar *) str; |
|
542 pt->num_ints = 0; |
|
543 while (*s && pt->num_ints < 4) |
|
544 { |
|
545 |
|
546 i = 0; |
|
547 while (*s && g_ascii_isdigit (*s) && i < NUM_LEN) |
|
548 { |
|
549 num[pt->num_ints][i] = *s; |
|
550 ++s; |
|
551 ++i; |
|
552 } |
|
553 |
|
554 if (i > 0) |
|
555 { |
|
556 num[pt->num_ints][i] = '\0'; |
|
557 ++(pt->num_ints); |
|
558 } |
|
559 |
|
560 if (*s == '\0') break; |
|
561 |
|
562 ++s; |
|
563 } |
|
564 |
|
565 pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0; |
|
566 pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0; |
|
567 pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0; |
|
568 |
|
569 pt->month = G_DATE_BAD_MONTH; |
|
570 |
|
571 if (pt->num_ints < 3) |
|
572 { |
|
573 gchar *casefold; |
|
574 gchar *normalized; |
|
575 |
|
576 casefold = g_utf8_casefold (str, -1); |
|
577 normalized = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); |
|
578 g_free (casefold); |
|
579 |
|
580 i = 1; |
|
581 while (i < 13) |
|
582 { |
|
583 if (long_month_names[i] != NULL) |
|
584 { |
|
585 const gchar *found = strstr (normalized, long_month_names[i]); |
|
586 |
|
587 if (found != NULL) |
|
588 { |
|
589 pt->month = i; |
|
590 break; |
|
591 } |
|
592 } |
|
593 |
|
594 if (short_month_names[i] != NULL) |
|
595 { |
|
596 const gchar *found = strstr (normalized, short_month_names[i]); |
|
597 |
|
598 if (found != NULL) |
|
599 { |
|
600 pt->month = i; |
|
601 break; |
|
602 } |
|
603 } |
|
604 |
|
605 ++i; |
|
606 } |
|
607 |
|
608 g_free (normalized); |
|
609 } |
|
610 } |
|
611 |
|
612 /* HOLDS: g_date_global_lock */ |
|
613 static void |
|
614 g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt) |
|
615 { |
|
616 const gchar *locale = setlocale (LC_TIME, NULL); |
|
617 gboolean recompute_localeinfo = FALSE; |
|
618 GDate d; |
|
619 |
|
620 g_return_if_fail (locale != NULL); /* should not happen */ |
|
621 |
|
622 g_date_clear (&d, 1); /* clear for scratch use */ |
|
623 |
|
624 if ( (current_locale == NULL) || (strcmp (locale, current_locale) != 0) ) |
|
625 { |
|
626 recompute_localeinfo = TRUE; /* Uh, there used to be a reason for the temporary */ |
|
627 } |
|
628 |
|
629 if (recompute_localeinfo) |
|
630 { |
|
631 int i = 1; |
|
632 GDateParseTokens testpt; |
|
633 gchar buf[128]; |
|
634 |
|
635 g_free (current_locale); /* still works if current_locale == NULL */ |
|
636 |
|
637 current_locale = g_strdup (locale); |
|
638 |
|
639 while (i < 13) |
|
640 { |
|
641 gchar *casefold; |
|
642 |
|
643 g_date_set_dmy (&d, 1, i, 1); |
|
644 |
|
645 g_return_if_fail (g_date_valid (&d)); |
|
646 |
|
647 g_date_strftime (buf, 127, "%b", &d); |
|
648 |
|
649 casefold = g_utf8_casefold (buf, -1); |
|
650 g_free (short_month_names[i]); |
|
651 short_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); |
|
652 g_free (casefold); |
|
653 |
|
654 g_date_strftime (buf, 127, "%B", &d); |
|
655 casefold = g_utf8_casefold (buf, -1); |
|
656 g_free (long_month_names[i]); |
|
657 long_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL); |
|
658 g_free (casefold); |
|
659 |
|
660 ++i; |
|
661 } |
|
662 |
|
663 /* Determine DMY order */ |
|
664 |
|
665 /* had to pick a random day - don't change this, some strftimes |
|
666 * are broken on some days, and this one is good so far. */ |
|
667 g_date_set_dmy (&d, 4, 7, 1976); |
|
668 |
|
669 g_date_strftime (buf, 127, "%x", &d); |
|
670 |
|
671 g_date_fill_parse_tokens (buf, &testpt); |
|
672 |
|
673 i = 0; |
|
674 while (i < testpt.num_ints) |
|
675 { |
|
676 switch (testpt.n[i]) |
|
677 { |
|
678 case 7: |
|
679 dmy_order[i] = G_DATE_MONTH; |
|
680 break; |
|
681 case 4: |
|
682 dmy_order[i] = G_DATE_DAY; |
|
683 break; |
|
684 case 76: |
|
685 using_twodigit_years = TRUE; /* FALL THRU */ |
|
686 case 1976: |
|
687 dmy_order[i] = G_DATE_YEAR; |
|
688 break; |
|
689 default: |
|
690 /* assume locale era */ |
|
691 locale_era_adjust = 1976 - testpt.n[i]; |
|
692 dmy_order[i] = G_DATE_YEAR; |
|
693 break; |
|
694 } |
|
695 ++i; |
|
696 } |
|
697 |
|
698 #ifdef G_ENABLE_DEBUG |
|
699 DEBUG_MSG (("**GDate prepared a new set of locale-specific parse rules.")); |
|
700 i = 1; |
|
701 while (i < 13) |
|
702 { |
|
703 DEBUG_MSG ((" %s %s", long_month_names[i], short_month_names[i])); |
|
704 ++i; |
|
705 } |
|
706 if (using_twodigit_years) |
|
707 DEBUG_MSG (("**Using twodigit years with cutoff year: %u", twodigit_start_year)); |
|
708 { |
|
709 gchar *strings[3]; |
|
710 i = 0; |
|
711 while (i < 3) |
|
712 { |
|
713 switch (dmy_order[i]) |
|
714 { |
|
715 case G_DATE_MONTH: |
|
716 strings[i] = "Month"; |
|
717 break; |
|
718 case G_DATE_YEAR: |
|
719 strings[i] = "Year"; |
|
720 break; |
|
721 case G_DATE_DAY: |
|
722 strings[i] = "Day"; |
|
723 break; |
|
724 default: |
|
725 strings[i] = NULL; |
|
726 break; |
|
727 } |
|
728 ++i; |
|
729 } |
|
730 DEBUG_MSG (("**Order: %s, %s, %s", strings[0], strings[1], strings[2])); |
|
731 DEBUG_MSG (("**Sample date in this locale: `%s'", buf)); |
|
732 } |
|
733 #endif |
|
734 } |
|
735 |
|
736 g_date_fill_parse_tokens (str, pt); |
|
737 } |
|
738 |
|
739 EXPORT_C void |
|
740 g_date_set_parse (GDate *d, |
|
741 const gchar *str) |
|
742 { |
|
743 GDateParseTokens pt; |
|
744 guint m = G_DATE_BAD_MONTH, day = G_DATE_BAD_DAY, y = G_DATE_BAD_YEAR; |
|
745 |
|
746 g_return_if_fail (d != NULL); |
|
747 |
|
748 /* set invalid */ |
|
749 g_date_clear (d, 1); |
|
750 |
|
751 G_LOCK (g_date_global); |
|
752 |
|
753 g_date_prepare_to_parse (str, &pt); |
|
754 |
|
755 DEBUG_MSG (("Found %d ints, `%d' `%d' `%d' and written out month %d", |
|
756 pt.num_ints, pt.n[0], pt.n[1], pt.n[2], pt.month)); |
|
757 |
|
758 |
|
759 if (pt.num_ints == 4) |
|
760 { |
|
761 G_UNLOCK (g_date_global); |
|
762 return; /* presumably a typo; bail out. */ |
|
763 } |
|
764 |
|
765 if (pt.num_ints > 1) |
|
766 { |
|
767 int i = 0; |
|
768 int j = 0; |
|
769 |
|
770 g_assert (pt.num_ints < 4); /* i.e., it is 2 or 3 */ |
|
771 |
|
772 while (i < pt.num_ints && j < 3) |
|
773 { |
|
774 switch (dmy_order[j]) |
|
775 { |
|
776 case G_DATE_MONTH: |
|
777 { |
|
778 if (pt.num_ints == 2 && pt.month != G_DATE_BAD_MONTH) |
|
779 { |
|
780 m = pt.month; |
|
781 ++j; /* skip months, but don't skip this number */ |
|
782 continue; |
|
783 } |
|
784 else |
|
785 m = pt.n[i]; |
|
786 } |
|
787 break; |
|
788 case G_DATE_DAY: |
|
789 { |
|
790 if (pt.num_ints == 2 && pt.month == G_DATE_BAD_MONTH) |
|
791 { |
|
792 day = 1; |
|
793 ++j; /* skip days, since we may have month/year */ |
|
794 continue; |
|
795 } |
|
796 day = pt.n[i]; |
|
797 } |
|
798 break; |
|
799 case G_DATE_YEAR: |
|
800 { |
|
801 y = pt.n[i]; |
|
802 |
|
803 if (locale_era_adjust != 0) |
|
804 { |
|
805 y += locale_era_adjust; |
|
806 } |
|
807 else if (using_twodigit_years && y < 100) |
|
808 { |
|
809 guint two = twodigit_start_year % 100; |
|
810 guint century = (twodigit_start_year / 100) * 100; |
|
811 |
|
812 if (y < two) |
|
813 century += 100; |
|
814 |
|
815 y += century; |
|
816 } |
|
817 } |
|
818 break; |
|
819 default: |
|
820 break; |
|
821 } |
|
822 |
|
823 ++i; |
|
824 ++j; |
|
825 } |
|
826 |
|
827 |
|
828 if (pt.num_ints == 3 && !g_date_valid_dmy (day, m, y)) |
|
829 { |
|
830 /* Try YYYY MM DD */ |
|
831 y = pt.n[0]; |
|
832 m = pt.n[1]; |
|
833 day = pt.n[2]; |
|
834 |
|
835 if (using_twodigit_years && y < 100) |
|
836 y = G_DATE_BAD_YEAR; /* avoids ambiguity */ |
|
837 } |
|
838 else if (pt.num_ints == 2) |
|
839 { |
|
840 if (m == G_DATE_BAD_MONTH && pt.month != G_DATE_BAD_MONTH) |
|
841 { |
|
842 m = pt.month; |
|
843 } |
|
844 } |
|
845 } |
|
846 else if (pt.num_ints == 1) |
|
847 { |
|
848 if (pt.month != G_DATE_BAD_MONTH) |
|
849 { |
|
850 /* Month name and year? */ |
|
851 m = pt.month; |
|
852 day = 1; |
|
853 y = pt.n[0]; |
|
854 } |
|
855 else |
|
856 { |
|
857 /* Try yyyymmdd and yymmdd */ |
|
858 |
|
859 m = (pt.n[0]/100) % 100; |
|
860 day = pt.n[0] % 100; |
|
861 y = pt.n[0]/10000; |
|
862 |
|
863 /* FIXME move this into a separate function */ |
|
864 if (using_twodigit_years && y < 100) |
|
865 { |
|
866 guint two = twodigit_start_year % 100; |
|
867 guint century = (twodigit_start_year / 100) * 100; |
|
868 |
|
869 if (y < two) |
|
870 century += 100; |
|
871 |
|
872 y += century; |
|
873 } |
|
874 } |
|
875 } |
|
876 |
|
877 /* See if we got anything valid out of all this. */ |
|
878 /* y < 8000 is to catch 19998 style typos; the library is OK up to 65535 or so */ |
|
879 if (y < 8000 && g_date_valid_dmy (day, m, y)) |
|
880 { |
|
881 d->month = m; |
|
882 d->day = day; |
|
883 d->year = y; |
|
884 d->dmy = TRUE; |
|
885 } |
|
886 #ifdef G_ENABLE_DEBUG |
|
887 else |
|
888 DEBUG_MSG (("Rejected DMY %u %u %u", day, m, y)); |
|
889 #endif |
|
890 G_UNLOCK (g_date_global); |
|
891 } |
|
892 |
|
893 /** |
|
894 * g_date_set_time_t: |
|
895 * @date: a #GDate |
|
896 * @timet: <type>time_t</type> value to set |
|
897 * |
|
898 * Sets the value of a date from a <type>time_t</type> value. |
|
899 * |
|
900 * To set the value of a date to the current day, you could write: |
|
901 * <informalexample><programlisting> |
|
902 * g_date_set_time_t (date, time (NULL)); |
|
903 * </programlisting></informalexample> |
|
904 * |
|
905 * Since: 2.10 |
|
906 */ |
|
907 EXPORT_C void |
|
908 g_date_set_time_t (GDate *date, |
|
909 time_t timet) |
|
910 { |
|
911 struct tm tm; |
|
912 |
|
913 g_return_if_fail (date != NULL); |
|
914 |
|
915 #ifdef HAVE_LOCALTIME_R |
|
916 localtime_r (&timet, &tm); |
|
917 #else |
|
918 { |
|
919 struct tm *ptm = localtime (&timet); |
|
920 |
|
921 if (ptm == NULL) |
|
922 { |
|
923 /* Happens at least in Microsoft's C library if you pass a |
|
924 * negative time_t. Use 2000-01-01 as default date. |
|
925 */ |
|
926 #ifndef G_DISABLE_CHECKS |
|
927 g_return_if_fail_warning (G_LOG_DOMAIN, "g_date_set_time", "ptm != NULL"); |
|
928 #endif |
|
929 |
|
930 tm.tm_mon = 0; |
|
931 tm.tm_mday = 1; |
|
932 tm.tm_year = 100; |
|
933 } |
|
934 else |
|
935 memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm)); |
|
936 } |
|
937 #endif |
|
938 |
|
939 date->julian = FALSE; |
|
940 |
|
941 date->month = tm.tm_mon + 1; |
|
942 date->day = tm.tm_mday; |
|
943 date->year = tm.tm_year + 1900; |
|
944 |
|
945 g_return_if_fail (g_date_valid_dmy (date->day, date->month, date->year)); |
|
946 |
|
947 date->dmy = TRUE; |
|
948 } |
|
949 |
|
950 |
|
951 /** |
|
952 * g_date_set_time: |
|
953 * @date: a #GDate. |
|
954 * @time_: #GTime value to set. |
|
955 * |
|
956 * Sets the value of a date from a #GTime value. |
|
957 * |
|
958 * @Deprecated:2.10: Use g_date_set_time_t() instead. |
|
959 */ |
|
960 #ifndef __SYMBIAN32__ |
|
961 void |
|
962 g_date_set_time (GDate *date, |
|
963 GTime *time_) |
|
964 #else |
|
965 EXPORT_C void |
|
966 g_date_set_time (GDate *date, |
|
967 GTime time_) |
|
968 #endif /* __SYMBIAN32__ */ |
|
969 { |
|
970 g_date_set_time_t (date, (time_t) time_); |
|
971 } |
|
972 |
|
973 /** |
|
974 * g_date_set_time_val: |
|
975 * @date: a #GDate |
|
976 * @timeval: #GTimeVal value to set |
|
977 * |
|
978 * Sets the value of a date from a #GTimeVal value. Note that the |
|
979 * @tv_usec member is ignored, because #GDate can't make use of the |
|
980 * additional precision. |
|
981 * |
|
982 * Since: 2.10 |
|
983 */ |
|
984 EXPORT_C void |
|
985 g_date_set_time_val (GDate *date, |
|
986 GTimeVal *timeval) |
|
987 { |
|
988 g_date_set_time_t (date, (time_t) timeval->tv_sec); |
|
989 } |
|
990 |
|
991 EXPORT_C void |
|
992 g_date_set_month (GDate *d, |
|
993 GDateMonth m) |
|
994 { |
|
995 g_return_if_fail (d != NULL); |
|
996 g_return_if_fail (g_date_valid_month (m)); |
|
997 |
|
998 if (d->julian && !d->dmy) g_date_update_dmy(d); |
|
999 d->julian = FALSE; |
|
1000 |
|
1001 d->month = m; |
|
1002 |
|
1003 if (g_date_valid_dmy (d->day, d->month, d->year)) |
|
1004 d->dmy = TRUE; |
|
1005 else |
|
1006 d->dmy = FALSE; |
|
1007 } |
|
1008 |
|
1009 EXPORT_C void |
|
1010 g_date_set_day (GDate *d, |
|
1011 GDateDay day) |
|
1012 { |
|
1013 g_return_if_fail (d != NULL); |
|
1014 g_return_if_fail (g_date_valid_day (day)); |
|
1015 |
|
1016 if (d->julian && !d->dmy) g_date_update_dmy(d); |
|
1017 d->julian = FALSE; |
|
1018 |
|
1019 d->day = day; |
|
1020 |
|
1021 if (g_date_valid_dmy (d->day, d->month, d->year)) |
|
1022 d->dmy = TRUE; |
|
1023 else |
|
1024 d->dmy = FALSE; |
|
1025 } |
|
1026 |
|
1027 EXPORT_C void |
|
1028 g_date_set_year (GDate *d, |
|
1029 GDateYear y) |
|
1030 { |
|
1031 g_return_if_fail (d != NULL); |
|
1032 g_return_if_fail (g_date_valid_year (y)); |
|
1033 |
|
1034 if (d->julian && !d->dmy) g_date_update_dmy(d); |
|
1035 d->julian = FALSE; |
|
1036 |
|
1037 d->year = y; |
|
1038 |
|
1039 if (g_date_valid_dmy (d->day, d->month, d->year)) |
|
1040 d->dmy = TRUE; |
|
1041 else |
|
1042 d->dmy = FALSE; |
|
1043 } |
|
1044 |
|
1045 EXPORT_C void |
|
1046 g_date_set_dmy (GDate *d, |
|
1047 GDateDay day, |
|
1048 GDateMonth m, |
|
1049 GDateYear y) |
|
1050 { |
|
1051 g_return_if_fail (d != NULL); |
|
1052 g_return_if_fail (g_date_valid_dmy (day, m, y)); |
|
1053 |
|
1054 d->julian = FALSE; |
|
1055 |
|
1056 d->month = m; |
|
1057 d->day = day; |
|
1058 d->year = y; |
|
1059 |
|
1060 d->dmy = TRUE; |
|
1061 } |
|
1062 |
|
1063 EXPORT_C void |
|
1064 g_date_set_julian (GDate *d, guint32 j) |
|
1065 { |
|
1066 g_return_if_fail (d != NULL); |
|
1067 g_return_if_fail (g_date_valid_julian (j)); |
|
1068 |
|
1069 d->julian_days = j; |
|
1070 d->julian = TRUE; |
|
1071 d->dmy = FALSE; |
|
1072 } |
|
1073 |
|
1074 |
|
1075 EXPORT_C gboolean |
|
1076 g_date_is_first_of_month (const GDate *d) |
|
1077 { |
|
1078 g_return_val_if_fail (g_date_valid (d), FALSE); |
|
1079 |
|
1080 if (!d->dmy) |
|
1081 { |
|
1082 g_date_update_dmy (d); |
|
1083 } |
|
1084 g_return_val_if_fail (d->dmy, FALSE); |
|
1085 |
|
1086 if (d->day == 1) return TRUE; |
|
1087 else return FALSE; |
|
1088 } |
|
1089 |
|
1090 EXPORT_C gboolean |
|
1091 g_date_is_last_of_month (const GDate *d) |
|
1092 { |
|
1093 gint index; |
|
1094 |
|
1095 g_return_val_if_fail (g_date_valid (d), FALSE); |
|
1096 |
|
1097 if (!d->dmy) |
|
1098 { |
|
1099 g_date_update_dmy (d); |
|
1100 } |
|
1101 g_return_val_if_fail (d->dmy, FALSE); |
|
1102 |
|
1103 index = g_date_is_leap_year (d->year) ? 1 : 0; |
|
1104 |
|
1105 if (d->day == days_in_months[index][d->month]) return TRUE; |
|
1106 else return FALSE; |
|
1107 } |
|
1108 |
|
1109 EXPORT_C void |
|
1110 g_date_add_days (GDate *d, guint ndays) |
|
1111 { |
|
1112 g_return_if_fail (g_date_valid (d)); |
|
1113 |
|
1114 if (!d->julian) |
|
1115 { |
|
1116 g_date_update_julian (d); |
|
1117 } |
|
1118 g_return_if_fail (d->julian); |
|
1119 |
|
1120 d->julian_days += ndays; |
|
1121 d->dmy = FALSE; |
|
1122 } |
|
1123 |
|
1124 EXPORT_C void |
|
1125 g_date_subtract_days (GDate *d, guint ndays) |
|
1126 { |
|
1127 g_return_if_fail (g_date_valid (d)); |
|
1128 |
|
1129 if (!d->julian) |
|
1130 { |
|
1131 g_date_update_julian (d); |
|
1132 } |
|
1133 g_return_if_fail (d->julian); |
|
1134 g_return_if_fail (d->julian_days > ndays); |
|
1135 |
|
1136 d->julian_days -= ndays; |
|
1137 d->dmy = FALSE; |
|
1138 } |
|
1139 |
|
1140 EXPORT_C void |
|
1141 g_date_add_months (GDate *d, |
|
1142 guint nmonths) |
|
1143 { |
|
1144 guint years, months; |
|
1145 gint index; |
|
1146 |
|
1147 g_return_if_fail (g_date_valid (d)); |
|
1148 |
|
1149 if (!d->dmy) |
|
1150 { |
|
1151 g_date_update_dmy (d); |
|
1152 } |
|
1153 g_return_if_fail (d->dmy); |
|
1154 |
|
1155 nmonths += d->month - 1; |
|
1156 |
|
1157 years = nmonths/12; |
|
1158 months = nmonths%12; |
|
1159 |
|
1160 d->month = months + 1; |
|
1161 d->year += years; |
|
1162 |
|
1163 index = g_date_is_leap_year (d->year) ? 1 : 0; |
|
1164 |
|
1165 if (d->day > days_in_months[index][d->month]) |
|
1166 d->day = days_in_months[index][d->month]; |
|
1167 |
|
1168 d->julian = FALSE; |
|
1169 |
|
1170 g_return_if_fail (g_date_valid (d)); |
|
1171 } |
|
1172 |
|
1173 EXPORT_C void |
|
1174 g_date_subtract_months (GDate *d, |
|
1175 guint nmonths) |
|
1176 { |
|
1177 guint years, months; |
|
1178 gint index; |
|
1179 |
|
1180 g_return_if_fail (g_date_valid (d)); |
|
1181 |
|
1182 if (!d->dmy) |
|
1183 { |
|
1184 g_date_update_dmy (d); |
|
1185 } |
|
1186 g_return_if_fail (d->dmy); |
|
1187 |
|
1188 years = nmonths/12; |
|
1189 months = nmonths%12; |
|
1190 |
|
1191 g_return_if_fail (d->year > years); |
|
1192 |
|
1193 d->year -= years; |
|
1194 |
|
1195 if (d->month > months) d->month -= months; |
|
1196 else |
|
1197 { |
|
1198 months -= d->month; |
|
1199 d->month = 12 - months; |
|
1200 d->year -= 1; |
|
1201 } |
|
1202 |
|
1203 index = g_date_is_leap_year (d->year) ? 1 : 0; |
|
1204 |
|
1205 if (d->day > days_in_months[index][d->month]) |
|
1206 d->day = days_in_months[index][d->month]; |
|
1207 |
|
1208 d->julian = FALSE; |
|
1209 |
|
1210 g_return_if_fail (g_date_valid (d)); |
|
1211 } |
|
1212 |
|
1213 EXPORT_C void |
|
1214 g_date_add_years (GDate *d, |
|
1215 guint nyears) |
|
1216 { |
|
1217 g_return_if_fail (g_date_valid (d)); |
|
1218 |
|
1219 if (!d->dmy) |
|
1220 { |
|
1221 g_date_update_dmy (d); |
|
1222 } |
|
1223 g_return_if_fail (d->dmy); |
|
1224 |
|
1225 d->year += nyears; |
|
1226 |
|
1227 if (d->month == 2 && d->day == 29) |
|
1228 { |
|
1229 if (!g_date_is_leap_year (d->year)) |
|
1230 { |
|
1231 d->day = 28; |
|
1232 } |
|
1233 } |
|
1234 |
|
1235 d->julian = FALSE; |
|
1236 } |
|
1237 |
|
1238 EXPORT_C void |
|
1239 g_date_subtract_years (GDate *d, |
|
1240 guint nyears) |
|
1241 { |
|
1242 g_return_if_fail (g_date_valid (d)); |
|
1243 |
|
1244 if (!d->dmy) |
|
1245 { |
|
1246 g_date_update_dmy (d); |
|
1247 } |
|
1248 g_return_if_fail (d->dmy); |
|
1249 g_return_if_fail (d->year > nyears); |
|
1250 |
|
1251 d->year -= nyears; |
|
1252 |
|
1253 if (d->month == 2 && d->day == 29) |
|
1254 { |
|
1255 if (!g_date_is_leap_year (d->year)) |
|
1256 { |
|
1257 d->day = 28; |
|
1258 } |
|
1259 } |
|
1260 |
|
1261 d->julian = FALSE; |
|
1262 } |
|
1263 |
|
1264 |
|
1265 EXPORT_C gboolean |
|
1266 g_date_is_leap_year (GDateYear year) |
|
1267 { |
|
1268 g_return_val_if_fail (g_date_valid_year (year), FALSE); |
|
1269 |
|
1270 return ( (((year % 4) == 0) && ((year % 100) != 0)) || |
|
1271 (year % 400) == 0 ); |
|
1272 } |
|
1273 |
|
1274 EXPORT_C guint8 |
|
1275 g_date_get_days_in_month (GDateMonth month, |
|
1276 GDateYear year) |
|
1277 { |
|
1278 gint index; |
|
1279 |
|
1280 g_return_val_if_fail (g_date_valid_year (year), 0); |
|
1281 g_return_val_if_fail (g_date_valid_month (month), 0); |
|
1282 |
|
1283 index = g_date_is_leap_year (year) ? 1 : 0; |
|
1284 |
|
1285 return days_in_months[index][month]; |
|
1286 } |
|
1287 |
|
1288 EXPORT_C guint8 |
|
1289 g_date_get_monday_weeks_in_year (GDateYear year) |
|
1290 { |
|
1291 GDate d; |
|
1292 |
|
1293 g_return_val_if_fail (g_date_valid_year (year), 0); |
|
1294 |
|
1295 g_date_clear (&d, 1); |
|
1296 g_date_set_dmy (&d, 1, 1, year); |
|
1297 if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; |
|
1298 g_date_set_dmy (&d, 31, 12, year); |
|
1299 if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; |
|
1300 if (g_date_is_leap_year (year)) |
|
1301 { |
|
1302 g_date_set_dmy (&d, 2, 1, year); |
|
1303 if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; |
|
1304 g_date_set_dmy (&d, 30, 12, year); |
|
1305 if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53; |
|
1306 } |
|
1307 return 52; |
|
1308 } |
|
1309 |
|
1310 EXPORT_C guint8 |
|
1311 g_date_get_sunday_weeks_in_year (GDateYear year) |
|
1312 { |
|
1313 GDate d; |
|
1314 |
|
1315 g_return_val_if_fail (g_date_valid_year (year), 0); |
|
1316 |
|
1317 g_date_clear (&d, 1); |
|
1318 g_date_set_dmy (&d, 1, 1, year); |
|
1319 if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; |
|
1320 g_date_set_dmy (&d, 31, 12, year); |
|
1321 if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; |
|
1322 if (g_date_is_leap_year (year)) |
|
1323 { |
|
1324 g_date_set_dmy (&d, 2, 1, year); |
|
1325 if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; |
|
1326 g_date_set_dmy (&d, 30, 12, year); |
|
1327 if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53; |
|
1328 } |
|
1329 return 52; |
|
1330 } |
|
1331 |
|
1332 EXPORT_C gint |
|
1333 g_date_compare (const GDate *lhs, |
|
1334 const GDate *rhs) |
|
1335 { |
|
1336 g_return_val_if_fail (lhs != NULL, 0); |
|
1337 g_return_val_if_fail (rhs != NULL, 0); |
|
1338 g_return_val_if_fail (g_date_valid (lhs), 0); |
|
1339 g_return_val_if_fail (g_date_valid (rhs), 0); |
|
1340 |
|
1341 /* Remember the self-comparison case! I think it works right now. */ |
|
1342 |
|
1343 while (TRUE) |
|
1344 { |
|
1345 |
|
1346 if (lhs->julian && rhs->julian) |
|
1347 { |
|
1348 if (lhs->julian_days < rhs->julian_days) return -1; |
|
1349 else if (lhs->julian_days > rhs->julian_days) return 1; |
|
1350 else return 0; |
|
1351 } |
|
1352 else if (lhs->dmy && rhs->dmy) |
|
1353 { |
|
1354 if (lhs->year < rhs->year) return -1; |
|
1355 else if (lhs->year > rhs->year) return 1; |
|
1356 else |
|
1357 { |
|
1358 if (lhs->month < rhs->month) return -1; |
|
1359 else if (lhs->month > rhs->month) return 1; |
|
1360 else |
|
1361 { |
|
1362 if (lhs->day < rhs->day) return -1; |
|
1363 else if (lhs->day > rhs->day) return 1; |
|
1364 else return 0; |
|
1365 } |
|
1366 |
|
1367 } |
|
1368 |
|
1369 } |
|
1370 else |
|
1371 { |
|
1372 if (!lhs->julian) g_date_update_julian (lhs); |
|
1373 if (!rhs->julian) g_date_update_julian (rhs); |
|
1374 g_return_val_if_fail (lhs->julian, 0); |
|
1375 g_return_val_if_fail (rhs->julian, 0); |
|
1376 } |
|
1377 |
|
1378 } |
|
1379 return 0; /* warnings */ |
|
1380 } |
|
1381 |
|
1382 |
|
1383 EXPORT_C void |
|
1384 g_date_to_struct_tm (const GDate *d, |
|
1385 struct tm *tm) |
|
1386 { |
|
1387 GDateWeekday day; |
|
1388 |
|
1389 g_return_if_fail (g_date_valid (d)); |
|
1390 g_return_if_fail (tm != NULL); |
|
1391 |
|
1392 if (!d->dmy) |
|
1393 { |
|
1394 g_date_update_dmy (d); |
|
1395 } |
|
1396 g_return_if_fail (d->dmy); |
|
1397 |
|
1398 /* zero all the irrelevant fields to be sure they're valid */ |
|
1399 |
|
1400 /* On Linux and maybe other systems, there are weird non-POSIX |
|
1401 * fields on the end of struct tm that choke strftime if they |
|
1402 * contain garbage. So we need to 0 the entire struct, not just the |
|
1403 * fields we know to exist. |
|
1404 */ |
|
1405 |
|
1406 memset (tm, 0x0, sizeof (struct tm)); |
|
1407 |
|
1408 tm->tm_mday = d->day; |
|
1409 tm->tm_mon = d->month - 1; /* 0-11 goes in tm */ |
|
1410 tm->tm_year = ((int)d->year) - 1900; /* X/Open says tm_year can be negative */ |
|
1411 |
|
1412 day = g_date_get_weekday (d); |
|
1413 if (day == 7) day = 0; /* struct tm wants days since Sunday, so Sunday is 0 */ |
|
1414 |
|
1415 tm->tm_wday = (int)day; |
|
1416 |
|
1417 tm->tm_yday = g_date_get_day_of_year (d) - 1; /* 0 to 365 */ |
|
1418 tm->tm_isdst = -1; /* -1 means "information not available" */ |
|
1419 } |
|
1420 |
|
1421 EXPORT_C void |
|
1422 g_date_clamp (GDate *date, |
|
1423 const GDate *min_date, |
|
1424 const GDate *max_date) |
|
1425 { |
|
1426 g_return_if_fail (g_date_valid (date)); |
|
1427 |
|
1428 if (min_date != NULL) |
|
1429 g_return_if_fail (g_date_valid (min_date)); |
|
1430 if (max_date != NULL) |
|
1431 g_return_if_fail (g_date_valid (max_date)); |
|
1432 if (min_date != NULL && max_date != NULL) |
|
1433 g_return_if_fail (g_date_compare (min_date, max_date) <= 0); |
|
1434 |
|
1435 if (min_date && g_date_compare (date, min_date) < 0) |
|
1436 *date = *min_date; |
|
1437 |
|
1438 if (max_date && g_date_compare (max_date, date) < 0) |
|
1439 *date = *max_date; |
|
1440 } |
|
1441 |
|
1442 EXPORT_C void |
|
1443 g_date_order (GDate *date1, |
|
1444 GDate *date2) |
|
1445 { |
|
1446 g_return_if_fail (g_date_valid (date1)); |
|
1447 g_return_if_fail (g_date_valid (date2)); |
|
1448 |
|
1449 if (g_date_compare (date1, date2) > 0) |
|
1450 { |
|
1451 GDate tmp = *date1; |
|
1452 *date1 = *date2; |
|
1453 *date2 = tmp; |
|
1454 } |
|
1455 } |
|
1456 |
|
1457 EXPORT_C gsize |
|
1458 g_date_strftime (gchar *s, |
|
1459 gsize slen, |
|
1460 const gchar *format, |
|
1461 const GDate *d) |
|
1462 { |
|
1463 struct tm tm; |
|
1464 gsize locale_format_len = 0; |
|
1465 gchar *locale_format; |
|
1466 gsize tmplen; |
|
1467 gchar *tmpbuf; |
|
1468 gsize tmpbufsize; |
|
1469 gsize convlen = 0; |
|
1470 gchar *convbuf; |
|
1471 GError *error = NULL; |
|
1472 gsize retval; |
|
1473 |
|
1474 g_return_val_if_fail (g_date_valid (d), 0); |
|
1475 g_return_val_if_fail (slen > 0, 0); |
|
1476 g_return_val_if_fail (format != 0, 0); |
|
1477 g_return_val_if_fail (s != 0, 0); |
|
1478 |
|
1479 g_date_to_struct_tm (d, &tm); |
|
1480 |
|
1481 locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error); |
|
1482 |
|
1483 if (error) |
|
1484 { |
|
1485 g_warning (G_STRLOC "Error converting format to locale encoding: %s\n", error->message); |
|
1486 g_error_free (error); |
|
1487 |
|
1488 s[0] = '\0'; |
|
1489 return 0; |
|
1490 } |
|
1491 |
|
1492 tmpbufsize = MAX (128, locale_format_len * 2); |
|
1493 while (TRUE) |
|
1494 { |
|
1495 tmpbuf = g_malloc (tmpbufsize); |
|
1496 |
|
1497 /* Set the first byte to something other than '\0', to be able to |
|
1498 * recognize whether strftime actually failed or just returned "". |
|
1499 */ |
|
1500 tmpbuf[0] = '\1'; |
|
1501 tmplen = strftime (tmpbuf, tmpbufsize, locale_format, &tm); |
|
1502 |
|
1503 if (tmplen == 0 && tmpbuf[0] != '\0') |
|
1504 { |
|
1505 g_free (tmpbuf); |
|
1506 tmpbufsize *= 2; |
|
1507 |
|
1508 if (tmpbufsize > 65536) |
|
1509 { |
|
1510 g_warning (G_STRLOC "Maximum buffer size for g_date_strftime exceeded: giving up\n"); |
|
1511 g_free (locale_format); |
|
1512 |
|
1513 s[0] = '\0'; |
|
1514 return 0; |
|
1515 } |
|
1516 } |
|
1517 else |
|
1518 break; |
|
1519 } |
|
1520 g_free (locale_format); |
|
1521 |
|
1522 convbuf = g_locale_to_utf8 (tmpbuf, tmplen, NULL, &convlen, &error); |
|
1523 g_free (tmpbuf); |
|
1524 |
|
1525 if (error) |
|
1526 { |
|
1527 g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s\n", error->message); |
|
1528 g_error_free (error); |
|
1529 |
|
1530 s[0] = '\0'; |
|
1531 return 0; |
|
1532 } |
|
1533 |
|
1534 if (slen <= convlen) |
|
1535 { |
|
1536 /* Ensure only whole characters are copied into the buffer. |
|
1537 */ |
|
1538 gchar *end = g_utf8_find_prev_char (convbuf, convbuf + slen); |
|
1539 g_assert (end != NULL); |
|
1540 convlen = end - convbuf; |
|
1541 |
|
1542 /* Return 0 because the buffer isn't large enough. |
|
1543 */ |
|
1544 retval = 0; |
|
1545 } |
|
1546 else |
|
1547 retval = convlen; |
|
1548 |
|
1549 memcpy (s, convbuf, convlen); |
|
1550 s[convlen] = '\0'; |
|
1551 g_free (convbuf); |
|
1552 |
|
1553 return retval; |
|
1554 } |
|
1555 |
|
1556 #define __G_DATE_C__ |
|
1557 #include "galiasdef.c" |
|
1558 |