📄 gdate.c
字号:
/* GLIB - Library of useful routines for C programming * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * Modified by the GLib Team and others 1997-2000. See the AUTHORS * file for a list of people on the GLib Team. See the ChangeLog * files for a list of changes. These files are distributed with * GLib at ftp://ftp.gtk.org/pub/gtk/. *//* * MT safe */#define DEBUG_MSG(x) /* */#ifdef G_ENABLE_DEBUG/* #define DEBUG_MSG(args) g_message args ; */#endif#ifdef HAVE_CONFIG_H#include "glibconfig.h"#endif#include "glib.h"#include <time.h>#include <string.h>#include <stdlib.h>#include <locale.h>GDate*g_date_new (){ GDate *d = g_new0 (GDate, 1); /* happily, 0 is the invalid flag for everything. */ return d;}GDate*g_date_new_dmy (GDateDay day, GDateMonth m, GDateYear y){ GDate *d; g_return_val_if_fail (g_date_valid_dmy (day, m, y), NULL); d = g_new (GDate, 1); d->julian = FALSE; d->dmy = TRUE; d->month = m; d->day = day; d->year = y; g_assert (g_date_valid (d)); return d;}GDate*g_date_new_julian (guint32 j){ GDate *d; g_return_val_if_fail (g_date_valid_julian (j), NULL); d = g_new (GDate, 1); d->julian = TRUE; d->dmy = FALSE; d->julian_days = j; g_assert (g_date_valid (d)); return d;}voidg_date_free (GDate *d){ g_return_if_fail (d != NULL); g_free (d);}gboolean g_date_valid (const GDate *d){ g_return_val_if_fail (d != NULL, FALSE); return (d->julian || d->dmy);}static const guint8 days_in_months[2][13] = { /* error, jan feb mar apr may jun jul aug sep oct nov dec */ { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* leap year */};static const guint16 days_in_year[2][14] = { /* 0, jan feb mar apr may jun jul aug sep oct nov dec */ { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }};gboolean g_date_valid_month (GDateMonth m){ return ( (m > G_DATE_BAD_MONTH) && (m < 13) );}gboolean g_date_valid_year (GDateYear y){ return ( y > G_DATE_BAD_YEAR );}gboolean g_date_valid_day (GDateDay d){ return ( (d > G_DATE_BAD_DAY) && (d < 32) );}gboolean g_date_valid_weekday (GDateWeekday w){ return ( (w > G_DATE_BAD_WEEKDAY) && (w < 8) );}gboolean g_date_valid_julian (guint32 j){ return (j > G_DATE_BAD_JULIAN);}gboolean g_date_valid_dmy (GDateDay d, GDateMonth m, GDateYear y){ return ( (m > G_DATE_BAD_MONTH) && (m < 13) && (d > G_DATE_BAD_DAY) && (y > G_DATE_BAD_YEAR) && /* must check before using g_date_is_leap_year */ (d <= (g_date_is_leap_year (y) ? days_in_months[1][m] : days_in_months[0][m])) );}/* "Julian days" just means an absolute number of days, where Day 1 == * Jan 1, Year 1 */static voidg_date_update_julian (const GDate *const_d){ GDate *d = (GDate *) const_d; GDateYear year; gint index; g_return_if_fail (d != NULL); g_return_if_fail (d->dmy); g_return_if_fail (!d->julian); g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year)); /* What we actually do is: multiply years * 365 days in the year, * add the number of years divided by 4, subtract the number of * years divided by 100 and add the number of years divided by 400, * which accounts for leap year stuff. Code from Steffen Beyer's * DateCalc. */ year = d->year - 1; /* we know d->year > 0 since it's valid */ d->julian_days = year * 365U; d->julian_days += (year >>= 2); /* divide by 4 and add */ d->julian_days -= (year /= 25); /* divides original # years by 100 */ d->julian_days += year >> 2; /* divides by 4, which divides original by 400 */ index = g_date_is_leap_year (d->year) ? 1 : 0; d->julian_days += days_in_year[index][d->month] + d->day; g_return_if_fail (g_date_valid_julian (d->julian_days)); d->julian = TRUE;}static void g_date_update_dmy (const GDate *const_d){ GDate *d = (GDate *) const_d; GDateYear y; GDateMonth m; GDateDay day; guint32 A, B, C, D, E, M; g_return_if_fail (d != NULL); g_return_if_fail (d->julian); g_return_if_fail (!d->dmy); g_return_if_fail (g_date_valid_julian (d->julian_days)); /* Formula taken from the Calendar FAQ; the formula was for the * Julian Period which starts on 1 January 4713 BC, so we add * 1,721,425 to the number of days before doing the formula. * * I'm sure this can be simplified for our 1 January 1 AD period * start, but I can't figure out how to unpack the formula. */ A = d->julian_days + 1721425 + 32045; B = ( 4 *(A + 36524) )/ 146097 - 1; C = A - (146097 * B)/4; D = ( 4 * (C + 365) ) / 1461 - 1; E = C - ((1461*D) / 4); M = (5 * (E - 1) + 2)/153; m = M + 3 - (12*(M/10)); day = E - (153*M + 2)/5; y = 100 * B + D - 4800 + (M/10); #ifdef G_ENABLE_DEBUG if (!g_date_valid_dmy (day, m, y)) { g_warning ("\nOOPS julian: %u computed dmy: %u %u %u\n", d->julian_days, day, m, y); }#endif d->month = m; d->day = day; d->year = y; d->dmy = TRUE;}GDateWeekday g_date_get_weekday (const GDate *d){ g_return_val_if_fail (d != NULL, G_DATE_BAD_WEEKDAY); g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_WEEKDAY); if (!d->julian) { g_date_update_julian (d); } g_return_val_if_fail (d->julian, G_DATE_BAD_WEEKDAY); return ((d->julian_days - 1) % 7) + 1;}GDateMonth g_date_get_month (const GDate *d){ g_return_val_if_fail (d != NULL, G_DATE_BAD_MONTH); g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_MONTH); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, G_DATE_BAD_MONTH); return d->month;}GDateYear g_date_get_year (const GDate *d){ g_return_val_if_fail (d != NULL, G_DATE_BAD_YEAR); g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_YEAR); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, G_DATE_BAD_YEAR); return d->year;}GDateDay g_date_get_day (const GDate *d){ g_return_val_if_fail (d != NULL, G_DATE_BAD_DAY); g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_DAY); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, G_DATE_BAD_DAY); return d->day;}guint32 g_date_get_julian (const GDate *d){ g_return_val_if_fail (d != NULL, G_DATE_BAD_JULIAN); g_return_val_if_fail (g_date_valid (d), G_DATE_BAD_JULIAN); if (!d->julian) { g_date_update_julian (d); } g_return_val_if_fail (d->julian, G_DATE_BAD_JULIAN); return d->julian_days;}guint g_date_get_day_of_year (const GDate *d){ gint index; g_return_val_if_fail (d != NULL, 0); g_return_val_if_fail (g_date_valid (d), 0); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, 0); index = g_date_is_leap_year (d->year) ? 1 : 0; return (days_in_year[index][d->month] + d->day);}guint g_date_get_monday_week_of_year (const GDate *d){ GDateWeekday wd; guint day; GDate first; g_return_val_if_fail (d != NULL, 0); g_return_val_if_fail (g_date_valid (d), 0); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, 0); g_date_clear (&first, 1); g_date_set_dmy (&first, 1, 1, d->year); wd = g_date_get_weekday (&first) - 1; /* make Monday day 0 */ day = g_date_get_day_of_year (d) - 1; return ((day + wd)/7U + (wd == 0 ? 1 : 0));}guint g_date_get_sunday_week_of_year (const GDate *d){ GDateWeekday wd; guint day; GDate first; g_return_val_if_fail (d != NULL, 0); g_return_val_if_fail (g_date_valid (d), 0); if (!d->dmy) { g_date_update_dmy (d); } g_return_val_if_fail (d->dmy, 0); g_date_clear (&first, 1); g_date_set_dmy (&first, 1, 1, d->year); wd = g_date_get_weekday (&first); if (wd == 7) wd = 0; /* make Sunday day 0 */ day = g_date_get_day_of_year (d) - 1; return ((day + wd)/7U + (wd == 0 ? 1 : 0));}gintg_date_days_between (const GDate *d1, const GDate *d2){ g_return_val_if_fail (d1 != NULL, 0); g_return_val_if_fail (d2 != NULL, 0); g_return_val_if_fail (g_date_valid (d1), 0); g_return_val_if_fail (g_date_valid (d2), 0); return (gint)g_date_get_julian (d2) - (gint)g_date_get_julian (d1);}void g_date_clear (GDate *d, guint ndates){ g_return_if_fail (d != NULL); g_return_if_fail (ndates != 0); memset (d, 0x0, ndates*sizeof (GDate)); }G_LOCK_DEFINE_STATIC (g_date_global);/* These are for the parser, output to the user should use * * g_date_strftime () - this creates more never-freed memory to annoy * all those memory debugger users. :-) */static gchar *long_month_names[13] = { "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };static gchar *short_month_names[13] = { "Error", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };/* This tells us if we need to update the parse info */static gchar *current_locale = NULL;/* order of these in the current locale */static GDateDMY dmy_order[3] = { G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR};/* Where to chop two-digit years: i.e., for the 1930 default, numbers * 29 and below are counted as in the year 2000, numbers 30 and above * are counted as in the year 1900. */static GDateYear twodigit_start_year = 1930;/* It is impossible to enter a year between 1 AD and 99 AD with this * in effect. */static gboolean using_twodigit_years = FALSE;struct _GDateParseTokens { gint num_ints; gint n[3]; guint month;};typedef struct _GDateParseTokens GDateParseTokens;#define NUM_LEN 10/* HOLDS: g_date_global_lock */static voidg_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt){ gchar num[4][NUM_LEN+1]; gint i; const guchar *s; /* We count 4, but store 3; so we can give an error * if there are 4. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -