00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034
00035 #include "glib.h"
00036
00037 #include <time.h>
00038 #include <string.h>
00039 #include <ctype.h>
00040 #include <stdlib.h>
00041 #include <locale.h>
00042
00043 GDate*
00044 g_date_new ()
00045 {
00046 GDate *d = g_new0 (GDate, 1);
00047
00048 return d;
00049 }
00050
00051 GDate*
00052 g_date_new_dmy (GDateDay day, GDateMonth m, GDateYear y)
00053 {
00054 GDate *d;
00055 g_return_val_if_fail (g_date_valid_dmy (day, m, y), NULL);
00056
00057 d = g_new (GDate, 1);
00058
00059 d->julian = FALSE;
00060 d->dmy = TRUE;
00061
00062 d->month = m;
00063 d->day = day;
00064 d->year = y;
00065
00066 g_assert (g_date_valid (d));
00067
00068 return d;
00069 }
00070
00071 GDate*
00072 g_date_new_julian (guint32 j)
00073 {
00074 GDate *d;
00075 g_return_val_if_fail (g_date_valid_julian (j), NULL);
00076
00077 d = g_new (GDate, 1);
00078
00079 d->julian = TRUE;
00080 d->dmy = FALSE;
00081
00082 d->julian_days = j;
00083
00084 g_assert (g_date_valid (d));
00085
00086 return d;
00087 }
00088
00089 void
00090 g_date_free (GDate *d)
00091 {
00092 g_return_if_fail (d != NULL);
00093
00094 g_free (d);
00095 }
00096
00097 gboolean
00098 g_date_valid (GDate *d)
00099 {
00100 g_return_val_if_fail (d != NULL, FALSE);
00101
00102 return (d->julian || d->dmy);
00103 }
00104
00105 static const guint8 days_in_months[2][13] =
00106 {
00107 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00108 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00109 };
00110
00111 static const guint16 days_in_year[2][14] =
00112 {
00113 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
00114 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
00115 };
00116
00117 gboolean
00118 g_date_valid_month (GDateMonth m)
00119 {
00120 return ( (m > G_DATE_BAD_MONTH) && (m < 13) );
00121 }
00122
00123 gboolean
00124 g_date_valid_year (GDateYear y)
00125 {
00126 return ( y > G_DATE_BAD_YEAR );
00127 }
00128
00129 gboolean
00130 g_date_valid_day (GDateDay d)
00131 {
00132 return ( (d > G_DATE_BAD_DAY) && (d < 32) );
00133 }
00134
00135 gboolean
00136 g_date_valid_weekday (GDateWeekday w)
00137 {
00138 return ( (w > G_DATE_BAD_WEEKDAY) && (w < 8) );
00139 }
00140
00141 gboolean
00142 g_date_valid_julian (guint32 j)
00143 {
00144 return (j > G_DATE_BAD_JULIAN);
00145 }
00146
00147 gboolean
00148 g_date_valid_dmy (GDateDay d,
00149 GDateMonth m,
00150 GDateYear y)
00151 {
00152 return ( (m > G_DATE_BAD_MONTH) &&
00153 (m < 13) &&
00154 (d > G_DATE_BAD_DAY) &&
00155 (y > G_DATE_BAD_YEAR) &&
00156 (d <= (g_date_is_leap_year (y) ?
00157 days_in_months[1][m] : days_in_months[0][m])) );
00158 }
00159
00160
00161
00162
00163
00164 static void
00165 g_date_update_julian (GDate *d)
00166 {
00167 GDateYear year;
00168 gint index;
00169
00170 g_return_if_fail (d != NULL);
00171 g_return_if_fail (d->dmy);
00172 g_return_if_fail (!d->julian);
00173 g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year));
00174
00175
00176
00177
00178
00179
00180
00181
00182 year = d->year - 1;
00183
00184 d->julian_days = year * 365U;
00185 d->julian_days += (year >>= 2);
00186 d->julian_days -= (year /= 25);
00187 d->julian_days += year >> 2;
00188
00189 index = g_date_is_leap_year (d->year) ? 1 : 0;
00190
00191 d->julian_days += days_in_year[index][d->month] + d->day;
00192
00193 g_return_if_fail (g_date_valid_julian (d->julian_days));
00194
00195 d->julian = TRUE;
00196 }
00197
00198 static void
00199 g_date_update_dmy (GDate *d)
00200 {
00201 GDateYear y;
00202 GDateMonth m;
00203 GDateDay day;
00204
00205 guint32 A, B, C, D, E, M;
00206
00207 g_return_if_fail (d != NULL);
00208 g_return_if_fail (d->julian);
00209 g_return_if_fail (!d->dmy);
00210 g_return_if_fail (g_date_valid_julian (d->julian_days));
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 A = d->julian_days + 1721425 + 32045;
00221 B = ( 4 *(A + 36524) )/ 146097 - 1;
00222 C = A - (146097 * B)/4;
00223 D = ( 4 * (C + 365) ) / 1461 - 1;
00224 E = C - ((1461*D) / 4);
00225 M = (5 * (E - 1) + 2)/153;
00226
00227 m = M + 3 - (12*(M/10));
00228 day = E - (153*M + 2)/5;
00229 y = 100 * B + D - 4800 + (M/10);
00230
00231 #ifdef G_ENABLE_DEBUG
00232 if (!g_date_valid_dmy (day, m, y))
00233 {
00234 g_warning ("\nOOPS julian: %u computed dmy: %u %u %u\n",
00235 d->julian_days, day, m, y);
00236 }
00237 #endif
00238
00239 d->month = m;
00240 d->day = day;
00241 d->year = y;
00242
00243 d->dmy = TRUE;
00244 }
00245
00246 GDateWeekday
00247 g_date_weekday (GDate *d)
00248 {
00249 g_return_val_if_fail (d != NULL, G_DATE_BAD_WEEKDAY);
00250 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_WEEKDAY);
00251
00252 if (!d->julian)
00253 {
00254 g_date_update_julian (d);
00255 }
00256 g_return_val_if_fail (d->julian, G_DATE_BAD_WEEKDAY);
00257
00258 return ((d->julian_days - 1) % 7) + 1;
00259 }
00260
00261 GDateMonth
00262 g_date_month (GDate *d)
00263 {
00264 g_return_val_if_fail (d != NULL, G_DATE_BAD_MONTH);
00265 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_MONTH);
00266
00267 if (!d->dmy)
00268 {
00269 g_date_update_dmy (d);
00270 }
00271 g_return_val_if_fail (d->dmy, G_DATE_BAD_MONTH);
00272
00273 return d->month;
00274 }
00275
00276 GDateYear
00277 g_date_year (GDate *d)
00278 {
00279 g_return_val_if_fail (d != NULL, G_DATE_BAD_YEAR);
00280 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_YEAR);
00281
00282 if (!d->dmy)
00283 {
00284 g_date_update_dmy (d);
00285 }
00286 g_return_val_if_fail (d->dmy, G_DATE_BAD_YEAR);
00287
00288 return d->year;
00289 }
00290
00291 GDateDay
00292 g_date_day (GDate *d)
00293 {
00294 g_return_val_if_fail (d != NULL, G_DATE_BAD_DAY);
00295 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_DAY);
00296
00297 if (!d->dmy)
00298 {
00299 g_date_update_dmy (d);
00300 }
00301 g_return_val_if_fail (d->dmy, G_DATE_BAD_DAY);
00302
00303 return d->day;
00304 }
00305
00306 guint32
00307 g_date_julian (GDate *d)
00308 {
00309 g_return_val_if_fail (d != NULL, G_DATE_BAD_JULIAN);
00310 g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_JULIAN);
00311
00312 if (!d->julian)
00313 {
00314 g_date_update_julian (d);
00315 }
00316 g_return_val_if_fail (d->julian, G_DATE_BAD_JULIAN);
00317
00318 return d->julian_days;
00319 }
00320
00321 guint
00322 g_date_day_of_year (GDate *d)
00323 {
00324 gint index;
00325
00326 g_return_val_if_fail (d != NULL, 0);
00327 g_return_val_if_fail (g_date_valid (d), 0);
00328
00329 if (!d->dmy)
00330 {
00331 g_date_update_dmy (d);
00332 }
00333 g_return_val_if_fail (d->dmy, 0);
00334
00335 index = g_date_is_leap_year (d->year) ? 1 : 0;
00336
00337 return (days_in_year[index][d->month] + d->day);
00338 }
00339
00340 guint
00341 g_date_monday_week_of_year (GDate *d)
00342 {
00343 GDateWeekday wd;
00344 guint day;
00345 GDate first;
00346
00347 g_return_val_if_fail (d != NULL, 0);
00348 g_return_val_if_fail (g_date_valid (d), 0);
00349
00350 if (!d->dmy)
00351 {
00352 g_date_update_dmy (d);
00353 }
00354 g_return_val_if_fail (d->dmy, 0);
00355
00356 g_date_clear (&first, 1);
00357
00358 g_date_set_dmy (&first, 1, 1, d->year);
00359
00360 wd = g_date_weekday (&first) - 1;
00361 day = g_date_day_of_year (d) - 1;
00362
00363 return ((day + wd)/7U + (wd == 0 ? 1 : 0));
00364 }
00365
00366 guint
00367 g_date_sunday_week_of_year (GDate *d)
00368 {
00369 GDateWeekday wd;
00370 guint day;
00371 GDate first;
00372
00373 g_return_val_if_fail (d != NULL, 0);
00374 g_return_val_if_fail (g_date_valid (d), 0);
00375
00376 if (!d->dmy)
00377 {
00378 g_date_update_dmy (d);
00379 }
00380 g_return_val_if_fail (d->dmy, 0);
00381
00382 g_date_clear (&first, 1);
00383
00384 g_date_set_dmy (&first, 1, 1, d->year);
00385
00386 wd = g_date_weekday (&first);
00387 if (wd == 7) wd = 0;
00388 day = g_date_day_of_year (d) - 1;
00389
00390 return ((day + wd)/7U + (wd == 0 ? 1 : 0));
00391 }
00392
00393 void
00394 g_date_clear (GDate *d, guint ndates)
00395 {
00396 g_return_if_fail (d != NULL);
00397 g_return_if_fail (ndates != 0);
00398
00399 memset (d, 0x0, ndates*sizeof (GDate));
00400 }
00401
00402 G_LOCK_DEFINE_STATIC (g_date_global);
00403
00404
00405
00406
00407
00408
00409 static gchar *long_month_names[13] =
00410 {
00411 "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
00412 };
00413
00414 static gchar *short_month_names[13] =
00415 {
00416 "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
00417 };
00418
00419
00420 static gchar *current_locale = NULL;
00421
00422
00423 static GDateDMY dmy_order[3] =
00424 {
00425 G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR
00426 };
00427
00428
00429
00430
00431
00432
00433 static GDateYear twodigit_start_year = 1930;
00434
00435
00436
00437
00438 static gboolean using_twodigit_years = FALSE;
00439
00440 struct _GDateParseTokens {
00441 gint num_ints;
00442 gint n[3];
00443 guint month;
00444 };
00445
00446 typedef struct _GDateParseTokens GDateParseTokens;
00447
00448 #define NUM_LEN 10
00449
00450
00451 static void
00452 g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
00453 {
00454 gchar num[4][NUM_LEN+1];
00455 gint i;
00456 const guchar *s;
00457
00458
00459
00460
00461 num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0';
00462
00463 s = str;
00464 pt->num_ints = 0;
00465 while (*s && pt->num_ints < 4)
00466 {
00467
00468 i = 0;
00469 while (*s && isdigit (*s) && i <= NUM_LEN)
00470 {
00471 num[pt->num_ints][i] = *s;
00472 ++s;
00473 ++i;
00474 }
00475
00476 if (i > 0)
00477 {
00478 num[pt->num_ints][i] = '\0';
00479 ++(pt->num_ints);
00480 }
00481
00482 if (*s == '\0') break;
00483
00484 ++s;
00485 }
00486
00487 pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0;
00488 pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0;
00489 pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0;
00490
00491 pt->month = G_DATE_BAD_MONTH;
00492
00493 if (pt->num_ints < 3)
00494 {
00495 gchar lcstr[128];
00496 int i = 1;
00497
00498 strncpy (lcstr, str, 127);
00499 g_strdown (lcstr);
00500
00501 while (i < 13)
00502 {
00503 if (long_month_names[i] != NULL)
00504 {
00505 const gchar *found = strstr (lcstr, long_month_names[i]);
00506
00507 if (found != NULL)
00508 {
00509 pt->month = i;
00510 return;
00511 }
00512 }
00513
00514 if (short_month_names[i] != NULL)
00515 {
00516 const gchar *found = strstr (lcstr, short_month_names[i]);
00517
00518 if (found != NULL)
00519 {
00520 pt->month = i;
00521 return;
00522 }
00523 }
00524
00525 ++i;
00526 }
00527 }
00528 }
00529
00530
00531 static void
00532 g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
00533 {
00534 const gchar *locale = setlocale (LC_TIME, NULL);
00535 gboolean recompute_localeinfo = FALSE;
00536 GDate d;
00537
00538 g_return_if_fail (locale != NULL);
00539
00540 g_date_clear (&d, 1);
00541
00542 if ( (current_locale == NULL) || (strcmp (locale, current_locale) != 0) )
00543 {
00544 recompute_localeinfo = TRUE;
00545 }
00546
00547 if (recompute_localeinfo)
00548 {
00549 int i = 1;
00550 GDateParseTokens testpt;
00551 gchar buf[128];
00552
00553 g_free (current_locale);
00554
00555 current_locale = g_strdup (locale);
00556
00557 while (i < 13)
00558 {
00559 g_date_set_dmy (&d, 1, i, 1);
00560
00561 g_return_if_fail (g_date_valid (&d));
00562
00563 g_date_strftime (buf, 127, "%b", &d);
00564 g_free (short_month_names[i]);
00565 g_strdown (buf);
00566 short_month_names[i] = g_strdup (buf);
00567
00568
00569
00570 g_date_strftime (buf, 127, "%B", &d);
00571 g_free (long_month_names[i]);
00572 g_strdown (buf);
00573 long_month_names[i] = g_strdup (buf);
00574
00575 ++i;
00576 }
00577
00578
00579
00580
00581
00582 g_date_set_dmy (&d, 4, 7, 1976);
00583
00584 g_date_strftime (buf, 127, "%x", &d);
00585
00586 g_date_fill_parse_tokens (buf, &testpt);
00587
00588 i = 0;
00589 while (i < testpt.num_ints)
00590 {
00591 switch (testpt.n[i])
00592 {
00593 case 7:
00594 dmy_order[i] = G_DATE_MONTH;
00595 break;
00596 case 4:
00597 dmy_order[i] = G_DATE_DAY;
00598 break;
00599 case 76:
00600 using_twodigit_years = TRUE;
00601 case 1976:
00602 dmy_order[i] = G_DATE_YEAR;
00603 break;
00604 default:
00605
00606 break;
00607 }
00608 ++i;
00609 }
00610
00611 #ifdef G_ENABLE_DEBUG
00612 g_message ("**GDate prepared a new set of locale-specific parse rules.");
00613 i = 1;
00614 while (i < 13)
00615 {
00616 g_message (" %s %s", long_month_names[i], short_month_names[i]);
00617 ++i;
00618 }
00619 if (using_twodigit_years)
00620 {
00621 g_message ("**Using twodigit years with cutoff year: %u", twodigit_start_year);
00622 }
00623 {
00624 gchar *strings[3];
00625 i = 0;
00626 while (i < 3)
00627 {
00628 switch (dmy_order[i])
00629 {
00630 case G_DATE_MONTH:
00631 strings[i] = "Month";
00632 break;
00633 case G_DATE_YEAR:
00634 strings[i] = "Year";
00635 break;
00636 case G_DATE_DAY:
00637 strings[i] = "Day";
00638 break;
00639 default:
00640 strings[i] = NULL;
00641 break;
00642 }
00643 ++i;
00644 }
00645 g_message ("**Order: %s, %s, %s", strings[0], strings[1], strings[2]);
00646 g_message ("**Sample date in this locale: `%s'", buf);
00647 }
00648 #endif
00649 }
00650
00651 g_date_fill_parse_tokens (str, pt);
00652 }
00653
00654 void
00655 g_date_set_parse (GDate *d,
00656 const gchar *str)
00657 {
00658 GDateParseTokens pt;
00659 guint m = G_DATE_BAD_MONTH, day = G_DATE_BAD_DAY, y = G_DATE_BAD_YEAR;
00660
00661 g_return_if_fail (d != NULL);
00662
00663
00664 g_date_clear (d, 1);
00665
00666 G_LOCK (g_date_global);
00667
00668 g_date_prepare_to_parse (str, &pt);
00669
00670 #ifdef G_ENABLE_DEBUG
00671 g_message ("Found %d ints, `%d' `%d' `%d' and written out month %d",
00672 pt.num_ints, pt.n[0], pt.n[1], pt.n[2], pt.month);
00673 #endif
00674
00675
00676 if (pt.num_ints == 4)
00677 {
00678 G_UNLOCK (g_date_global);
00679 return;
00680 }
00681
00682 if (pt.num_ints > 1)
00683 {
00684 int i = 0;
00685 int j = 0;
00686
00687 g_assert (pt.num_ints < 4);
00688
00689 while (i < pt.num_ints && j < 3)
00690 {
00691 switch (dmy_order[j])
00692 {
00693 case G_DATE_MONTH:
00694 {
00695 if (pt.num_ints == 2 && pt.month != G_DATE_BAD_MONTH)
00696 {
00697 m = pt.month;
00698 ++j;
00699 continue;
00700 }
00701 else
00702 m = pt.n[i];
00703 }
00704 break;
00705 case G_DATE_DAY:
00706 {
00707 if (pt.num_ints == 2 && pt.month == G_DATE_BAD_MONTH)
00708 {
00709 day = 1;
00710 ++j;
00711 continue;
00712 }
00713 day = pt.n[i];
00714 }
00715 break;
00716 case G_DATE_YEAR:
00717 {
00718 y = pt.n[i];
00719
00720 if (using_twodigit_years && y < 100)
00721 {
00722 guint two = twodigit_start_year % 100;
00723 guint century = (twodigit_start_year / 100) * 100;
00724
00725 if (y < two)
00726 century += 100;
00727
00728 y += century;
00729 }
00730 }
00731 break;
00732 default:
00733 break;
00734 }
00735
00736 ++i;
00737 ++j;
00738 }
00739
00740
00741 if (pt.num_ints == 3 && !g_date_valid_dmy (day, m, y))
00742 {
00743
00744 y = pt.n[0];
00745 m = pt.n[1];
00746 day = pt.n[2];
00747
00748 if (using_twodigit_years && y < 100)
00749 y = G_DATE_BAD_YEAR;
00750 }
00751 }
00752 else if (pt.num_ints == 1)
00753 {
00754 if (pt.month != G_DATE_BAD_MONTH)
00755 {
00756
00757 m = pt.month;
00758 day = 1;
00759 y = pt.n[0];
00760 }
00761 else
00762 {
00763
00764
00765 m = (pt.n[0]/100) % 100;
00766 day = pt.n[0] % 100;
00767 y = pt.n[0]/10000;
00768
00769
00770 if (using_twodigit_years && y < 100)
00771 {
00772 guint two = twodigit_start_year % 100;
00773 guint century = (twodigit_start_year / 100) * 100;
00774
00775 if (y < two)
00776 century += 100;
00777
00778 y += century;
00779 }
00780 }
00781 }
00782
00783
00784
00785 if (y < 8000 && g_date_valid_dmy (day, m, y))
00786 {
00787 d->month = m;
00788 d->day = day;
00789 d->year = y;
00790 d->dmy = TRUE;
00791 }
00792 #ifdef G_ENABLE_DEBUG
00793 else
00794 g_message ("Rejected DMY %u %u %u", day, m, y);
00795 #endif
00796 G_UNLOCK (g_date_global);
00797 }
00798
00799 void
00800 g_date_set_time (GDate *d,
00801 GTime time)
00802 {
00803 time_t t = time;
00804 struct tm tm;
00805
00806 g_return_if_fail (d != NULL);
00807
00808 #ifdef HAVE_LOCALTIME_R
00809 localtime_r (&t, &tm);
00810 #else
00811 {
00812 struct tm *ptm = localtime (&t);
00813 g_assert (ptm);
00814 memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm));
00815 }
00816 #endif
00817
00818 d->julian = FALSE;
00819
00820 d->month = tm.tm_mon + 1;
00821 d->day = tm.tm_mday;
00822 d->year = tm.tm_year + 1900;
00823
00824 g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year));
00825
00826 d->dmy = TRUE;
00827 }
00828
00829 void
00830 g_date_set_month (GDate *d,
00831 GDateMonth m)
00832 {
00833 g_return_if_fail (d != NULL);
00834 g_return_if_fail (g_date_valid_month (m));
00835
00836 if (d->julian && !d->dmy) g_date_update_dmy(d);
00837 d->julian = FALSE;
00838
00839 d->month = m;
00840
00841 if (g_date_valid_dmy (d->day, d->month, d->year))
00842 d->dmy = TRUE;
00843 else
00844 d->dmy = FALSE;
00845 }
00846
00847 void
00848 g_date_set_day (GDate *d,
00849 GDateDay day)
00850 {
00851 g_return_if_fail (d != NULL);
00852 g_return_if_fail (g_date_valid_day (day));
00853
00854 if (d->julian && !d->dmy) g_date_update_dmy(d);
00855 d->julian = FALSE;
00856
00857 d->day = day;
00858
00859 if (g_date_valid_dmy (d->day, d->month, d->year))
00860 d->dmy = TRUE;
00861 else
00862 d->dmy = FALSE;
00863 }
00864
00865 void
00866 g_date_set_year (GDate *d,
00867 GDateYear y)
00868 {
00869 g_return_if_fail (d != NULL);
00870 g_return_if_fail (g_date_valid_year (y));
00871
00872 if (d->julian && !d->dmy) g_date_update_dmy(d);
00873 d->julian = FALSE;
00874
00875 d->year = y;
00876
00877 if (g_date_valid_dmy (d->day, d->month, d->year))
00878 d->dmy = TRUE;
00879 else
00880 d->dmy = FALSE;
00881 }
00882
00883 void
00884 g_date_set_dmy (GDate *d,
00885 GDateDay day,
00886 GDateMonth m,
00887 GDateYear y)
00888 {
00889 g_return_if_fail (d != NULL);
00890 g_return_if_fail (g_date_valid_dmy (day, m, y));
00891
00892 d->julian = FALSE;
00893
00894 d->month = m;
00895 d->day = day;
00896 d->year = y;
00897
00898 d->dmy = TRUE;
00899 }
00900
00901 void
00902 g_date_set_julian (GDate *d, guint32 j)
00903 {
00904 g_return_if_fail (d != NULL);
00905 g_return_if_fail (g_date_valid_julian (j));
00906
00907 d->julian_days = j;
00908 d->julian = TRUE;
00909 d->dmy = FALSE;
00910 }
00911
00912
00913 gboolean
00914 g_date_is_first_of_month (GDate *d)
00915 {
00916 g_return_val_if_fail (d != NULL, FALSE);
00917 g_return_val_if_fail (g_date_valid (d), FALSE);
00918
00919 if (!d->dmy)
00920 {
00921 g_date_update_dmy (d);
00922 }
00923 g_return_val_if_fail (d->dmy, FALSE);
00924
00925 if (d->day == 1) return TRUE;
00926 else return FALSE;
00927 }
00928
00929 gboolean
00930 g_date_is_last_of_month (GDate *d)
00931 {
00932 gint index;
00933
00934 g_return_val_if_fail (d != NULL, FALSE);
00935 g_return_val_if_fail (g_date_valid (d), FALSE);
00936
00937 if (!d->dmy)
00938 {
00939 g_date_update_dmy (d);
00940 }
00941 g_return_val_if_fail (d->dmy, FALSE);
00942
00943 index = g_date_is_leap_year (d->year) ? 1 : 0;
00944
00945 if (d->day == days_in_months[index][d->month]) return TRUE;
00946 else return FALSE;
00947 }
00948
00949 void
00950 g_date_add_days (GDate *d, guint ndays)
00951 {
00952 g_return_if_fail (d != NULL);
00953 g_return_if_fail (g_date_valid (d));
00954
00955 if (!d->julian)
00956 {
00957 g_date_update_julian (d);
00958 }
00959 g_return_if_fail (d->julian);
00960
00961 d->julian_days += ndays;
00962 d->dmy = FALSE;
00963 }
00964
00965 void
00966 g_date_subtract_days (GDate *d, guint ndays)
00967 {
00968 g_return_if_fail (d != NULL);
00969 g_return_if_fail (g_date_valid (d));
00970
00971 if (!d->julian)
00972 {
00973 g_date_update_julian (d);
00974 }
00975 g_return_if_fail (d->julian);
00976 g_return_if_fail (d->julian_days > ndays);
00977
00978 d->julian_days -= ndays;
00979 d->dmy = FALSE;
00980 }
00981
00982 void
00983 g_date_add_months (GDate *d,
00984 guint nmonths)
00985 {
00986 guint years, months;
00987 gint index;
00988
00989 g_return_if_fail (d != NULL);
00990 g_return_if_fail (g_date_valid (d));
00991
00992 if (!d->dmy)
00993 {
00994 g_date_update_dmy (d);
00995 }
00996 g_return_if_fail (d->dmy);
00997
00998 nmonths += d->month - 1;
00999
01000 years = nmonths/12;
01001 months = nmonths%12;
01002
01003 d->month = months + 1;
01004 d->year += years;
01005
01006 index = g_date_is_leap_year (d->year) ? 1 : 0;
01007
01008 if (d->day > days_in_months[index][d->month])
01009 d->day = days_in_months[index][d->month];
01010
01011 d->julian = FALSE;
01012
01013 g_return_if_fail (g_date_valid (d));
01014 }
01015
01016 void
01017 g_date_subtract_months (GDate *d,
01018 guint nmonths)
01019 {
01020 guint years, months;
01021 gint index;
01022
01023 g_return_if_fail (d != NULL);
01024 g_return_if_fail (g_date_valid (d));
01025
01026 if (!d->dmy)
01027 {
01028 g_date_update_dmy (d);
01029 }
01030 g_return_if_fail (d->dmy);
01031
01032 years = nmonths/12;
01033 months = nmonths%12;
01034
01035 g_return_if_fail (d->year > years);
01036
01037 d->year -= years;
01038
01039 if (d->month > months) d->month -= months;
01040 else
01041 {
01042 months -= d->month;
01043 d->month = 12 - months;
01044 d->year -= 1;
01045 }
01046
01047 index = g_date_is_leap_year (d->year) ? 1 : 0;
01048
01049 if (d->day > days_in_months[index][d->month])
01050 d->day = days_in_months[index][d->month];
01051
01052 d->julian = FALSE;
01053
01054 g_return_if_fail (g_date_valid (d));
01055 }
01056
01057 void
01058 g_date_add_years (GDate *d,
01059 guint nyears)
01060 {
01061 g_return_if_fail (d != NULL);
01062 g_return_if_fail (g_date_valid (d));
01063
01064 if (!d->dmy)
01065 {
01066 g_date_update_dmy (d);
01067 }
01068 g_return_if_fail (d->dmy);
01069
01070 d->year += nyears;
01071
01072 if (d->month == 2 && d->day == 29)
01073 {
01074 if (!g_date_is_leap_year (d->year))
01075 {
01076 d->day = 28;
01077 }
01078 }
01079
01080 d->julian = FALSE;
01081 }
01082
01083 void
01084 g_date_subtract_years (GDate *d,
01085 guint nyears)
01086 {
01087 g_return_if_fail (d != NULL);
01088 g_return_if_fail (g_date_valid (d));
01089
01090 if (!d->dmy)
01091 {
01092 g_date_update_dmy (d);
01093 }
01094 g_return_if_fail (d->dmy);
01095 g_return_if_fail (d->year > nyears);
01096
01097 d->year -= nyears;
01098
01099 if (d->month == 2 && d->day == 29)
01100 {
01101 if (!g_date_is_leap_year (d->year))
01102 {
01103 d->day = 28;
01104 }
01105 }
01106
01107 d->julian = FALSE;
01108 }
01109
01110
01111 gboolean
01112 g_date_is_leap_year (GDateYear year)
01113 {
01114 g_return_val_if_fail (g_date_valid_year (year), FALSE);
01115
01116 return ( (((year % 4) == 0) && ((year % 100) != 0)) ||
01117 (year % 400) == 0 );
01118 }
01119
01120 guint8
01121 g_date_days_in_month (GDateMonth month,
01122 GDateYear year)
01123 {
01124 gint index;
01125
01126 g_return_val_if_fail (g_date_valid_year (year), 0);
01127 g_return_val_if_fail (g_date_valid_month (month), 0);
01128
01129 index = g_date_is_leap_year (year) ? 1 : 0;
01130
01131 return days_in_months[index][month];
01132 }
01133
01134 guint8
01135 g_date_monday_weeks_in_year (GDateYear year)
01136 {
01137 GDate d;
01138
01139 g_return_val_if_fail (g_date_valid_year (year), 0);
01140
01141 g_date_clear (&d, 1);
01142 g_date_set_dmy (&d, 1, 1, year);
01143 if (g_date_weekday (&d) == G_DATE_MONDAY) return 53;
01144 g_date_set_dmy (&d, 31, 12, year);
01145 if (g_date_weekday (&d) == G_DATE_MONDAY) return 53;
01146 if (g_date_is_leap_year (year))
01147 {
01148 g_date_set_dmy (&d, 2, 1, year);
01149 if (g_date_weekday (&d) == G_DATE_MONDAY) return 53;
01150 g_date_set_dmy (&d, 30, 12, year);
01151 if (g_date_weekday (&d) == G_DATE_MONDAY) return 53;
01152 }
01153 return 52;
01154 }
01155
01156 guint8
01157 g_date_sunday_weeks_in_year (GDateYear year)
01158 {
01159 GDate d;
01160
01161 g_return_val_if_fail (g_date_valid_year (year), 0);
01162
01163 g_date_clear (&d, 1);
01164 g_date_set_dmy (&d, 1, 1, year);
01165 if (g_date_weekday (&d) == G_DATE_SUNDAY) return 53;
01166 g_date_set_dmy (&d, 31, 12, year);
01167 if (g_date_weekday (&d) == G_DATE_SUNDAY) return 53;
01168 if (g_date_is_leap_year (year))
01169 {
01170 g_date_set_dmy (&d, 2, 1, year);
01171 if (g_date_weekday (&d) == G_DATE_SUNDAY) return 53;
01172 g_date_set_dmy (&d, 30, 12, year);
01173 if (g_date_weekday (&d) == G_DATE_SUNDAY) return 53;
01174 }
01175 return 52;
01176 }
01177
01178 gint
01179 g_date_compare (GDate *lhs,
01180 GDate *rhs)
01181 {
01182 g_return_val_if_fail (lhs != NULL, 0);
01183 g_return_val_if_fail (rhs != NULL, 0);
01184 g_return_val_if_fail (g_date_valid (lhs), 0);
01185 g_return_val_if_fail (g_date_valid (rhs), 0);
01186
01187
01188
01189 while (TRUE)
01190 {
01191
01192 if (lhs->julian && rhs->julian)
01193 {
01194 if (lhs->julian_days < rhs->julian_days) return -1;
01195 else if (lhs->julian_days > rhs->julian_days) return 1;
01196 else return 0;
01197 }
01198 else if (lhs->dmy && rhs->dmy)
01199 {
01200 if (lhs->year < rhs->year) return -1;
01201 else if (lhs->year > rhs->year) return 1;
01202 else
01203 {
01204 if (lhs->month < rhs->month) return -1;
01205 else if (lhs->month > rhs->month) return 1;
01206 else
01207 {
01208 if (lhs->day < rhs->day) return -1;
01209 else if (lhs->day > rhs->day) return 1;
01210 else return 0;
01211 }
01212
01213 }
01214
01215 }
01216 else
01217 {
01218 if (!lhs->julian) g_date_update_julian (lhs);
01219 if (!rhs->julian) g_date_update_julian (rhs);
01220 g_return_val_if_fail (lhs->julian, 0);
01221 g_return_val_if_fail (rhs->julian, 0);
01222 }
01223
01224 }
01225 return 0;
01226 }
01227
01228
01229 void
01230 g_date_to_struct_tm (GDate *d,
01231 struct tm *tm)
01232 {
01233 GDateWeekday day;
01234
01235 g_return_if_fail (d != NULL);
01236 g_return_if_fail (g_date_valid (d));
01237 g_return_if_fail (tm != NULL);
01238
01239 if (!d->dmy)
01240 {
01241 g_date_update_dmy (d);
01242 }
01243 g_return_if_fail (d->dmy);
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253 memset (tm, 0x0, sizeof (struct tm));
01254
01255 tm->tm_mday = d->day;
01256 tm->tm_mon = d->month - 1;
01257 tm->tm_year = ((int)d->year) - 1900;
01258
01259 day = g_date_weekday (d);
01260 if (day == 7) day = 0;
01261
01262 tm->tm_wday = (int)day;
01263
01264 tm->tm_yday = g_date_day_of_year (d) - 1;
01265 tm->tm_isdst = -1;
01266 }
01267
01268 gsize
01269 g_date_strftime (gchar *s,
01270 gsize slen,
01271 const gchar *format,
01272 GDate *d)
01273 {
01274 struct tm tm;
01275 gsize retval;
01276
01277 g_return_val_if_fail (d != NULL, 0);
01278 g_return_val_if_fail (g_date_valid (d), 0);
01279 g_return_val_if_fail (slen > 0, 0);
01280 g_return_val_if_fail (format != 0, 0);
01281 g_return_val_if_fail (s != 0, 0);
01282
01283 g_date_to_struct_tm (d, &tm);
01284
01285 retval = strftime (s, slen, format, &tm);
01286 if (retval == 0)
01287 {
01288
01289
01290
01291 s[0] = '\0';
01292 }
01293 return retval;
01294 }