glib/libglib/src/gdate.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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