"Fossies" - the Fresh Open Source Software Archive

Member "pkg-config-0.29.2/glib/glib/gdate.c" (20 Mar 2017, 67044 Bytes) of package /linux/misc/pkg-config-0.29.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gdate.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.29.1_vs_0.29.2.

    1 /* GLIB - Library of useful routines for C programming
    2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
    3  *
    4  * This library is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU Lesser General Public
    6  * License as published by the Free Software Foundation; either
    7  * version 2 of the License, or (at your option) any later version.
    8  *
    9  * This library is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12  * Lesser General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU Lesser General Public
   15  * License along with this library; if not, write to the
   16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   17  * Boston, MA 02111-1307, USA.
   18  */
   19 
   20 /*
   21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
   22  * file for a list of people on the GLib Team.  See the ChangeLog
   23  * files for a list of changes.  These files are distributed with
   24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
   25  */
   26 
   27 /* 
   28  * MT safe
   29  */
   30 
   31 #include "config.h"
   32 #include "glibconfig.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 <time.h>
   40 #include <string.h>
   41 #include <stdlib.h>
   42 #include <locale.h>
   43 
   44 #ifdef G_OS_WIN32
   45 #include <windows.h>
   46 #endif
   47 
   48 #include "gdate.h"
   49 
   50 #include "gconvert.h"
   51 #include "gmem.h"
   52 #include "gstrfuncs.h"
   53 #include "gtestutils.h"
   54 #include "gthread.h"
   55 #include "gunicode.h"
   56 
   57 #ifdef G_OS_WIN32
   58 #include "garray.h"
   59 #endif
   60 
   61 /**
   62  * SECTION:date
   63  * @title: Date and Time Functions
   64  * @short_description: calendrical calculations and miscellaneous time stuff
   65  *
   66  * The #GDate data structure represents a day between January 1, Year 1,
   67  * and sometime a few thousand years in the future (right now it will go
   68  * to the year 65535 or so, but g_date_set_parse() only parses up to the
   69  * year 8000 or so - just count on "a few thousand"). #GDate is meant to
   70  * represent everyday dates, not astronomical dates or historical dates
   71  * or ISO timestamps or the like. It extrapolates the current Gregorian
   72  * calendar forward and backward in time; there is no attempt to change
   73  * the calendar to match time periods or locations. #GDate does not store
   74  * time information; it represents a <emphasis>day</emphasis>.
   75  *
   76  * The #GDate implementation has several nice features; it is only a
   77  * 64-bit struct, so storing large numbers of dates is very efficient. It
   78  * can keep both a Julian and day-month-year representation of the date,
   79  * since some calculations are much easier with one representation or the
   80  * other. A Julian representation is simply a count of days since some
   81  * fixed day in the past; for #GDate the fixed day is January 1, 1 AD.
   82  * ("Julian" dates in the #GDate API aren't really Julian dates in the
   83  * technical sense; technically, Julian dates count from the start of the
   84  * Julian period, Jan 1, 4713 BC).
   85  *
   86  * #GDate is simple to use. First you need a "blank" date; you can get a
   87  * dynamically allocated date from g_date_new(), or you can declare an
   88  * automatic variable or array and initialize it to a sane state by
   89  * calling g_date_clear(). A cleared date is sane; it's safe to call
   90  * g_date_set_dmy() and the other mutator functions to initialize the
   91  * value of a cleared date. However, a cleared date is initially
   92  * <emphasis>invalid</emphasis>, meaning that it doesn't represent a day
   93  * that exists. It is undefined to call any of the date calculation
   94  * routines on an invalid date. If you obtain a date from a user or other
   95  * unpredictable source, you should check its validity with the
   96  * g_date_valid() predicate. g_date_valid() is also used to check for
   97  * errors with g_date_set_parse() and other functions that can
   98  * fail. Dates can be invalidated by calling g_date_clear() again.
   99  *
  100  * <emphasis>It is very important to use the API to access the #GDate
  101  * struct.</emphasis> Often only the day-month-year or only the Julian
  102  * representation is valid. Sometimes neither is valid. Use the API.
  103  *
  104  * GLib also features #GDateTime which represents a precise time.
  105  */
  106 
  107 /**
  108  * G_USEC_PER_SEC:
  109  *
  110  * Number of microseconds in one second (1 million).
  111  * This macro is provided for code readability.
  112  */
  113 
  114 /**
  115  * GTimeVal:
  116  * @tv_sec: seconds
  117  * @tv_usec: microseconds
  118  *
  119  * Represents a precise time, with seconds and microseconds.
  120  * Similar to the <structname>struct timeval</structname> returned by
  121  * the gettimeofday() UNIX system call.
  122  *
  123  * GLib is attempting to unify around the use of 64bit integers to
  124  * represent microsecond-precision time. As such, this type will be
  125  * removed from a future version of GLib.
  126  */
  127 
  128 /**
  129  * GDate:
  130  * @julian_days: the Julian representation of the date
  131  * @julian: this bit is set if @julian_days is valid
  132  * @dmy: this is set if @day, @month and @year are valid
  133  * @day: the day of the day-month-year representation of the date,
  134  *     as a number between 1 and 31
  135  * @month: the day of the day-month-year representation of the date,
  136  *     as a number between 1 and 12
  137  * @year: the day of the day-month-year representation of the date
  138  *
  139  * Represents a day between January 1, Year 1 and a few thousand years in
  140  * the future. None of its members should be accessed directly. If the
  141  * <structname>GDate</structname> is obtained from g_date_new(), it will
  142  * be safe to mutate but invalid and thus not safe for calendrical
  143  * computations. If it's declared on the stack, it will contain garbage
  144  * so must be initialized with g_date_clear(). g_date_clear() makes the
  145  * date invalid but sane. An invalid date doesn't represent a day, it's
  146  * "empty." A date becomes valid after you set it to a Julian day or you
  147  * set a day, month, and year.
  148  */
  149 
  150 /**
  151  * GTime:
  152  *
  153  * Simply a replacement for <type>time_t</type>. It has been deprecated
  154  * since it is <emphasis>not</emphasis> equivalent to <type>time_t</type>
  155  * on 64-bit platforms with a 64-bit <type>time_t</type>.
  156  * Unrelated to #GTimer.
  157  *
  158  * Note that <type>GTime</type> is defined to always be a 32bit integer,
  159  * unlike <type>time_t</type> which may be 64bit on some systems.
  160  * Therefore, <type>GTime</type> will overflow in the year 2038, and
  161  * you cannot use the address of a <type>GTime</type> variable as argument
  162  * to the UNIX time() function. Instead, do the following:
  163  * |[
  164  * time_t ttime;
  165  * GTime gtime;
  166  *
  167  * time (&amp;ttime);
  168  * gtime = (GTime)ttime;
  169  * ]|
  170  */
  171 
  172 /**
  173  * GDateDMY:
  174  * @G_DATE_DAY: a day
  175  * @G_DATE_MONTH: a month
  176  * @G_DATE_YEAR: a year
  177  *
  178  * This enumeration isn't used in the API, but may be useful if you need
  179  * to mark a number as a day, month, or year.
  180  */
  181 
  182 /**
  183  * GDateDay:
  184  *
  185  * Integer representing a day of the month; between 1 and
  186  * 31. #G_DATE_BAD_DAY represents an invalid day of the month.
  187  */
  188 
  189 /**
  190  * GDateMonth:
  191  * @G_DATE_BAD_MONTH: invalid value
  192  * @G_DATE_JANUARY: January
  193  * @G_DATE_FEBRUARY: February
  194  * @G_DATE_MARCH: March
  195  * @G_DATE_APRIL: April
  196  * @G_DATE_MAY: May
  197  * @G_DATE_JUNE: June
  198  * @G_DATE_JULY: July
  199  * @G_DATE_AUGUST: August
  200  * @G_DATE_SEPTEMBER: September
  201  * @G_DATE_OCTOBER: October
  202  * @G_DATE_NOVEMBER: November
  203  * @G_DATE_DECEMBER: December
  204  *
  205  * Enumeration representing a month; values are #G_DATE_JANUARY,
  206  * #G_DATE_FEBRUARY, etc. #G_DATE_BAD_MONTH is the invalid value.
  207  */
  208 
  209 /**
  210  * GDateYear:
  211  *
  212  * Integer representing a year; #G_DATE_BAD_YEAR is the invalid
  213  * value. The year must be 1 or higher; negative (BC) years are not
  214  * allowed. The year is represented with four digits.
  215  */
  216 
  217 /**
  218  * GDateWeekday:
  219  * @G_DATE_BAD_WEEKDAY: invalid value
  220  * @G_DATE_MONDAY: Monday
  221  * @G_DATE_TUESDAY: Tuesday
  222  * @G_DATE_WEDNESDAY: Wednesday
  223  * @G_DATE_THURSDAY: Thursday
  224  * @G_DATE_FRIDAY: Friday
  225  * @G_DATE_SATURDAY: Saturday
  226  * @G_DATE_SUNDAY: Sunday
  227  *
  228  * Enumeration representing a day of the week; #G_DATE_MONDAY,
  229  * #G_DATE_TUESDAY, etc. #G_DATE_BAD_WEEKDAY is an invalid weekday.
  230  */
  231 
  232 /**
  233  * G_DATE_BAD_DAY:
  234  *
  235  * Represents an invalid #GDateDay.
  236  */
  237 
  238 /**
  239  * G_DATE_BAD_JULIAN:
  240  *
  241  * Represents an invalid Julian day number.
  242  */
  243 
  244 /**
  245  * G_DATE_BAD_YEAR:
  246  *
  247  * Represents an invalid year.
  248  */
  249 
  250 /**
  251  * g_date_new:
  252  *
  253  * Allocates a #GDate and initializes
  254  * it to a sane state. The new date will
  255  * be cleared (as if you'd called g_date_clear()) but invalid (it won't
  256  * represent an existing day). Free the return value with g_date_free().
  257  *
  258  * Returns: a newly-allocated #GDate
  259  */
  260 GDate*
  261 g_date_new (void)
  262 {
  263   GDate *d = g_new0 (GDate, 1); /* happily, 0 is the invalid flag for everything. */
  264   
  265   return d;
  266 }
  267 
  268 /**
  269  * g_date_new_dmy:
  270  * @day: day of the month
  271  * @month: month of the year
  272  * @year: year
  273  *
  274  * Like g_date_new(), but also sets the value of the date. Assuming the
  275  * day-month-year triplet you pass in represents an existing day, the
  276  * returned date will be valid.
  277  *
  278  * Returns: a newly-allocated #GDate initialized with @day, @month, and @year
  279  */
  280 GDate*
  281 g_date_new_dmy (GDateDay   day, 
  282                 GDateMonth m, 
  283                 GDateYear  y)
  284 {
  285   GDate *d;
  286   g_return_val_if_fail (g_date_valid_dmy (day, m, y), NULL);
  287   
  288   d = g_new (GDate, 1);
  289   
  290   d->julian = FALSE;
  291   d->dmy    = TRUE;
  292   
  293   d->month = m;
  294   d->day   = day;
  295   d->year  = y;
  296   
  297   g_assert (g_date_valid (d));
  298   
  299   return d;
  300 }
  301 
  302 /**
  303  * g_date_new_julian:
  304  * @julian_day: days since January 1, Year 1
  305  *
  306  * Like g_date_new(), but also sets the value of the date. Assuming the
  307  * Julian day number you pass in is valid (greater than 0, less than an
  308  * unreasonably large number), the returned date will be valid.
  309  *
  310  * Returns: a newly-allocated #GDate initialized with @julian_day
  311  */
  312 GDate*
  313 g_date_new_julian (guint32 julian_day)
  314 {
  315   GDate *d;
  316   g_return_val_if_fail (g_date_valid_julian (julian_day), NULL);
  317   
  318   d = g_new (GDate, 1);
  319   
  320   d->julian = TRUE;
  321   d->dmy    = FALSE;
  322   
  323   d->julian_days = julian_day;
  324   
  325   g_assert (g_date_valid (d));
  326   
  327   return d;
  328 }
  329 
  330 /**
  331  * g_date_free:
  332  * @date: a #GDate to free
  333  *
  334  * Frees a #GDate returned from g_date_new().
  335  */
  336 void
  337 g_date_free (GDate *date)
  338 {
  339   g_return_if_fail (date != NULL);
  340   
  341   g_free (date);
  342 }
  343 
  344 /**
  345  * g_date_valid:
  346  * @date: a #GDate to check
  347  *
  348  * Returns %TRUE if the #GDate represents an existing day. The date must not
  349  * contain garbage; it should have been initialized with g_date_clear()
  350  * if it wasn't allocated by one of the g_date_new() variants.
  351  *
  352  * Returns: Whether the date is valid
  353  */
  354 gboolean     
  355 g_date_valid (const GDate *d)
  356 {
  357   g_return_val_if_fail (d != NULL, FALSE);
  358   
  359   return (d->julian || d->dmy);
  360 }
  361 
  362 static const guint8 days_in_months[2][13] = 
  363 {  /* error, jan feb mar apr may jun jul aug sep oct nov dec */
  364   {  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 
  365   {  0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* leap year */
  366 };
  367 
  368 static const guint16 days_in_year[2][14] = 
  369 {  /* 0, jan feb mar apr may  jun  jul  aug  sep  oct  nov  dec */
  370   {  0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 
  371   {  0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
  372 };
  373 
  374 /**
  375  * g_date_valid_month:
  376  * @month: month
  377  *
  378  * Returns %TRUE if the month value is valid. The 12 #GDateMonth
  379  * enumeration values are the only valid months.
  380  *
  381  * Returns: %TRUE if the month is valid
  382  */
  383 gboolean     
  384 g_date_valid_month (GDateMonth m)
  385 { 
  386   return ( (m > G_DATE_BAD_MONTH) && (m < 13) );
  387 }
  388 
  389 /**
  390  * g_date_valid_year:
  391  * @year: year
  392  *
  393  * Returns %TRUE if the year is valid. Any year greater than 0 is valid,
  394  * though there is a 16-bit limit to what #GDate will understand.
  395  *
  396  * Returns: %TRUE if the year is valid
  397  */
  398 gboolean     
  399 g_date_valid_year (GDateYear y)
  400 {
  401   return ( y > G_DATE_BAD_YEAR );
  402 }
  403 
  404 /**
  405  * g_date_valid_day:
  406  * @day: day to check
  407  *
  408  * Returns %TRUE if the day of the month is valid (a day is valid if it's
  409  * between 1 and 31 inclusive).
  410  *
  411  * Returns: %TRUE if the day is valid
  412  */
  413 
  414 gboolean     
  415 g_date_valid_day (GDateDay d)
  416 {
  417   return ( (d > G_DATE_BAD_DAY) && (d < 32) );
  418 }
  419 
  420 /**
  421  * g_date_valid_weekday:
  422  * @weekday: weekday
  423  *
  424  * Returns %TRUE if the weekday is valid. The seven #GDateWeekday enumeration
  425  * values are the only valid weekdays.
  426  *
  427  * Returns: %TRUE if the weekday is valid
  428  */
  429 gboolean     
  430 g_date_valid_weekday (GDateWeekday w)
  431 {
  432   return ( (w > G_DATE_BAD_WEEKDAY) && (w < 8) );
  433 }
  434 
  435 /**
  436  * g_date_valid_julian:
  437  * @julian_date: Julian day to check
  438  *
  439  * Returns %TRUE if the Julian day is valid. Anything greater than zero
  440  * is basically a valid Julian, though there is a 32-bit limit.
  441  *
  442  * Returns: %TRUE if the Julian day is valid
  443  */
  444 gboolean     
  445 g_date_valid_julian (guint32 j)
  446 {
  447   return (j > G_DATE_BAD_JULIAN);
  448 }
  449 
  450 /**
  451  * g_date_valid_dmy:
  452  * @day: day
  453  * @month: month
  454  * @year: year
  455  *
  456  * Returns %TRUE if the day-month-year triplet forms a valid, existing day
  457  * in the range of days #GDate understands (Year 1 or later, no more than
  458  * a few thousand years in the future).
  459  *
  460  * Returns: %TRUE if the date is a valid one
  461  */
  462 gboolean     
  463 g_date_valid_dmy (GDateDay   d, 
  464                   GDateMonth m, 
  465           GDateYear  y)
  466 {
  467   return ( (m > G_DATE_BAD_MONTH) &&
  468            (m < 13)               && 
  469            (d > G_DATE_BAD_DAY)   && 
  470            (y > G_DATE_BAD_YEAR)  &&   /* must check before using g_date_is_leap_year */
  471            (d <=  (g_date_is_leap_year (y) ? 
  472            days_in_months[1][m] : days_in_months[0][m])) );
  473 }
  474 
  475 
  476 /* "Julian days" just means an absolute number of days, where Day 1 ==
  477  *   Jan 1, Year 1
  478  */
  479 static void
  480 g_date_update_julian (const GDate *const_d)
  481 {
  482   GDate *d = (GDate *) const_d;
  483   GDateYear year;
  484   gint idx;
  485   
  486   g_return_if_fail (d != NULL);
  487   g_return_if_fail (d->dmy);
  488   g_return_if_fail (!d->julian);
  489   g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year));
  490   
  491   /* What we actually do is: multiply years * 365 days in the year,
  492    * add the number of years divided by 4, subtract the number of
  493    * years divided by 100 and add the number of years divided by 400,
  494    * which accounts for leap year stuff. Code from Steffen Beyer's
  495    * DateCalc. 
  496    */
  497   
  498   year = d->year - 1; /* we know d->year > 0 since it's valid */
  499   
  500   d->julian_days = year * 365U;
  501   d->julian_days += (year >>= 2); /* divide by 4 and add */
  502   d->julian_days -= (year /= 25); /* divides original # years by 100 */
  503   d->julian_days += year >> 2;    /* divides by 4, which divides original by 400 */
  504   
  505   idx = g_date_is_leap_year (d->year) ? 1 : 0;
  506   
  507   d->julian_days += days_in_year[idx][d->month] + d->day;
  508   
  509   g_return_if_fail (g_date_valid_julian (d->julian_days));
  510   
  511   d->julian = TRUE;
  512 }
  513 
  514 static void 
  515 g_date_update_dmy (const GDate *const_d)
  516 {
  517   GDate *d = (GDate *) const_d;
  518   GDateYear y;
  519   GDateMonth m;
  520   GDateDay day;
  521   
  522   guint32 A, B, C, D, E, M;
  523   
  524   g_return_if_fail (d != NULL);
  525   g_return_if_fail (d->julian);
  526   g_return_if_fail (!d->dmy);
  527   g_return_if_fail (g_date_valid_julian (d->julian_days));
  528   
  529   /* Formula taken from the Calendar FAQ; the formula was for the
  530    *  Julian Period which starts on 1 January 4713 BC, so we add
  531    *  1,721,425 to the number of days before doing the formula.
  532    *
  533    * I'm sure this can be simplified for our 1 January 1 AD period
  534    * start, but I can't figure out how to unpack the formula.  
  535    */
  536   
  537   A = d->julian_days + 1721425 + 32045;
  538   B = ( 4 *(A + 36524) )/ 146097 - 1;
  539   C = A - (146097 * B)/4;
  540   D = ( 4 * (C + 365) ) / 1461 - 1;
  541   E = C - ((1461*D) / 4);
  542   M = (5 * (E - 1) + 2)/153;
  543   
  544   m = M + 3 - (12*(M/10));
  545   day = E - (153*M + 2)/5;
  546   y = 100 * B + D - 4800 + (M/10);
  547   
  548 #ifdef G_ENABLE_DEBUG
  549   if (!g_date_valid_dmy (day, m, y)) 
  550     g_warning ("\nOOPS julian: %u  computed dmy: %u %u %u\n", 
  551            d->julian_days, day, m, y);
  552 #endif
  553   
  554   d->month = m;
  555   d->day   = day;
  556   d->year  = y;
  557   
  558   d->dmy = TRUE;
  559 }
  560 
  561 /**
  562  * g_date_get_weekday:
  563  * @date: a #GDate
  564  *
  565  * Returns the day of the week for a #GDate. The date must be valid.
  566  *
  567  * Returns: day of the week as a #GDateWeekday.
  568  */
  569 GDateWeekday 
  570 g_date_get_weekday (const GDate *d)
  571 {
  572   g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_WEEKDAY);
  573   
  574   if (!d->julian) 
  575     g_date_update_julian (d);
  576 
  577   g_return_val_if_fail (d->julian, G_DATE_BAD_WEEKDAY);
  578   
  579   return ((d->julian_days - 1) % 7) + 1;
  580 }
  581 
  582 /**
  583  * g_date_get_month:
  584  * @date: a #GDate to get the month from
  585  *
  586  * Returns the month of the year. The date must be valid.
  587  *
  588  * Returns: month of the year as a #GDateMonth
  589  */
  590 GDateMonth   
  591 g_date_get_month (const GDate *d)
  592 {
  593   g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_MONTH);
  594   
  595   if (!d->dmy) 
  596     g_date_update_dmy (d);
  597 
  598   g_return_val_if_fail (d->dmy, G_DATE_BAD_MONTH);
  599   
  600   return d->month;
  601 }
  602 
  603 /**
  604  * g_date_get_year:
  605  * @date: a #GDate
  606  *
  607  * Returns the year of a #GDate. The date must be valid.
  608  *
  609  * Returns: year in which the date falls
  610  */
  611 GDateYear    
  612 g_date_get_year (const GDate *d)
  613 {
  614   g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_YEAR);
  615   
  616   if (!d->dmy) 
  617     g_date_update_dmy (d);
  618 
  619   g_return_val_if_fail (d->dmy, G_DATE_BAD_YEAR);  
  620   
  621   return d->year;
  622 }
  623 
  624 /**
  625  * g_date_get_day:
  626  * @date: a #GDate to extract the day of the month from
  627  *
  628  * Returns the day of the month. The date must be valid.
  629  *
  630  * Returns: day of the month
  631  */
  632 GDateDay     
  633 g_date_get_day (const GDate *d)
  634 {
  635   g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_DAY);
  636   
  637   if (!d->dmy) 
  638     g_date_update_dmy (d);
  639 
  640   g_return_val_if_fail (d->dmy, G_DATE_BAD_DAY);  
  641   
  642   return d->day;
  643 }
  644 
  645 /**
  646  * g_date_get_julian:
  647  * @date: a #GDate to extract the Julian day from
  648  *
  649  * Returns the Julian day or "serial number" of the #GDate. The
  650  * Julian day is simply the number of days since January 1, Year 1; i.e.,
  651  * January 1, Year 1 is Julian day 1; January 2, Year 1 is Julian day 2,
  652  * etc. The date must be valid.
  653  *
  654  * Returns: Julian day
  655  */
  656 guint32      
  657 g_date_get_julian (const GDate *d)
  658 {
  659   g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_JULIAN);
  660   
  661   if (!d->julian) 
  662     g_date_update_julian (d);
  663 
  664   g_return_val_if_fail (d->julian, G_DATE_BAD_JULIAN);  
  665   
  666   return d->julian_days;
  667 }
  668 
  669 /**
  670  * g_date_get_day_of_year:
  671  * @date: a #GDate to extract day of year from
  672  *
  673  * Returns the day of the year, where Jan 1 is the first day of the
  674  * year. The date must be valid.
  675  *
  676  * Returns: day of the year
  677  */
  678 guint        
  679 g_date_get_day_of_year (const GDate *d)
  680 {
  681   gint idx;
  682   
  683   g_return_val_if_fail (g_date_valid (d), 0);
  684   
  685   if (!d->dmy) 
  686     g_date_update_dmy (d);
  687 
  688   g_return_val_if_fail (d->dmy, 0);  
  689   
  690   idx = g_date_is_leap_year (d->year) ? 1 : 0;
  691   
  692   return (days_in_year[idx][d->month] + d->day);
  693 }
  694 
  695 /**
  696  * g_date_get_monday_week_of_year:
  697  * @date: a #GDate
  698  *
  699  * Returns the week of the year, where weeks are understood to start on
  700  * Monday. If the date is before the first Monday of the year, return
  701  * 0. The date must be valid.
  702  *
  703  * Returns: week of the year
  704  */
  705 guint        
  706 g_date_get_monday_week_of_year (const GDate *d)
  707 {
  708   GDateWeekday wd;
  709   guint day;
  710   GDate first;
  711   
  712   g_return_val_if_fail (g_date_valid (d), 0);
  713   
  714   if (!d->dmy) 
  715     g_date_update_dmy (d);
  716 
  717   g_return_val_if_fail (d->dmy, 0);  
  718   
  719   g_date_clear (&first, 1);
  720   
  721   g_date_set_dmy (&first, 1, 1, d->year);
  722   
  723   wd = g_date_get_weekday (&first) - 1; /* make Monday day 0 */
  724   day = g_date_get_day_of_year (d) - 1;
  725   
  726   return ((day + wd)/7U + (wd == 0 ? 1 : 0));
  727 }
  728 
  729 /**
  730  * g_date_get_sunday_week_of_year:
  731  * @date: a #GDate
  732  *
  733  * Returns the week of the year during which this date falls, if weeks
  734  * are understood to being on Sunday. The date must be valid. Can return
  735  * 0 if the day is before the first Sunday of the year.
  736  *
  737  * Returns: week number
  738  */
  739 guint        
  740 g_date_get_sunday_week_of_year (const GDate *d)
  741 {
  742   GDateWeekday wd;
  743   guint day;
  744   GDate first;
  745   
  746   g_return_val_if_fail (g_date_valid (d), 0);
  747   
  748   if (!d->dmy) 
  749     g_date_update_dmy (d);
  750 
  751   g_return_val_if_fail (d->dmy, 0);  
  752   
  753   g_date_clear (&first, 1);
  754   
  755   g_date_set_dmy (&first, 1, 1, d->year);
  756   
  757   wd = g_date_get_weekday (&first);
  758   if (wd == 7) wd = 0; /* make Sunday day 0 */
  759   day = g_date_get_day_of_year (d) - 1;
  760   
  761   return ((day + wd)/7U + (wd == 0 ? 1 : 0));
  762 }
  763 
  764 /**
  765  * g_date_get_iso8601_week_of_year:
  766  * @date: a valid #GDate
  767  *
  768  * Returns the week of the year, where weeks are interpreted according
  769  * to ISO 8601. 
  770  * 
  771  * Returns: ISO 8601 week number of the year.
  772  *
  773  * Since: 2.6
  774  **/
  775 guint
  776 g_date_get_iso8601_week_of_year (const GDate *d)
  777 {
  778   guint j, d4, L, d1, w;
  779 
  780   g_return_val_if_fail (g_date_valid (d), 0);
  781   
  782   if (!d->julian)
  783     g_date_update_julian (d);
  784 
  785   g_return_val_if_fail (d->julian, 0);
  786 
  787   /* Formula taken from the Calendar FAQ; the formula was for the
  788    * Julian Period which starts on 1 January 4713 BC, so we add
  789    * 1,721,425 to the number of days before doing the formula. 
  790    */
  791   j  = d->julian_days + 1721425;
  792   d4 = (j + 31741 - (j % 7)) % 146097 % 36524 % 1461;
  793   L  = d4 / 1460;
  794   d1 = ((d4 - L) % 365) + L;
  795   w  = d1 / 7 + 1;
  796 
  797   return w;
  798 }
  799 
  800 /**
  801  * g_date_days_between:
  802  * @date1: the first date
  803  * @date2: the second date
  804  *
  805  * Computes the number of days between two dates.
  806  * If @date2 is prior to @date1, the returned value is negative.
  807  * Both dates must be valid.
  808  *
  809  * Returns: the number of days between @date1 and @date2
  810  */
  811 gint
  812 g_date_days_between (const GDate *d1,
  813              const GDate *d2)
  814 {
  815   g_return_val_if_fail (g_date_valid (d1), 0);
  816   g_return_val_if_fail (g_date_valid (d2), 0);
  817 
  818   return (gint)g_date_get_julian (d2) - (gint)g_date_get_julian (d1);
  819 }
  820 
  821 /**
  822  * g_date_clear:
  823  * @date: pointer to one or more dates to clear
  824  * @n_dates: number of dates to clear
  825  *
  826  * Initializes one or more #GDate structs to a sane but invalid
  827  * state. The cleared dates will not represent an existing date, but will
  828  * not contain garbage. Useful to init a date declared on the stack.
  829  * Validity can be tested with g_date_valid().
  830  */
  831 void         
  832 g_date_clear (GDate *d, guint ndates)
  833 {
  834   g_return_if_fail (d != NULL);
  835   g_return_if_fail (ndates != 0);
  836   
  837   memset (d, 0x0, ndates*sizeof (GDate)); 
  838 }
  839 
  840 G_LOCK_DEFINE_STATIC (g_date_global);
  841 
  842 /* These are for the parser, output to the user should use *
  843  * g_date_strftime () - this creates more never-freed memory to annoy
  844  * all those memory debugger users. :-) 
  845  */
  846 
  847 static gchar *long_month_names[13] = 
  848 { 
  849   NULL,
  850 };
  851 
  852 static gchar *short_month_names[13] = 
  853 {
  854   NULL, 
  855 };
  856 
  857 /* This tells us if we need to update the parse info */
  858 static gchar *current_locale = NULL;
  859 
  860 /* order of these in the current locale */
  861 static GDateDMY dmy_order[3] = 
  862 {
  863    G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR
  864 };
  865 
  866 /* Where to chop two-digit years: i.e., for the 1930 default, numbers
  867  * 29 and below are counted as in the year 2000, numbers 30 and above
  868  * are counted as in the year 1900.  
  869  */
  870 
  871 static const GDateYear twodigit_start_year = 1930;
  872 
  873 /* It is impossible to enter a year between 1 AD and 99 AD with this
  874  * in effect.  
  875  */
  876 static gboolean using_twodigit_years = FALSE;
  877 
  878 /* Adjustment of locale era to AD, non-zero means using locale era
  879  */
  880 static gint locale_era_adjust = 0;
  881 
  882 struct _GDateParseTokens {
  883   gint num_ints;
  884   gint n[3];
  885   guint month;
  886 };
  887 
  888 typedef struct _GDateParseTokens GDateParseTokens;
  889 
  890 #define NUM_LEN 10
  891 
  892 /* HOLDS: g_date_global_lock */
  893 static void
  894 g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
  895 {
  896   gchar num[4][NUM_LEN+1];
  897   gint i;
  898   const guchar *s;
  899   
  900   /* We count 4, but store 3; so we can give an error
  901    * if there are 4.
  902    */
  903   num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0';
  904   
  905   s = (const guchar *) str;
  906   pt->num_ints = 0;
  907   while (*s && pt->num_ints < 4) 
  908     {
  909       
  910       i = 0;
  911       while (*s && g_ascii_isdigit (*s) && i < NUM_LEN)
  912         {
  913           num[pt->num_ints][i] = *s;
  914           ++s; 
  915           ++i;
  916         }
  917       
  918       if (i > 0) 
  919         {
  920           num[pt->num_ints][i] = '\0';
  921           ++(pt->num_ints);
  922         }
  923       
  924       if (*s == '\0') break;
  925       
  926       ++s;
  927     }
  928   
  929   pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0;
  930   pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0;
  931   pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0;
  932   
  933   pt->month = G_DATE_BAD_MONTH;
  934   
  935   if (pt->num_ints < 3)
  936     {
  937       gchar *casefold;
  938       gchar *normalized;
  939       
  940       casefold = g_utf8_casefold (str, -1);
  941       normalized = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL);
  942       g_free (casefold);
  943 
  944       i = 1;
  945       while (i < 13)
  946         {
  947           if (long_month_names[i] != NULL) 
  948             {
  949               const gchar *found = strstr (normalized, long_month_names[i]);
  950           
  951               if (found != NULL)
  952                 {
  953                   pt->month = i;
  954           break;
  955                 }
  956             }
  957       
  958           if (short_month_names[i] != NULL) 
  959             {
  960               const gchar *found = strstr (normalized, short_month_names[i]);
  961           
  962               if (found != NULL)
  963                 {
  964                   pt->month = i;
  965           break;
  966                 }
  967             }
  968 
  969           ++i;
  970         }
  971 
  972       g_free (normalized);
  973     }
  974 }
  975 
  976 /* HOLDS: g_date_global_lock */
  977 static void
  978 g_date_prepare_to_parse (const gchar      *str, 
  979                          GDateParseTokens *pt)
  980 {
  981   const gchar *locale = setlocale (LC_TIME, NULL);
  982   gboolean recompute_localeinfo = FALSE;
  983   GDate d;
  984   
  985   g_return_if_fail (locale != NULL); /* should not happen */
  986   
  987   g_date_clear (&d, 1);              /* clear for scratch use */
  988   
  989   if ( (current_locale == NULL) || (strcmp (locale, current_locale) != 0) ) 
  990     recompute_localeinfo = TRUE;  /* Uh, there used to be a reason for the temporary */
  991   
  992   if (recompute_localeinfo)
  993     {
  994       int i = 1;
  995       GDateParseTokens testpt;
  996       gchar buf[128];
  997       
  998       g_free (current_locale); /* still works if current_locale == NULL */
  999       
 1000       current_locale = g_strdup (locale);
 1001       
 1002       short_month_names[0] = "Error";
 1003       long_month_names[0] = "Error";
 1004 
 1005       while (i < 13) 
 1006         {
 1007       gchar *casefold;
 1008       
 1009           g_date_set_dmy (&d, 1, i, 1);
 1010       
 1011           g_return_if_fail (g_date_valid (&d));
 1012       
 1013           g_date_strftime (buf, 127, "%b", &d);
 1014 
 1015       casefold = g_utf8_casefold (buf, -1);
 1016           g_free (short_month_names[i]);
 1017           short_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL);
 1018       g_free (casefold);
 1019       
 1020           g_date_strftime (buf, 127, "%B", &d);
 1021       casefold = g_utf8_casefold (buf, -1);
 1022           g_free (long_month_names[i]);
 1023           long_month_names[i] = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL);
 1024       g_free (casefold);
 1025           
 1026           ++i;
 1027         }
 1028       
 1029       /* Determine DMY order */
 1030       
 1031       /* had to pick a random day - don't change this, some strftimes
 1032        * are broken on some days, and this one is good so far. */
 1033       g_date_set_dmy (&d, 4, 7, 1976);
 1034       
 1035       g_date_strftime (buf, 127, "%x", &d);
 1036       
 1037       g_date_fill_parse_tokens (buf, &testpt);
 1038       
 1039       i = 0;
 1040       while (i < testpt.num_ints)
 1041         {
 1042           switch (testpt.n[i])
 1043             {
 1044             case 7:
 1045               dmy_order[i] = G_DATE_MONTH;
 1046               break;
 1047             case 4:
 1048               dmy_order[i] = G_DATE_DAY;
 1049               break;
 1050             case 76:
 1051               using_twodigit_years = TRUE; /* FALL THRU */
 1052             case 1976:
 1053               dmy_order[i] = G_DATE_YEAR;
 1054               break;
 1055             default:
 1056               /* assume locale era */
 1057               locale_era_adjust = 1976 - testpt.n[i];
 1058               dmy_order[i] = G_DATE_YEAR;
 1059               break;
 1060             }
 1061           ++i;
 1062         }
 1063       
 1064 #if defined(G_ENABLE_DEBUG) && 0
 1065       DEBUG_MSG (("**GDate prepared a new set of locale-specific parse rules."));
 1066       i = 1;
 1067       while (i < 13) 
 1068         {
 1069           DEBUG_MSG (("  %s   %s", long_month_names[i], short_month_names[i]));
 1070           ++i;
 1071         }
 1072       if (using_twodigit_years)
 1073         {
 1074       DEBUG_MSG (("**Using twodigit years with cutoff year: %u", twodigit_start_year));
 1075         }
 1076       { 
 1077         gchar *strings[3];
 1078         i = 0;
 1079         while (i < 3)
 1080           {
 1081             switch (dmy_order[i])
 1082               {
 1083               case G_DATE_MONTH:
 1084                 strings[i] = "Month";
 1085                 break;
 1086               case G_DATE_YEAR:
 1087                 strings[i] = "Year";
 1088                 break;
 1089               case G_DATE_DAY:
 1090                 strings[i] = "Day";
 1091                 break;
 1092               default:
 1093                 strings[i] = NULL;
 1094                 break;
 1095               }
 1096             ++i;
 1097           }
 1098         DEBUG_MSG (("**Order: %s, %s, %s", strings[0], strings[1], strings[2]));
 1099         DEBUG_MSG (("**Sample date in this locale: '%s'", buf));
 1100       }
 1101 #endif
 1102     }
 1103   
 1104   g_date_fill_parse_tokens (str, pt);
 1105 }
 1106 
 1107 /**
 1108  * g_date_set_parse:
 1109  * @date: a #GDate to fill in
 1110  * @str: string to parse
 1111  *
 1112  * Parses a user-inputted string @str, and try to figure out what date it
 1113  * represents, taking the <link linkend="setlocale">current locale</link>
 1114  * into account. If the string is successfully parsed, the date will be
 1115  * valid after the call. Otherwise, it will be invalid. You should check
 1116  * using g_date_valid() to see whether the parsing succeeded.
 1117  *
 1118  * This function is not appropriate for file formats and the like; it
 1119  * isn't very precise, and its exact behavior varies with the locale.
 1120  * It's intended to be a heuristic routine that guesses what the user
 1121  * means by a given string (and it does work pretty well in that
 1122  * capacity).
 1123  */
 1124 void         
 1125 g_date_set_parse (GDate       *d, 
 1126                   const gchar *str)
 1127 {
 1128   GDateParseTokens pt;
 1129   guint m = G_DATE_BAD_MONTH, day = G_DATE_BAD_DAY, y = G_DATE_BAD_YEAR;
 1130   
 1131   g_return_if_fail (d != NULL);
 1132   
 1133   /* set invalid */
 1134   g_date_clear (d, 1);
 1135   
 1136   G_LOCK (g_date_global);
 1137 
 1138   g_date_prepare_to_parse (str, &pt);
 1139   
 1140   DEBUG_MSG (("Found %d ints, '%d' '%d' '%d' and written out month %d",
 1141           pt.num_ints, pt.n[0], pt.n[1], pt.n[2], pt.month));
 1142   
 1143   
 1144   if (pt.num_ints == 4) 
 1145     {
 1146       G_UNLOCK (g_date_global);
 1147       return; /* presumably a typo; bail out. */
 1148     }
 1149   
 1150   if (pt.num_ints > 1)
 1151     {
 1152       int i = 0;
 1153       int j = 0;
 1154       
 1155       g_assert (pt.num_ints < 4); /* i.e., it is 2 or 3 */
 1156       
 1157       while (i < pt.num_ints && j < 3) 
 1158         {
 1159           switch (dmy_order[j])
 1160             {
 1161             case G_DATE_MONTH:
 1162         {
 1163           if (pt.num_ints == 2 && pt.month != G_DATE_BAD_MONTH)
 1164         {
 1165           m = pt.month;
 1166           ++j;      /* skip months, but don't skip this number */
 1167           continue;
 1168         }
 1169           else 
 1170         m = pt.n[i];
 1171         }
 1172         break;
 1173             case G_DATE_DAY:
 1174         {
 1175           if (pt.num_ints == 2 && pt.month == G_DATE_BAD_MONTH)
 1176         {
 1177           day = 1;
 1178           ++j;      /* skip days, since we may have month/year */
 1179           continue;
 1180         }
 1181           day = pt.n[i];
 1182         }
 1183         break;
 1184             case G_DATE_YEAR:
 1185         {
 1186           y  = pt.n[i];
 1187           
 1188           if (locale_era_adjust != 0)
 1189             {
 1190           y += locale_era_adjust;
 1191             }
 1192           else if (using_twodigit_years && y < 100)
 1193         {
 1194           guint two     =  twodigit_start_year % 100;
 1195           guint century = (twodigit_start_year / 100) * 100;
 1196           
 1197           if (y < two)
 1198             century += 100;
 1199           
 1200           y += century;
 1201         }
 1202         }
 1203         break;
 1204             default:
 1205               break;
 1206             }
 1207       
 1208           ++i;
 1209           ++j;
 1210         }
 1211       
 1212       
 1213       if (pt.num_ints == 3 && !g_date_valid_dmy (day, m, y))
 1214         {
 1215           /* Try YYYY MM DD */
 1216           y   = pt.n[0];
 1217           m   = pt.n[1];
 1218           day = pt.n[2];
 1219           
 1220           if (using_twodigit_years && y < 100) 
 1221             y = G_DATE_BAD_YEAR; /* avoids ambiguity */
 1222         }
 1223       else if (pt.num_ints == 2)
 1224     {
 1225       if (m == G_DATE_BAD_MONTH && pt.month != G_DATE_BAD_MONTH)
 1226         m = pt.month;
 1227     }
 1228     }
 1229   else if (pt.num_ints == 1) 
 1230     {
 1231       if (pt.month != G_DATE_BAD_MONTH)
 1232         {
 1233           /* Month name and year? */
 1234           m    = pt.month;
 1235           day  = 1;
 1236           y = pt.n[0];
 1237         }
 1238       else
 1239         {
 1240           /* Try yyyymmdd and yymmdd */
 1241       
 1242           m   = (pt.n[0]/100) % 100;
 1243           day = pt.n[0] % 100;
 1244           y   = pt.n[0]/10000;
 1245       
 1246           /* FIXME move this into a separate function */
 1247           if (using_twodigit_years && y < 100)
 1248             {
 1249               guint two     =  twodigit_start_year % 100;
 1250               guint century = (twodigit_start_year / 100) * 100;
 1251               
 1252               if (y < two)
 1253                 century += 100;
 1254               
 1255               y += century;
 1256             }
 1257         }
 1258     }
 1259   
 1260   /* See if we got anything valid out of all this. */
 1261   /* y < 8000 is to catch 19998 style typos; the library is OK up to 65535 or so */
 1262   if (y < 8000 && g_date_valid_dmy (day, m, y)) 
 1263     {
 1264       d->month = m;
 1265       d->day   = day;
 1266       d->year  = y;
 1267       d->dmy   = TRUE;
 1268     }
 1269 #ifdef G_ENABLE_DEBUG
 1270   else 
 1271     {
 1272       DEBUG_MSG (("Rejected DMY %u %u %u", day, m, y));
 1273     }
 1274 #endif
 1275   G_UNLOCK (g_date_global);
 1276 }
 1277 
 1278 /**
 1279  * g_date_set_time_t:
 1280  * @date: a #GDate 
 1281  * @timet: <type>time_t</type> value to set
 1282  *
 1283  * Sets the value of a date to the date corresponding to a time 
 1284  * specified as a time_t. The time to date conversion is done using 
 1285  * the user's current timezone.
 1286  *
 1287  * To set the value of a date to the current day, you could write:
 1288  * |[
 1289  *  g_date_set_time_t (date, time (NULL)); 
 1290  * ]|
 1291  *
 1292  * Since: 2.10
 1293  */
 1294 void         
 1295 g_date_set_time_t (GDate *date,
 1296            time_t timet)
 1297 {
 1298   struct tm tm;
 1299   
 1300   g_return_if_fail (date != NULL);
 1301   
 1302 #ifdef HAVE_LOCALTIME_R
 1303   localtime_r (&timet, &tm);
 1304 #else
 1305   {
 1306     struct tm *ptm = localtime (&timet);
 1307 
 1308     if (ptm == NULL)
 1309       {
 1310     /* Happens at least in Microsoft's C library if you pass a
 1311      * negative time_t. Use 2000-01-01 as default date.
 1312      */
 1313 #ifndef G_DISABLE_CHECKS
 1314     g_return_if_fail_warning (G_LOG_DOMAIN, "g_date_set_time", "ptm != NULL");
 1315 #endif
 1316 
 1317     tm.tm_mon = 0;
 1318     tm.tm_mday = 1;
 1319     tm.tm_year = 100;
 1320       }
 1321     else
 1322       memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm));
 1323   }
 1324 #endif
 1325   
 1326   date->julian = FALSE;
 1327   
 1328   date->month = tm.tm_mon + 1;
 1329   date->day   = tm.tm_mday;
 1330   date->year  = tm.tm_year + 1900;
 1331   
 1332   g_return_if_fail (g_date_valid_dmy (date->day, date->month, date->year));
 1333   
 1334   date->dmy    = TRUE;
 1335 }
 1336 
 1337 
 1338 /**
 1339  * g_date_set_time:
 1340  * @date: a #GDate.
 1341  * @time_: #GTime value to set.
 1342  *
 1343  * Sets the value of a date from a #GTime value.
 1344  * The time to date conversion is done using the user's current timezone.
 1345  *
 1346  * Deprecated: 2.10: Use g_date_set_time_t() instead.
 1347  */
 1348 void
 1349 g_date_set_time (GDate *date,
 1350          GTime  time_)
 1351 {
 1352   g_date_set_time_t (date, (time_t) time_);
 1353 }
 1354 
 1355 /**
 1356  * g_date_set_time_val:
 1357  * @date: a #GDate 
 1358  * @timeval: #GTimeVal value to set
 1359  *
 1360  * Sets the value of a date from a #GTimeVal value.  Note that the
 1361  * @tv_usec member is ignored, because #GDate can't make use of the
 1362  * additional precision.
 1363  *
 1364  * The time to date conversion is done using the user's current timezone.
 1365  *
 1366  * Since: 2.10
 1367  */
 1368 void
 1369 g_date_set_time_val (GDate    *date,
 1370              GTimeVal *timeval)
 1371 {
 1372   g_date_set_time_t (date, (time_t) timeval->tv_sec);
 1373 }
 1374 
 1375 /**
 1376  * g_date_set_month:
 1377  * @date: a #GDate
 1378  * @month: month to set
 1379  *
 1380  * Sets the month of the year for a #GDate.  If the resulting
 1381  * day-month-year triplet is invalid, the date will be invalid.
 1382  */
 1383 void         
 1384 g_date_set_month (GDate     *d, 
 1385                   GDateMonth m)
 1386 {
 1387   g_return_if_fail (d != NULL);
 1388   g_return_if_fail (g_date_valid_month (m));
 1389 
 1390   if (d->julian && !d->dmy) g_date_update_dmy(d);
 1391   d->julian = FALSE;
 1392   
 1393   d->month = m;
 1394   
 1395   if (g_date_valid_dmy (d->day, d->month, d->year))
 1396     d->dmy = TRUE;
 1397   else 
 1398     d->dmy = FALSE;
 1399 }
 1400 
 1401 /**
 1402  * g_date_set_day:
 1403  * @date: a #GDate
 1404  * @day: day to set
 1405  *
 1406  * Sets the day of the month for a #GDate. If the resulting
 1407  * day-month-year triplet is invalid, the date will be invalid.
 1408  */
 1409 void         
 1410 g_date_set_day (GDate    *d, 
 1411                 GDateDay  day)
 1412 {
 1413   g_return_if_fail (d != NULL);
 1414   g_return_if_fail (g_date_valid_day (day));
 1415   
 1416   if (d->julian && !d->dmy) g_date_update_dmy(d);
 1417   d->julian = FALSE;
 1418   
 1419   d->day = day;
 1420   
 1421   if (g_date_valid_dmy (d->day, d->month, d->year))
 1422     d->dmy = TRUE;
 1423   else 
 1424     d->dmy = FALSE;
 1425 }
 1426 
 1427 /**
 1428  * g_date_set_year:
 1429  * @date: a #GDate
 1430  * @year: year to set
 1431  *
 1432  * Sets the year for a #GDate. If the resulting day-month-year
 1433  * triplet is invalid, the date will be invalid.
 1434  */
 1435 void         
 1436 g_date_set_year (GDate     *d, 
 1437                  GDateYear  y)
 1438 {
 1439   g_return_if_fail (d != NULL);
 1440   g_return_if_fail (g_date_valid_year (y));
 1441   
 1442   if (d->julian && !d->dmy) g_date_update_dmy(d);
 1443   d->julian = FALSE;
 1444   
 1445   d->year = y;
 1446   
 1447   if (g_date_valid_dmy (d->day, d->month, d->year))
 1448     d->dmy = TRUE;
 1449   else 
 1450     d->dmy = FALSE;
 1451 }
 1452 
 1453 /**
 1454  * g_date_set_dmy:
 1455  * @date: a #GDate
 1456  * @day: day
 1457  * @month: month
 1458  * @y: year
 1459  *
 1460  * Sets the value of a #GDate from a day, month, and year.
 1461  * The day-month-year triplet must be valid; if you aren't
 1462  * sure it is, call g_date_valid_dmy() to check before you
 1463  * set it.
 1464  */
 1465 void         
 1466 g_date_set_dmy (GDate      *d, 
 1467                 GDateDay    day, 
 1468                 GDateMonth  m, 
 1469                 GDateYear   y)
 1470 {
 1471   g_return_if_fail (d != NULL);
 1472   g_return_if_fail (g_date_valid_dmy (day, m, y));
 1473   
 1474   d->julian = FALSE;
 1475   
 1476   d->month = m;
 1477   d->day   = day;
 1478   d->year  = y;
 1479   
 1480   d->dmy = TRUE;
 1481 }
 1482 
 1483 /**
 1484  * g_date_set_julian:
 1485  * @date: a #GDate
 1486  * @julian_date: Julian day number (days since January 1, Year 1)
 1487  *
 1488  * Sets the value of a #GDate from a Julian day number.
 1489  */
 1490 void         
 1491 g_date_set_julian (GDate   *d, 
 1492                    guint32  j)
 1493 {
 1494   g_return_if_fail (d != NULL);
 1495   g_return_if_fail (g_date_valid_julian (j));
 1496   
 1497   d->julian_days = j;
 1498   d->julian = TRUE;
 1499   d->dmy = FALSE;
 1500 }
 1501 
 1502 /**
 1503  * g_date_is_first_of_month:
 1504  * @date: a #GDate to check
 1505  *
 1506  * Returns %TRUE if the date is on the first of a month.
 1507  * The date must be valid.
 1508  *
 1509  * Returns: %TRUE if the date is the first of the month
 1510  */
 1511 gboolean     
 1512 g_date_is_first_of_month (const GDate *d)
 1513 {
 1514   g_return_val_if_fail (g_date_valid (d), FALSE);
 1515   
 1516   if (!d->dmy) 
 1517     g_date_update_dmy (d);
 1518 
 1519   g_return_val_if_fail (d->dmy, FALSE);  
 1520   
 1521   if (d->day == 1) return TRUE;
 1522   else return FALSE;
 1523 }
 1524 
 1525 /**
 1526  * g_date_is_last_of_month:
 1527  * @date: a #GDate to check
 1528  *
 1529  * Returns %TRUE if the date is the last day of the month.
 1530  * The date must be valid.
 1531  *
 1532  * Returns: %TRUE if the date is the last day of the month
 1533  */
 1534 gboolean     
 1535 g_date_is_last_of_month (const GDate *d)
 1536 {
 1537   gint idx;
 1538   
 1539   g_return_val_if_fail (g_date_valid (d), FALSE);
 1540   
 1541   if (!d->dmy) 
 1542     g_date_update_dmy (d);
 1543 
 1544   g_return_val_if_fail (d->dmy, FALSE);  
 1545   
 1546   idx = g_date_is_leap_year (d->year) ? 1 : 0;
 1547   
 1548   if (d->day == days_in_months[idx][d->month]) return TRUE;
 1549   else return FALSE;
 1550 }
 1551 
 1552 /**
 1553  * g_date_add_days:
 1554  * @date: a #GDate to increment
 1555  * @n_days: number of days to move the date forward
 1556  *
 1557  * Increments a date some number of days.
 1558  * To move forward by weeks, add weeks*7 days.
 1559  * The date must be valid.
 1560  */
 1561 void         
 1562 g_date_add_days (GDate *d, 
 1563                  guint  ndays)
 1564 {
 1565   g_return_if_fail (g_date_valid (d));
 1566   
 1567   if (!d->julian)
 1568     g_date_update_julian (d);
 1569 
 1570   g_return_if_fail (d->julian);
 1571   
 1572   d->julian_days += ndays;
 1573   d->dmy = FALSE;
 1574 }
 1575 
 1576 /**
 1577  * g_date_subtract_days:
 1578  * @date: a #GDate to decrement
 1579  * @n_days: number of days to move
 1580  *
 1581  * Moves a date some number of days into the past.
 1582  * To move by weeks, just move by weeks*7 days.
 1583  * The date must be valid.
 1584  */
 1585 void         
 1586 g_date_subtract_days (GDate *d, 
 1587                       guint  ndays)
 1588 {
 1589   g_return_if_fail (g_date_valid (d));
 1590   
 1591   if (!d->julian)
 1592     g_date_update_julian (d);
 1593 
 1594   g_return_if_fail (d->julian);
 1595   g_return_if_fail (d->julian_days > ndays);
 1596   
 1597   d->julian_days -= ndays;
 1598   d->dmy = FALSE;
 1599 }
 1600 
 1601 /**
 1602  * g_date_add_months:
 1603  * @date: a #GDate to increment
 1604  * @n_months: number of months to move forward
 1605  *
 1606  * Increments a date by some number of months.
 1607  * If the day of the month is greater than 28,
 1608  * this routine may change the day of the month
 1609  * (because the destination month may not have
 1610  * the current day in it). The date must be valid.
 1611  */
 1612 void         
 1613 g_date_add_months (GDate *d, 
 1614                    guint  nmonths)
 1615 {
 1616   guint years, months;
 1617   gint idx;
 1618   
 1619   g_return_if_fail (g_date_valid (d));
 1620   
 1621   if (!d->dmy) 
 1622     g_date_update_dmy (d);
 1623 
 1624   g_return_if_fail (d->dmy);  
 1625   
 1626   nmonths += d->month - 1;
 1627   
 1628   years  = nmonths/12;
 1629   months = nmonths%12;
 1630   
 1631   d->month = months + 1;
 1632   d->year  += years;
 1633   
 1634   idx = g_date_is_leap_year (d->year) ? 1 : 0;
 1635   
 1636   if (d->day > days_in_months[idx][d->month])
 1637     d->day = days_in_months[idx][d->month];
 1638   
 1639   d->julian = FALSE;
 1640   
 1641   g_return_if_fail (g_date_valid (d));
 1642 }
 1643 
 1644 /**
 1645  * g_date_subtract_months:
 1646  * @date: a #GDate to decrement
 1647  * @n_months: number of months to move
 1648  *
 1649  * Moves a date some number of months into the past.
 1650  * If the current day of the month doesn't exist in
 1651  * the destination month, the day of the month
 1652  * may change. The date must be valid.
 1653  */
 1654 void         
 1655 g_date_subtract_months (GDate *d, 
 1656                         guint  nmonths)
 1657 {
 1658   guint years, months;
 1659   gint idx;
 1660   
 1661   g_return_if_fail (g_date_valid (d));
 1662   
 1663   if (!d->dmy) 
 1664     g_date_update_dmy (d);
 1665 
 1666   g_return_if_fail (d->dmy);  
 1667   
 1668   years  = nmonths/12;
 1669   months = nmonths%12;
 1670   
 1671   g_return_if_fail (d->year > years);
 1672   
 1673   d->year  -= years;
 1674   
 1675   if (d->month > months) d->month -= months;
 1676   else 
 1677     {
 1678       months -= d->month;
 1679       d->month = 12 - months;
 1680       d->year -= 1;
 1681     }
 1682   
 1683   idx = g_date_is_leap_year (d->year) ? 1 : 0;
 1684   
 1685   if (d->day > days_in_months[idx][d->month])
 1686     d->day = days_in_months[idx][d->month];
 1687   
 1688   d->julian = FALSE;
 1689   
 1690   g_return_if_fail (g_date_valid (d));
 1691 }
 1692 
 1693 /**
 1694  * g_date_add_years:
 1695  * @date: a #GDate to increment
 1696  * @n_years: number of years to move forward
 1697  *
 1698  * Increments a date by some number of years.
 1699  * If the date is February 29, and the destination
 1700  * year is not a leap year, the date will be changed
 1701  * to February 28. The date must be valid.
 1702  */
 1703 void         
 1704 g_date_add_years (GDate *d, 
 1705                   guint  nyears)
 1706 {
 1707   g_return_if_fail (g_date_valid (d));
 1708   
 1709   if (!d->dmy) 
 1710     g_date_update_dmy (d);
 1711 
 1712   g_return_if_fail (d->dmy);  
 1713   
 1714   d->year += nyears;
 1715   
 1716   if (d->month == 2 && d->day == 29)
 1717     {
 1718       if (!g_date_is_leap_year (d->year))
 1719         d->day = 28;
 1720     }
 1721   
 1722   d->julian = FALSE;
 1723 }
 1724 
 1725 /**
 1726  * g_date_subtract_years:
 1727  * @date: a #GDate to decrement
 1728  * @n_years: number of years to move
 1729  *
 1730  * Moves a date some number of years into the past.
 1731  * If the current day doesn't exist in the destination
 1732  * year (i.e. it's February 29 and you move to a non-leap-year)
 1733  * then the day is changed to February 29. The date
 1734  * must be valid.
 1735  */
 1736 void         
 1737 g_date_subtract_years (GDate *d, 
 1738                        guint  nyears)
 1739 {
 1740   g_return_if_fail (g_date_valid (d));
 1741   
 1742   if (!d->dmy) 
 1743     g_date_update_dmy (d);
 1744 
 1745   g_return_if_fail (d->dmy);  
 1746   g_return_if_fail (d->year > nyears);
 1747   
 1748   d->year -= nyears;
 1749   
 1750   if (d->month == 2 && d->day == 29)
 1751     {
 1752       if (!g_date_is_leap_year (d->year))
 1753         d->day = 28;
 1754     }
 1755   
 1756   d->julian = FALSE;
 1757 }
 1758 
 1759 /**
 1760  * g_date_is_leap_year:
 1761  * @year: year to check
 1762  *
 1763  * Returns %TRUE if the year is a leap year.
 1764  * <footnote><para>For the purposes of this function,
 1765  * leap year is every year divisible by 4 unless that year
 1766  * is divisible by 100. If it is divisible by 100 it would
 1767  * be a leap year only if that year is also divisible
 1768  * by 400.</para></footnote>
 1769  *
 1770  * Returns: %TRUE if the year is a leap year
 1771  */
 1772 gboolean     
 1773 g_date_is_leap_year (GDateYear year)
 1774 {
 1775   g_return_val_if_fail (g_date_valid_year (year), FALSE);
 1776   
 1777   return ( (((year % 4) == 0) && ((year % 100) != 0)) ||
 1778            (year % 400) == 0 );
 1779 }
 1780 
 1781 /**
 1782  * g_date_get_days_in_month:
 1783  * @month: month
 1784  * @year: year
 1785  *
 1786  * Returns the number of days in a month, taking leap
 1787  * years into account.
 1788  *
 1789  * Returns: number of days in @month during the @year
 1790  */
 1791 guint8         
 1792 g_date_get_days_in_month (GDateMonth month, 
 1793                           GDateYear  year)
 1794 {
 1795   gint idx;
 1796   
 1797   g_return_val_if_fail (g_date_valid_year (year), 0);
 1798   g_return_val_if_fail (g_date_valid_month (month), 0);
 1799   
 1800   idx = g_date_is_leap_year (year) ? 1 : 0;
 1801   
 1802   return days_in_months[idx][month];
 1803 }
 1804 
 1805 /**
 1806  * g_date_get_monday_weeks_in_year:
 1807  * @year: a year
 1808  *
 1809  * Returns the number of weeks in the year, where weeks
 1810  * are taken to start on Monday. Will be 52 or 53. The
 1811  * date must be valid. (Years always have 52 7-day periods,
 1812  * plus 1 or 2 extra days depending on whether it's a leap
 1813  * year. This function is basically telling you how many
 1814  * Mondays are in the year, i.e. there are 53 Mondays if
 1815  * one of the extra days happens to be a Monday.)
 1816  *
 1817  * Returns: number of Mondays in the year
 1818  */
 1819 guint8       
 1820 g_date_get_monday_weeks_in_year (GDateYear year)
 1821 {
 1822   GDate d;
 1823   
 1824   g_return_val_if_fail (g_date_valid_year (year), 0);
 1825   
 1826   g_date_clear (&d, 1);
 1827   g_date_set_dmy (&d, 1, 1, year);
 1828   if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53;
 1829   g_date_set_dmy (&d, 31, 12, year);
 1830   if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53;
 1831   if (g_date_is_leap_year (year)) 
 1832     {
 1833       g_date_set_dmy (&d, 2, 1, year);
 1834       if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53;
 1835       g_date_set_dmy (&d, 30, 12, year);
 1836       if (g_date_get_weekday (&d) == G_DATE_MONDAY) return 53;
 1837     }
 1838   return 52;
 1839 }
 1840 
 1841 /**
 1842  * g_date_get_sunday_weeks_in_year:
 1843  * @year: year to count weeks in
 1844  *
 1845  * Returns the number of weeks in the year, where weeks
 1846  * are taken to start on Sunday. Will be 52 or 53. The
 1847  * date must be valid. (Years always have 52 7-day periods,
 1848  * plus 1 or 2 extra days depending on whether it's a leap
 1849  * year. This function is basically telling you how many
 1850  * Sundays are in the year, i.e. there are 53 Sundays if
 1851  * one of the extra days happens to be a Sunday.)
 1852  *
 1853  * Returns: the number of weeks in @year
 1854  */
 1855 guint8       
 1856 g_date_get_sunday_weeks_in_year (GDateYear year)
 1857 {
 1858   GDate d;
 1859   
 1860   g_return_val_if_fail (g_date_valid_year (year), 0);
 1861   
 1862   g_date_clear (&d, 1);
 1863   g_date_set_dmy (&d, 1, 1, year);
 1864   if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53;
 1865   g_date_set_dmy (&d, 31, 12, year);
 1866   if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53;
 1867   if (g_date_is_leap_year (year)) 
 1868     {
 1869       g_date_set_dmy (&d, 2, 1, year);
 1870       if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53;
 1871       g_date_set_dmy (&d, 30, 12, year);
 1872       if (g_date_get_weekday (&d) == G_DATE_SUNDAY) return 53;
 1873     }
 1874   return 52;
 1875 }
 1876 
 1877 /**
 1878  * g_date_compare:
 1879  * @lhs: first date to compare
 1880  * @rhs: second date to compare
 1881  *
 1882  * qsort()-style comparison function for dates.
 1883  * Both dates must be valid.
 1884  *
 1885  * Returns: 0 for equal, less than zero if @lhs is less than @rhs,
 1886  *     greater than zero if @lhs is greater than @rhs
 1887  */
 1888 gint         
 1889 g_date_compare (const GDate *lhs, 
 1890                 const GDate *rhs)
 1891 {
 1892   g_return_val_if_fail (lhs != NULL, 0);
 1893   g_return_val_if_fail (rhs != NULL, 0);
 1894   g_return_val_if_fail (g_date_valid (lhs), 0);
 1895   g_return_val_if_fail (g_date_valid (rhs), 0);
 1896   
 1897   /* Remember the self-comparison case! I think it works right now. */
 1898   
 1899   while (TRUE)
 1900     {
 1901       if (lhs->julian && rhs->julian) 
 1902         {
 1903           if (lhs->julian_days < rhs->julian_days) return -1;
 1904           else if (lhs->julian_days > rhs->julian_days) return 1;
 1905           else                                          return 0;
 1906         }
 1907       else if (lhs->dmy && rhs->dmy) 
 1908         {
 1909           if (lhs->year < rhs->year)               return -1;
 1910           else if (lhs->year > rhs->year)               return 1;
 1911           else 
 1912             {
 1913               if (lhs->month < rhs->month)         return -1;
 1914               else if (lhs->month > rhs->month)         return 1;
 1915               else 
 1916                 {
 1917                   if (lhs->day < rhs->day)              return -1;
 1918                   else if (lhs->day > rhs->day)              return 1;
 1919                   else                                       return 0;
 1920                 }
 1921               
 1922             }
 1923           
 1924         }
 1925       else
 1926         {
 1927           if (!lhs->julian) g_date_update_julian (lhs);
 1928           if (!rhs->julian) g_date_update_julian (rhs);
 1929           g_return_val_if_fail (lhs->julian, 0);
 1930           g_return_val_if_fail (rhs->julian, 0);
 1931         }
 1932       
 1933     }
 1934   return 0; /* warnings */
 1935 }
 1936 
 1937 /**
 1938  * g_date_to_struct_tm:
 1939  * @date: a #GDate to set the <structname>struct tm</structname> from
 1940  * @tm: <structname>struct tm</structname> to fill
 1941  *
 1942  * Fills in the date-related bits of a <structname>struct tm</structname>
 1943  * using the @date value. Initializes the non-date parts with something
 1944  * sane but meaningless.
 1945  */
 1946 void        
 1947 g_date_to_struct_tm (const GDate *d, 
 1948                      struct tm   *tm)
 1949 {
 1950   GDateWeekday day;
 1951      
 1952   g_return_if_fail (g_date_valid (d));
 1953   g_return_if_fail (tm != NULL);
 1954   
 1955   if (!d->dmy) 
 1956     g_date_update_dmy (d);
 1957 
 1958   g_return_if_fail (d->dmy);
 1959   
 1960   /* zero all the irrelevant fields to be sure they're valid */
 1961   
 1962   /* On Linux and maybe other systems, there are weird non-POSIX
 1963    * fields on the end of struct tm that choke strftime if they
 1964    * contain garbage.  So we need to 0 the entire struct, not just the
 1965    * fields we know to exist. 
 1966    */
 1967   
 1968   memset (tm, 0x0, sizeof (struct tm));
 1969   
 1970   tm->tm_mday = d->day;
 1971   tm->tm_mon  = d->month - 1; /* 0-11 goes in tm */
 1972   tm->tm_year = ((int)d->year) - 1900; /* X/Open says tm_year can be negative */
 1973   
 1974   day = g_date_get_weekday (d);
 1975   if (day == 7) day = 0; /* struct tm wants days since Sunday, so Sunday is 0 */
 1976   
 1977   tm->tm_wday = (int)day;
 1978   
 1979   tm->tm_yday = g_date_get_day_of_year (d) - 1; /* 0 to 365 */
 1980   tm->tm_isdst = -1; /* -1 means "information not available" */
 1981 }
 1982 
 1983 /**
 1984  * g_date_clamp:
 1985  * @date: a #GDate to clamp
 1986  * @min_date: minimum accepted value for @date
 1987  * @max_date: maximum accepted value for @date
 1988  *
 1989  * If @date is prior to @min_date, sets @date equal to @min_date.
 1990  * If @date falls after @max_date, sets @date equal to @max_date.
 1991  * Otherwise, @date is unchanged.
 1992  * Either of @min_date and @max_date may be %NULL.
 1993  * All non-%NULL dates must be valid.
 1994  */
 1995 void
 1996 g_date_clamp (GDate       *date,
 1997           const GDate *min_date,
 1998           const GDate *max_date)
 1999 {
 2000   g_return_if_fail (g_date_valid (date));
 2001 
 2002   if (min_date != NULL)
 2003     g_return_if_fail (g_date_valid (min_date));
 2004 
 2005   if (max_date != NULL)
 2006     g_return_if_fail (g_date_valid (max_date));
 2007 
 2008   if (min_date != NULL && max_date != NULL)
 2009     g_return_if_fail (g_date_compare (min_date, max_date) <= 0);
 2010 
 2011   if (min_date && g_date_compare (date, min_date) < 0)
 2012     *date = *min_date;
 2013 
 2014   if (max_date && g_date_compare (max_date, date) < 0)
 2015     *date = *max_date;
 2016 }
 2017 
 2018 /**
 2019  * g_date_order:
 2020  * @date1: the first date
 2021  * @date2: the second date
 2022  *
 2023  * Checks if @date1 is less than or equal to @date2,
 2024  * and swap the values if this is not the case.
 2025  */
 2026 void
 2027 g_date_order (GDate *date1,
 2028               GDate *date2)
 2029 {
 2030   g_return_if_fail (g_date_valid (date1));
 2031   g_return_if_fail (g_date_valid (date2));
 2032 
 2033   if (g_date_compare (date1, date2) > 0)
 2034     {
 2035       GDate tmp = *date1;
 2036       *date1 = *date2;
 2037       *date2 = tmp;
 2038     }
 2039 }
 2040 
 2041 #ifdef G_OS_WIN32
 2042 static gsize
 2043 win32_strftime_helper (const GDate     *d,
 2044                const gchar     *format,
 2045                const struct tm *tm,
 2046                gchar           *s,
 2047                gsize            slen)
 2048 {
 2049   SYSTEMTIME systemtime;
 2050   TIME_ZONE_INFORMATION tzinfo;
 2051   LCID lcid;
 2052   int n, k;
 2053   GArray *result;
 2054   const gchar *p;
 2055   gunichar c;
 2056   const wchar_t digits[] = L"0123456789";
 2057   gchar *convbuf;
 2058   glong convlen = 0;
 2059   gsize retval;
 2060 
 2061   systemtime.wYear = tm->tm_year + 1900;
 2062   systemtime.wMonth = tm->tm_mon + 1;
 2063   systemtime.wDayOfWeek = tm->tm_wday;
 2064   systemtime.wDay = tm->tm_mday;
 2065   systemtime.wHour = tm->tm_hour;
 2066   systemtime.wMinute = tm->tm_min;
 2067   systemtime.wSecond = tm->tm_sec;
 2068   systemtime.wMilliseconds = 0;
 2069   
 2070   lcid = GetThreadLocale ();
 2071   result = g_array_sized_new (FALSE, FALSE, sizeof (wchar_t), MAX (128, strlen (format) * 2));
 2072 
 2073   p = format;
 2074   while (*p)
 2075     {
 2076       c = g_utf8_get_char (p);
 2077       if (c == '%')
 2078     {
 2079       p = g_utf8_next_char (p);
 2080       if (!*p)
 2081         {
 2082           s[0] = '\0';
 2083           g_array_free (result, TRUE);
 2084 
 2085           return 0;
 2086         }
 2087       
 2088       c = g_utf8_get_char (p);
 2089       if (c == 'E' || c == 'O')
 2090         {
 2091           /* Ignore modified conversion specifiers for now. */
 2092           p = g_utf8_next_char (p);
 2093           if (!*p)
 2094         {
 2095           s[0] = '\0';
 2096           g_array_free (result, TRUE);
 2097           
 2098           return 0;
 2099         }
 2100 
 2101           c = g_utf8_get_char (p);
 2102         }
 2103 
 2104       switch (c)
 2105         {
 2106         case 'a':
 2107           if (systemtime.wDayOfWeek == 0)
 2108         k = 6;
 2109           else
 2110         k = systemtime.wDayOfWeek - 1;
 2111           n = GetLocaleInfoW (lcid, LOCALE_SABBREVDAYNAME1+k, NULL, 0);
 2112           g_array_set_size (result, result->len + n);
 2113           GetLocaleInfoW (lcid, LOCALE_SABBREVDAYNAME1+k, ((wchar_t *) result->data) + result->len - n, n);
 2114           g_array_set_size (result, result->len - 1);
 2115           break;
 2116         case 'A':
 2117           if (systemtime.wDayOfWeek == 0)
 2118         k = 6;
 2119           else
 2120         k = systemtime.wDayOfWeek - 1;
 2121           n = GetLocaleInfoW (lcid, LOCALE_SDAYNAME1+k, NULL, 0);
 2122           g_array_set_size (result, result->len + n);
 2123           GetLocaleInfoW (lcid, LOCALE_SDAYNAME1+k, ((wchar_t *) result->data) + result->len - n, n);
 2124           g_array_set_size (result, result->len - 1);
 2125           break;
 2126         case 'b':
 2127         case 'h':
 2128           n = GetLocaleInfoW (lcid, LOCALE_SABBREVMONTHNAME1+systemtime.wMonth-1, NULL, 0);
 2129           g_array_set_size (result, result->len + n);
 2130           GetLocaleInfoW (lcid, LOCALE_SABBREVMONTHNAME1+systemtime.wMonth-1, ((wchar_t *) result->data) + result->len - n, n);
 2131           g_array_set_size (result, result->len - 1);
 2132           break;
 2133         case 'B':
 2134           n = GetLocaleInfoW (lcid, LOCALE_SMONTHNAME1+systemtime.wMonth-1, NULL, 0);
 2135           g_array_set_size (result, result->len + n);
 2136           GetLocaleInfoW (lcid, LOCALE_SMONTHNAME1+systemtime.wMonth-1, ((wchar_t *) result->data) + result->len - n, n);
 2137           g_array_set_size (result, result->len - 1);
 2138           break;
 2139         case 'c':
 2140           n = GetDateFormatW (lcid, 0, &systemtime, NULL, NULL, 0);
 2141           if (n > 0)
 2142         {
 2143           g_array_set_size (result, result->len + n);
 2144           GetDateFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n);
 2145           g_array_set_size (result, result->len - 1);
 2146         }
 2147           g_array_append_vals (result, L" ", 1);
 2148           n = GetTimeFormatW (lcid, 0, &systemtime, NULL, NULL, 0);
 2149           if (n > 0)
 2150         {
 2151           g_array_set_size (result, result->len + n);
 2152           GetTimeFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n);
 2153           g_array_set_size (result, result->len - 1);
 2154         }
 2155           break;
 2156         case 'C':
 2157           g_array_append_vals (result, digits + systemtime.wYear/1000, 1);
 2158           g_array_append_vals (result, digits + (systemtime.wYear/1000)%10, 1);
 2159           break;
 2160         case 'd':
 2161           g_array_append_vals (result, digits + systemtime.wDay/10, 1);
 2162           g_array_append_vals (result, digits + systemtime.wDay%10, 1);
 2163           break;
 2164         case 'D':
 2165           g_array_append_vals (result, digits + systemtime.wMonth/10, 1);
 2166           g_array_append_vals (result, digits + systemtime.wMonth%10, 1);
 2167           g_array_append_vals (result, L"/", 1);
 2168           g_array_append_vals (result, digits + systemtime.wDay/10, 1);
 2169           g_array_append_vals (result, digits + systemtime.wDay%10, 1);
 2170           g_array_append_vals (result, L"/", 1);
 2171           g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1);
 2172           g_array_append_vals (result, digits + systemtime.wYear%10, 1);
 2173           break;
 2174         case 'e':
 2175           if (systemtime.wDay >= 10)
 2176         g_array_append_vals (result, digits + systemtime.wDay/10, 1);
 2177           else
 2178         g_array_append_vals (result, L" ", 1);
 2179           g_array_append_vals (result, digits + systemtime.wDay%10, 1);
 2180           break;
 2181 
 2182           /* A GDate has no time fields, so for now we can
 2183            * hardcode all time conversions into zeros (or 12 for
 2184            * %I). The alternative code snippets in the #else
 2185            * branches are here ready to be taken into use when
 2186            * needed by a g_strftime() or g_date_and_time_format()
 2187            * or whatever.
 2188            */
 2189         case 'H':
 2190 #if 1
 2191           g_array_append_vals (result, L"00", 2);
 2192 #else
 2193           g_array_append_vals (result, digits + systemtime.wHour/10, 1);
 2194           g_array_append_vals (result, digits + systemtime.wHour%10, 1);
 2195 #endif
 2196           break;
 2197         case 'I':
 2198 #if 1
 2199           g_array_append_vals (result, L"12", 2);
 2200 #else
 2201           if (systemtime.wHour == 0)
 2202         g_array_append_vals (result, L"12", 2);
 2203           else
 2204         {
 2205           g_array_append_vals (result, digits + (systemtime.wHour%12)/10, 1);
 2206           g_array_append_vals (result, digits + (systemtime.wHour%12)%10, 1);
 2207         }
 2208 #endif
 2209           break;
 2210         case  'j':
 2211           g_array_append_vals (result, digits + (tm->tm_yday+1)/100, 1);
 2212           g_array_append_vals (result, digits + ((tm->tm_yday+1)/10)%10, 1);
 2213           g_array_append_vals (result, digits + (tm->tm_yday+1)%10, 1);
 2214           break;
 2215         case 'm':
 2216           g_array_append_vals (result, digits + systemtime.wMonth/10, 1);
 2217           g_array_append_vals (result, digits + systemtime.wMonth%10, 1);
 2218           break;
 2219         case 'M':
 2220 #if 1
 2221           g_array_append_vals (result, L"00", 2);
 2222 #else
 2223           g_array_append_vals (result, digits + systemtime.wMinute/10, 1);
 2224           g_array_append_vals (result, digits + systemtime.wMinute%10, 1);
 2225 #endif
 2226           break;
 2227         case 'n':
 2228           g_array_append_vals (result, L"\n", 1);
 2229           break;
 2230         case 'p':
 2231           n = GetTimeFormatW (lcid, 0, &systemtime, L"tt", NULL, 0);
 2232           if (n > 0)
 2233         {
 2234           g_array_set_size (result, result->len + n);
 2235           GetTimeFormatW (lcid, 0, &systemtime, L"tt", ((wchar_t *) result->data) + result->len - n, n);
 2236           g_array_set_size (result, result->len - 1);
 2237         }
 2238           break;
 2239         case 'r':
 2240           /* This is a rather odd format. Hard to say what to do.
 2241            * Let's always use the POSIX %I:%M:%S %p
 2242            */
 2243 #if 1
 2244           g_array_append_vals (result, L"12:00:00", 8);
 2245 #else
 2246           if (systemtime.wHour == 0)
 2247         g_array_append_vals (result, L"12", 2);
 2248           else
 2249         {
 2250           g_array_append_vals (result, digits + (systemtime.wHour%12)/10, 1);
 2251           g_array_append_vals (result, digits + (systemtime.wHour%12)%10, 1);
 2252         }
 2253           g_array_append_vals (result, L":", 1);
 2254           g_array_append_vals (result, digits + systemtime.wMinute/10, 1);
 2255           g_array_append_vals (result, digits + systemtime.wMinute%10, 1);
 2256           g_array_append_vals (result, L":", 1);
 2257           g_array_append_vals (result, digits + systemtime.wSecond/10, 1);
 2258           g_array_append_vals (result, digits + systemtime.wSecond%10, 1);
 2259           g_array_append_vals (result, L" ", 1);
 2260 #endif
 2261           n = GetTimeFormatW (lcid, 0, &systemtime, L"tt", NULL, 0);
 2262           if (n > 0)
 2263         {
 2264           g_array_set_size (result, result->len + n);
 2265           GetTimeFormatW (lcid, 0, &systemtime, L"tt", ((wchar_t *) result->data) + result->len - n, n);
 2266           g_array_set_size (result, result->len - 1);
 2267         }
 2268           break;
 2269         case 'R':
 2270 #if 1
 2271           g_array_append_vals (result, L"00:00", 5);
 2272 #else
 2273           g_array_append_vals (result, digits + systemtime.wHour/10, 1);
 2274           g_array_append_vals (result, digits + systemtime.wHour%10, 1);
 2275           g_array_append_vals (result, L":", 1);
 2276           g_array_append_vals (result, digits + systemtime.wMinute/10, 1);
 2277           g_array_append_vals (result, digits + systemtime.wMinute%10, 1);
 2278 #endif
 2279           break;
 2280         case 'S':
 2281 #if 1
 2282           g_array_append_vals (result, L"00", 2);
 2283 #else
 2284           g_array_append_vals (result, digits + systemtime.wSecond/10, 1);
 2285           g_array_append_vals (result, digits + systemtime.wSecond%10, 1);
 2286 #endif
 2287           break;
 2288         case 't':
 2289           g_array_append_vals (result, L"\t", 1);
 2290           break;
 2291         case 'T':
 2292 #if 1
 2293           g_array_append_vals (result, L"00:00:00", 8);
 2294 #else
 2295           g_array_append_vals (result, digits + systemtime.wHour/10, 1);
 2296           g_array_append_vals (result, digits + systemtime.wHour%10, 1);
 2297           g_array_append_vals (result, L":", 1);
 2298           g_array_append_vals (result, digits + systemtime.wMinute/10, 1);
 2299           g_array_append_vals (result, digits + systemtime.wMinute%10, 1);
 2300           g_array_append_vals (result, L":", 1);
 2301           g_array_append_vals (result, digits + systemtime.wSecond/10, 1);
 2302           g_array_append_vals (result, digits + systemtime.wSecond%10, 1);
 2303 #endif
 2304           break;
 2305         case 'u':
 2306           if (systemtime.wDayOfWeek == 0)
 2307         g_array_append_vals (result, L"7", 1);
 2308           else
 2309         g_array_append_vals (result, digits + systemtime.wDayOfWeek, 1);
 2310           break;
 2311         case 'U':
 2312           n = g_date_get_sunday_week_of_year (d);
 2313           g_array_append_vals (result, digits + n/10, 1);
 2314           g_array_append_vals (result, digits + n%10, 1);
 2315           break;
 2316         case 'V':
 2317           n = g_date_get_iso8601_week_of_year (d);
 2318           g_array_append_vals (result, digits + n/10, 1);
 2319           g_array_append_vals (result, digits + n%10, 1);
 2320           break;
 2321         case 'w':
 2322           g_array_append_vals (result, digits + systemtime.wDayOfWeek, 1);
 2323           break;
 2324         case 'W':
 2325           n = g_date_get_monday_week_of_year (d);
 2326           g_array_append_vals (result, digits + n/10, 1);
 2327           g_array_append_vals (result, digits + n%10, 1);
 2328           break;
 2329         case 'x':
 2330           n = GetDateFormatW (lcid, 0, &systemtime, NULL, NULL, 0);
 2331           if (n > 0)
 2332         {
 2333           g_array_set_size (result, result->len + n);
 2334           GetDateFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n);
 2335           g_array_set_size (result, result->len - 1);
 2336         }
 2337           break;
 2338         case 'X':
 2339           n = GetTimeFormatW (lcid, 0, &systemtime, NULL, NULL, 0);
 2340           if (n > 0)
 2341         {
 2342           g_array_set_size (result, result->len + n);
 2343           GetTimeFormatW (lcid, 0, &systemtime, NULL, ((wchar_t *) result->data) + result->len - n, n);
 2344           g_array_set_size (result, result->len - 1);
 2345         }
 2346           break;
 2347         case 'y':
 2348           g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1);
 2349           g_array_append_vals (result, digits + systemtime.wYear%10, 1);
 2350           break;
 2351         case 'Y':
 2352           g_array_append_vals (result, digits + systemtime.wYear/1000, 1);
 2353           g_array_append_vals (result, digits + (systemtime.wYear/100)%10, 1);
 2354           g_array_append_vals (result, digits + (systemtime.wYear/10)%10, 1);
 2355           g_array_append_vals (result, digits + systemtime.wYear%10, 1);
 2356           break;
 2357         case 'Z':
 2358           n = GetTimeZoneInformation (&tzinfo);
 2359           if (n == TIME_ZONE_ID_UNKNOWN)
 2360         ;
 2361           else if (n == TIME_ZONE_ID_STANDARD)
 2362         g_array_append_vals (result, tzinfo.StandardName, wcslen (tzinfo.StandardName));
 2363           else if (n == TIME_ZONE_ID_DAYLIGHT)
 2364         g_array_append_vals (result, tzinfo.DaylightName, wcslen (tzinfo.DaylightName));
 2365           break;
 2366         case '%':
 2367           g_array_append_vals (result, L"%", 1);
 2368           break;
 2369         }      
 2370     } 
 2371       else if (c <= 0xFFFF)
 2372     {
 2373       wchar_t wc = c;
 2374       g_array_append_vals (result, &wc, 1);
 2375     }
 2376       else
 2377     {
 2378       glong nwc;
 2379       wchar_t *ws;
 2380 
 2381       ws = g_ucs4_to_utf16 (&c, 1, NULL, &nwc, NULL);
 2382       g_array_append_vals (result, ws, nwc);
 2383       g_free (ws);
 2384     }
 2385       p = g_utf8_next_char (p);
 2386     }
 2387   
 2388   convbuf = g_utf16_to_utf8 ((wchar_t *) result->data, result->len, NULL, &convlen, NULL);
 2389   g_array_free (result, TRUE);
 2390 
 2391   if (!convbuf)
 2392     {
 2393       s[0] = '\0';
 2394       return 0;
 2395     }
 2396   
 2397   if (slen <= convlen)
 2398     {
 2399       /* Ensure only whole characters are copied into the buffer. */
 2400       gchar *end = g_utf8_find_prev_char (convbuf, convbuf + slen);
 2401       g_assert (end != NULL);
 2402       convlen = end - convbuf;
 2403 
 2404       /* Return 0 because the buffer isn't large enough. */
 2405       retval = 0;
 2406     }
 2407   else
 2408     retval = convlen;
 2409 
 2410   memcpy (s, convbuf, convlen);
 2411   s[convlen] = '\0';
 2412   g_free (convbuf);
 2413 
 2414   return retval;
 2415 }
 2416 
 2417 #endif
 2418 
 2419 /**
 2420  * g_date_strftime:
 2421  * @s: destination buffer
 2422  * @slen: buffer size
 2423  * @format: format string
 2424  * @date: valid #GDate
 2425  *
 2426  * Generates a printed representation of the date, in a
 2427  * <link linkend="setlocale">locale</link>-specific way.
 2428  * Works just like the platform's C library strftime() function,
 2429  * but only accepts date-related formats; time-related formats
 2430  * give undefined results. Date must be valid. Unlike strftime()
 2431  * (which uses the locale encoding), works on a UTF-8 format
 2432  * string and stores a UTF-8 result.
 2433  *
 2434  * This function does not provide any conversion specifiers in
 2435  * addition to those implemented by the platform's C library.
 2436  * For example, don't expect that using g_date_strftime() would
 2437  * make the \%F provided by the C99 strftime() work on Windows
 2438  * where the C library only complies to C89.
 2439  *
 2440  * Returns: number of characters written to the buffer, or 0 the buffer was too small
 2441  */
 2442 #pragma GCC diagnostic push
 2443 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 2444 
 2445 gsize     
 2446 g_date_strftime (gchar       *s, 
 2447                  gsize        slen, 
 2448                  const gchar *format, 
 2449                  const GDate *d)
 2450 {
 2451   struct tm tm;
 2452 #ifndef G_OS_WIN32
 2453   gsize locale_format_len = 0;
 2454   gchar *locale_format;
 2455   gsize tmplen;
 2456   gchar *tmpbuf;
 2457   gsize tmpbufsize;
 2458   gsize convlen = 0;
 2459   gchar *convbuf;
 2460   GError *error = NULL;
 2461   gsize retval;
 2462 #endif
 2463 
 2464   g_return_val_if_fail (g_date_valid (d), 0);
 2465   g_return_val_if_fail (slen > 0, 0); 
 2466   g_return_val_if_fail (format != NULL, 0);
 2467   g_return_val_if_fail (s != NULL, 0);
 2468 
 2469   g_date_to_struct_tm (d, &tm);
 2470 
 2471 #ifdef G_OS_WIN32
 2472   if (!g_utf8_validate (format, -1, NULL))
 2473     {
 2474       s[0] = '\0';
 2475       return 0;
 2476     }
 2477   return win32_strftime_helper (d, format, &tm, s, slen);
 2478 #else
 2479 
 2480   locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error);
 2481 
 2482   if (error)
 2483     {
 2484       g_warning (G_STRLOC "Error converting format to locale encoding: %s\n", error->message);
 2485       g_error_free (error);
 2486 
 2487       s[0] = '\0';
 2488       return 0;
 2489     }
 2490 
 2491   tmpbufsize = MAX (128, locale_format_len * 2);
 2492   while (TRUE)
 2493     {
 2494       tmpbuf = g_malloc (tmpbufsize);
 2495 
 2496       /* Set the first byte to something other than '\0', to be able to
 2497        * recognize whether strftime actually failed or just returned "".
 2498        */
 2499       tmpbuf[0] = '\1';
 2500       tmplen = strftime (tmpbuf, tmpbufsize, locale_format, &tm);
 2501 
 2502       if (tmplen == 0 && tmpbuf[0] != '\0')
 2503         {
 2504           g_free (tmpbuf);
 2505           tmpbufsize *= 2;
 2506 
 2507           if (tmpbufsize > 65536)
 2508             {
 2509               g_warning (G_STRLOC "Maximum buffer size for g_date_strftime exceeded: giving up\n");
 2510               g_free (locale_format);
 2511 
 2512               s[0] = '\0';
 2513               return 0;
 2514             }
 2515         }
 2516       else
 2517         break;
 2518     }
 2519   g_free (locale_format);
 2520 
 2521   convbuf = g_locale_to_utf8 (tmpbuf, tmplen, NULL, &convlen, &error);
 2522   g_free (tmpbuf);
 2523 
 2524   if (error)
 2525     {
 2526       g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s\n", error->message);
 2527       g_error_free (error);
 2528 
 2529       s[0] = '\0';
 2530       return 0;
 2531     }
 2532 
 2533   if (slen <= convlen)
 2534     {
 2535       /* Ensure only whole characters are copied into the buffer.
 2536        */
 2537       gchar *end = g_utf8_find_prev_char (convbuf, convbuf + slen);
 2538       g_assert (end != NULL);
 2539       convlen = end - convbuf;
 2540 
 2541       /* Return 0 because the buffer isn't large enough.
 2542        */
 2543       retval = 0;
 2544     }
 2545   else
 2546     retval = convlen;
 2547 
 2548   memcpy (s, convbuf, convlen);
 2549   s[convlen] = '\0';
 2550   g_free (convbuf);
 2551 
 2552   return retval;
 2553 #endif
 2554 }
 2555 
 2556 #pragma GCC diagnostic pop