📄 gbx_date.c
字号:
/*************************************************************************** Date.c The date & time management routines Code adapted from GLib 1.2.8 (c) 2000-2004 Beno顃 Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __DATE_C#include <unistd.h>#include <ctype.h>#include "gb_common.h"#include "gb_common_buffer.h"#include "gb_error.h"#include "gbx_value.h"#include "gbx_local.h"#include "gbx_number.h"#include "gbx_date.h"/*#define DEBUG_DATE*/static const char 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 short 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 } /* leap year */};static long date_timezone;static int date_daylight;static double _start_time;/* Returns 1 for a leap year, 0 else */static int date_is_leap_year(short year){ if (year < 0) year += 8001; if ((((year % 4) == 0) && ((year % 100) != 0)) || (year % 400) == 0) return 1; else return 0;}static boolean date_is_valid(DATE_SERIAL *date){ return ((date->month >= 1) && (date->month <= 12) && (date->year >= DATE_YEAR_MIN) && (date->year <= DATE_YEAR_MAX) && (date->year != 0) && (date->day >= 1) && (date->day <= days_in_months[date_is_leap_year(date->year)][(short)date->month]) && (date->hour >= 0) && (date->hour <= 23) && (date->min >= 0) && (date->min <= 59) && (date->sec >= 0) && (date->sec <= 59));}static short date_to_julian_year(short year){ if (year < 0) return year - DATE_YEAR_MIN; else return year - DATE_YEAR_MIN - 1;}static short date_from_julian_year(short year){ if (year < (-DATE_YEAR_MIN)) return year + DATE_YEAR_MIN; else return year + DATE_YEAR_MIN + 1;}PUBLIC void DATE_init(void){ time_t t = (time_t)0L; struct tm *tm; struct timeval tv; if (gettimeofday(&tv, NULL) == 0) _start_time = (double)tv.tv_sec + (double)tv.tv_usec / 1E6; else _start_time = 0.0; tm = localtime(&t); #ifdef __FreeBSD__ date_timezone = tm->tm_gmtoff; date_daylight = tm->tm_isdst; #else date_timezone = timezone; date_daylight = daylight; #endif #ifdef DEBUG_DATE printf("TimeZone = %ld DayLight = %d Hour = %d\n", date_timezone, date_daylight, tm->tm_hour); tm = gmtime(&t); printf("Hour = %d\n", tm->tm_hour); #endif}PUBLIC DATE_SERIAL *DATE_split(VALUE *value){ static long last_nday, last_nmsec; static DATE_SERIAL last_date = { 0 }; long nday, nmsec; long A, B, C, D, E, M; nday = value->_date.date; nmsec = value->_date.time; if (nday > 0) nmsec += date_timezone * 1000; if (nmsec < 0) { nday--; nmsec += 86400000; } else if (nmsec >= 86400000) { nday++; nmsec -= 86400000; } if (last_nmsec != nmsec) { last_nmsec = nmsec; last_date.msec = nmsec % 1000; nmsec /= 1000; last_date.sec = nmsec % 60; nmsec /= 60; last_date.min = nmsec % 60; nmsec /= 60; last_date.hour = nmsec; } if (last_nday != nday) { last_nday = nday; /*nday += DATE_NDAY_BC;*/ if (nday <= 0) { last_date.month = 0; last_date.day = 0; last_date.year = 0; last_date.weekday = 0; } else { A = nday - 58 - 1; 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; last_date.month = M + 3 - (12 * (M / 10)); last_date.day = E - (153 * M + 2)/5; last_date.year = 100 * B + D + (M / 10) /*- 4800*/ ; last_date.year = date_from_julian_year(last_date.year); last_date.weekday = (nday - 1) % 7; } } return &last_date;}PUBLIC bool DATE_make(DATE_SERIAL *date, VALUE *val){ short year; long nday; bool timezone; if (date->year == 0) { nday = 0; /*(-DATE_NDAY_BC - 1);*/ timezone = FALSE; } else { if (!date_is_valid(date)) return TRUE; year = date_to_julian_year(date->year); nday = year * 365; year--; nday += (year >>= 2); nday -= (year /= 25); nday += year >> 2; nday += days_in_year[date_is_leap_year(date->year)][(short)date->month] + date->day; /*nday -= DATE_NDAY_BC;*/ timezone = TRUE; } val->_date.date = nday; val->_date.time = ((date->hour * 60) + date->min) * 60 + date->sec; if (timezone) val->_date.time -= date_timezone; if (val->_date.time < 0) { val->_date.date--; val->_date.time += 86400; } else if (val->_date.time >= 86400) { val->_date.date++; val->_date.time -= 86400; } val->_date.time = (val->_date.time * 1000) + date->msec; val->type = T_DATE; return FALSE;}/*struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; quanti鑝e du mois int tm_mon; int tm_year; int tm_wday; jour de la semaine int tm_yday; jour de l'ann閑 int tm_isdst; d閏alage horaire };*/static int get_current_year(void){ struct tm *tm; struct timeval tv; if (gettimeofday(&tv, NULL) != 0) THROW(E_DATE); tm = localtime((time_t *)&tv.tv_sec); return tm->tm_year + 1900;}PUBLIC void DATE_from_time(time_t time, long usec, VALUE *val){ struct tm *tm; DATE_SERIAL date; tm = localtime(&time); date.year = tm->tm_year + 1900; date.month = tm->tm_mon + 1; date.day = tm->tm_mday; date.hour = tm->tm_hour; date.min = tm->tm_min; date.sec = tm->tm_sec; date.msec = usec / 1000; if (DATE_make(&date, val)) val->type = T_NULL;}PUBLIC void DATE_now(VALUE *val){ struct timeval tv; if (gettimeofday(&tv, NULL) != 0) val->type = T_NULL; else DATE_from_time((time_t)tv.tv_sec, tv.tv_usec, val);}PUBLIC int DATE_to_string(char *buffer, VALUE *value){ DATE_SERIAL *date; int len; date = DATE_split(value); if (value->_date.date == 0) len = sprintf(buffer,"%02d:%02d:%02d", date->hour, date->min, date->sec); else if ((date->hour | date->min | date->sec | date->msec) == 0) len = sprintf(buffer,"%02d/%02d/%04d", date->month, date->day, date->year); else len = sprintf(buffer,"%02d/%02d/%04d %02d:%02d:%02d", date->month, date->day, date->year, date->hour, date->min, date->sec); if (date->msec) { len += sprintf(&buffer[len], ".%03d", date->msec); while (buffer[len - 1] == '0') len--; buffer[len] = 0; } return len;}static boolean read_integer(int *number){ int nbr = 0; int nbr2; int c; boolean minus = FALSE; c = get_char(); if (c == '-') { minus = TRUE; c = get_char(); } else if (c == '+') c = get_char(); if ((c < 0) || !isdigit(c)) return TRUE; for(;;) { nbr2 = nbr * 10 + (c - '0'); if (nbr2 < nbr) return TRUE; nbr = nbr2; c = look_char(); if ((c < 0) || !isdigit(c)) break; buffer_pos++; } *number = nbr; return FALSE;}static boolean read_msec(int *number){ int nbr = 0; int nbr2; int c; int i; c = get_char(); if ((c < 0) || !isdigit(c)) return TRUE; i = 0; for(;;) { i++; nbr2 = nbr * 10 + (c - '0'); if (nbr2 < nbr) return TRUE; nbr = nbr2; if (i == 3) break; c = look_char(); if ((c < 0) || !isdigit(c)) break; buffer_pos++; } for (; i < 3; i++) nbr *= 10; *number = nbr; return FALSE;}static void set_date(DATE_SERIAL *date, int which, int value){ if (which == LO_YEAR) { if (value >= 0 && value <= 99) { if (value > 30) value += 1900; else value += 2000; } date->year = value; } else if (which == LO_MONTH) date->month = value; else if (which == LO_DAY) date->day = value;}static void set_time(DATE_SERIAL *date, int which, int value){ if (which == LO_HOUR) date->hour = value; else if (which == LO_MINUTE) date->min = value; else if (which == LO_SECOND) date->sec = value;}PUBLIC boolean DATE_from_string(const char *str, long len, VALUE *val, boolean local){ DATE_SERIAL date; LOCAL_INFO *info = LOCAL_get(local); int nbr, nbr2; int c, i; boolean has_date = FALSE; boolean has_time = FALSE; CLEAR(&date); buffer_init(str, len); jump_space(); if (read_integer(&nbr)) return TRUE; c = get_char(); if (c == info->date_sep) { has_date = TRUE; if (read_integer(&nbr2)) return TRUE; c = get_char(); if ((c < 0) || isspace(c)) { i = 0; set_date(&date, LO_YEAR, get_current_year()); if (info->date_order[i] == LO_YEAR) i++; set_date(&date, info->date_order[i], nbr); i++; if (info->date_order[i] == LO_YEAR) i++; set_date(&date, info->date_order[i], nbr2); } else if (c == info->date_sep) { set_date(&date, info->date_order[0], nbr); set_date(&date, info->date_order[1], nbr2); if (read_integer(&nbr)) return TRUE; set_date(&date, info->date_order[2], nbr); } jump_space(); c = look_char(); if (c < 0) goto _OK; if (read_integer(&nbr)) return TRUE; c = get_char(); } if (c == info->time_sep) { has_time = TRUE; if (read_integer(&nbr2)) return TRUE; c = get_char(); if ((c < 0) || isspace(c)) { i = 0; if (info->time_order[i] == LO_SECOND) i++; set_time(&date, info->time_order[i], nbr); i++; if (info->time_order[i] == LO_SECOND) i++; set_time(&date, info->time_order[i], nbr2); } else if (c == info->time_sep) { set_time(&date, info->time_order[0], nbr); set_time(&date, info->time_order[1], nbr2); if (read_integer(&nbr)) return TRUE; set_time(&date, info->time_order[2], nbr); c = get_char(); if (c == '.') // msec separator { if (read_msec(&nbr)) return TRUE; date.msec = nbr; } } c = get_char(); if ((c < 0) || isspace(c)) goto _OK; } return TRUE;_OK: if (DATE_make(&date, val)) return TRUE; if (!has_date) val->_date.date = 0; return FALSE;}PUBLIC int DATE_comp(DATE *date1, DATE *date2){ if (date1->date < date2->date) return (-1); if (date1->date > date2->date) return 1; if (date1->time < date2->time) return (-1); if (date1->time > date2->time) return 1; return 0;}PUBLIC int DATE_comp_value(VALUE *date1, VALUE *date2){ return DATE_comp((DATE *)&date1->_date.date, (DATE *)&date2->_date.date);}PUBLIC bool DATE_timer(double *result, int from_start){ struct timeval tv; *result = 0; if (gettimeofday(&tv, NULL) == 0) { *result = (double)tv.tv_sec + (double)tv.tv_usec / 1E6; if (from_start) *result -= _start_time; return FALSE; } else return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -