source: trunk/drmaa_utils/drmaa_utils/datetime.c @ 1

Revision 1, 7.8 KB checked in by mmamonski, 13 years ago (diff)

Torque/PBS DRMAA initial commit

Line 
1/* $Id: datetime.c 132 2010-04-28 14:34:34Z mamonski $ */
2/*
3 *  FedStage DRMAA utilities library
4 *  Copyright (C) 2006-2008  FedStage Systems
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * @file datetime.c
22 * DRMAA date/time parser.
23 */
24
25#include <ctype.h>
26#include <limits.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <time.h>
31
32#include <drmaa_utils/compat.h>
33#include <drmaa_utils/datetime_impl.h>
34#include <drmaa_utils/datetime_tab.h>
35#include <drmaa_utils/logging.h>
36
37
38void
39fsd_datetime_dump( const fsd_datetime_t *dt, char *s, size_t len )
40{
41        char mask[] = "YMDhmsZ";
42        char sign = '+';
43        long tz_delta = dt->tz_delta;
44        unsigned d_hour, d_min, d_sec;
45        unsigned m;
46        if( tz_delta < 0 )
47         {
48                tz_delta = -tz_delta;
49                sign = '-';
50         }
51        d_sec = tz_delta%60;  tz_delta/=60;
52        d_min = tz_delta%60;  tz_delta/=60;
53        d_hour = tz_delta;
54        for( m=0;  m<7;  m++ )
55         {
56                if( !(dt->mask & (1<<m)) )
57                        mask[m]='-';
58         }
59        snprintf( s, len, "%04d-%02d-%02d %02d:%02d:%02d %c%02d:%02d:%02d [%s]",
60                        dt->year, dt->month, dt->day,
61                        dt->hour, dt->minute, dt->second,
62                        sign, d_hour, d_min, d_sec,
63                        mask
64                        );
65}
66
67
68long
69fsd_timezone( time_t t )
70{
71        struct tm utc_tm;
72        struct tm local_tm;
73        int d;
74        long result;
75
76        gmtime_r( &t, &utc_tm );
77        localtime_r( &t, &local_tm );
78        if( local_tm.tm_year != utc_tm.tm_year )
79                d = local_tm.tm_year - utc_tm.tm_year;
80        else if( local_tm.tm_mon != utc_tm.tm_mon )
81                d = local_tm.tm_mon - utc_tm.tm_mon;
82        else if( local_tm.tm_mday != utc_tm.tm_mday )
83                d = local_tm.tm_mday - utc_tm.tm_mday;
84        else
85                d = 0;
86        result =
87                ( (local_tm.tm_hour-utc_tm.tm_hour)*60
88                + local_tm.tm_min-utc_tm.tm_min )*60
89                + local_tm.tm_sec-utc_tm.tm_sec;
90        if( d > 0 )
91                result += 24*3600;
92        else if( d < 0 )
93                result -= 24*3600;
94        return result;
95}
96
97
98void
99fsd_datetime_fill( fsd_datetime_t *dt, time_t filler )
100{
101        unsigned unfilled = ~dt->mask;
102        struct tm t;
103
104#ifdef DEBUGGING
105        char dbg[256];
106        fsd_datetime_dump( dt, dbg, sizeof(dbg) );
107        fsd_log_enter(( "(dt={%s}, filler=%u)",
108                                dbg, (unsigned)filler ));
109#endif
110
111#ifdef HAVE_STRUCT_TM_GMTOFF
112        /*
113         * glibc have tm_gmtoff field in tm struct
114         * which is number of second east from UTC
115         */
116        if( unfilled & FSD_DT_TZ_DELTA )
117         {
118                localtime_r( &filler, &t );
119                dt->tz_delta = t.tm_gmtoff;
120         }
121        else
122         {
123                filler += dt->tz_delta;
124                gmtime_r( &filler, &t );
125         }
126#else /* ! __GNUC__ */
127        if( unfilled & FSD_DT_TZ_DELTA )
128                dt->tz_delta = fsd_timezone( filler );
129        filler += dt->tz_delta;
130        gmtime_r( &filler, &t );
131#endif
132
133        if( unfilled & FSD_DT_YEAR )
134                dt->year = t.tm_year + 1900;
135        else if( dt->year < 100 )
136                dt->year += 100 * ( (t.tm_year+1900)/100 );
137        if( unfilled & FSD_DT_MONTH )
138                dt->month = t.tm_mon + 1;
139        if( unfilled & FSD_DT_DAY )
140                dt->day = t.tm_mday;
141        if( unfilled & FSD_DT_HOUR )
142                dt->hour = t.tm_hour;
143        if( unfilled & FSD_DT_MINUTE )
144                dt->minute = t.tm_min;
145        if( unfilled & FSD_DT_SECOND )
146                dt->second = 0;
147
148        dt->mask |= FSD_DT_ALL;
149
150#ifdef DEBUGGING
151        fsd_datetime_dump( dt, dbg, sizeof(dbg) );
152        fsd_log_return(( ": dt={%s}", dbg ));
153#endif
154}
155
156
157time_t
158fsd_datetime_mktime( const fsd_datetime_t *dt )
159{
160        const unsigned month_days[12]
161                = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
162        unsigned long year, month;
163        unsigned long years, days;
164        time_t result;
165#ifdef DEBUGGING
166        char dbg[ 128 ];
167        fsd_datetime_dump( dt, dbg, sizeof(dbg) );
168        fsd_log_enter(( "(dt={%s})", dbg ));
169#endif
170        year = dt->year;
171        month = dt->month;
172        while( month < 1 )
173         { year--;  month += 12; }
174        while( month > 12 )
175         { year++;  month -= 12; }
176        years = year - 1970;
177        days = 365*years + (years+1)/4;
178        days += month_days[ month-1 ];
179        if( month > 2  &&  (year&3) == 0 )
180                days ++;
181        days += dt->day - 1;
182        result = ( ( days*24 + dt->hour )*60 + dt->minute )*60
183                + dt->second - dt->tz_delta;
184#ifdef DEBUGGING
185         {
186                struct tm utc_tm;
187                gmtime_r( &result, &utc_tm );
188                fsd_log_trace(( "years=%ld, days=%ld", years, days ));
189                fsd_log_return(( " =%ld (%04d-%02d-%02d %02d:%02d:%02d+00:00)",
190                                        result,
191                                        1900+utc_tm.tm_year, 1+utc_tm.tm_mon, utc_tm.tm_mday,
192                                        utc_tm.tm_hour, utc_tm.tm_min, utc_tm.tm_sec
193                                        ));
194         }
195#endif
196        return result;
197}
198
199
200time_t
201fsd_datetime_after( fsd_datetime_t *dt, time_t t )
202{
203        char dbg[256];
204        unsigned unfilled = ~dt->mask;
205        time_t result;
206
207        fsd_datetime_fill( dt, t );
208        fsd_datetime_dump( dt, dbg, sizeof(dbg) );
209        fsd_log_debug(( "filled: %s", dbg ));
210        result = fsd_datetime_mktime( dt );
211
212        if( result < t )
213         {
214                if( unfilled & FSD_DT_DAY )
215                 {
216                        while( result < t )
217                         {
218                                fsd_log_debug(( "next day" ));
219                                result += 24*3600;
220                         }
221                 }
222                else if( unfilled & FSD_DT_MONTH )
223                 {
224                        while( result < t )
225                         {
226                                fsd_log_debug(( "next month" ));
227                                dt->month++;
228                                result = fsd_datetime_mktime( dt );
229                         }
230                 }
231                else if( unfilled & FSD_DT_YEAR )
232                 {
233                        while( result < t )
234                         {
235                                fsd_log_debug(( "next year" ));
236                                dt->year++;
237                                result = fsd_datetime_mktime( dt );
238                         }
239                 }
240                else /* FIXME: error message */
241                        fsd_exc_raise_fmt( FSD_ERRNO_INVALID_VALUE,
242                                        "'%s' is in the past", dbg );
243         }
244
245        return result;
246}
247
248
249time_t
250fsd_datetime_parse( const char *string )
251{
252#ifdef DEBUGGING
253        char dbg[256];
254#endif
255        fsd_dt_parser_t *volatile parser = NULL;
256        fsd_dt_lexer_t *volatile lexer = NULL;
257        int parse_err = 0;
258        fsd_datetime_t dt;
259        time_t result;
260
261        fsd_log_enter(( "(%s)", string ));
262        TRY
263         {
264                fsd_malloc( parser, fsd_dt_parser_t );
265                fsd_malloc( lexer, fsd_dt_lexer_t );
266
267                parser->lexer = lexer;
268                parser->n_errors = 0;
269                lexer->parser = parser;
270                lexer->begin = lexer->p = (unsigned char*)string;
271                lexer->end = (unsigned char*)( string + strlen(string) );
272                parse_err = fsd_dt_parse( parser, lexer );
273                if( parse_err || parser->n_errors )
274                        fsd_exc_raise_fmt(
275                                        FSD_ERRNO_INVALID_VALUE_FORMAT,
276                                        "invalid date/time format: %s", string
277                                        );
278
279                dt = parser->result;
280#ifdef DEBUGGING
281                fsd_datetime_dump( &dt, dbg, sizeof(dbg) );
282                fsd_log_debug(( "parsed: %s", dbg ));
283#endif
284                result = fsd_datetime_after( &dt, time(NULL) );
285         }
286        FINALLY
287         {
288                fsd_free( parser );
289                fsd_free( lexer );
290         }
291        END_TRY
292
293        fsd_log_return(( "(%s) =%u", string, (unsigned)result ));
294        return result;
295}
296
297
298void
299fsd_dt_error(
300                fsd_dt_parser_t *parser,
301                fsd_dt_lexer_t *lexer __attribute__((unused)),
302                const char *fmt, ... )
303{
304        va_list args;
305        char *msg = NULL;
306        parser->n_errors ++;
307        va_start( args, fmt );
308        vasprintf( &msg, fmt, args );
309        va_end( args );
310        fsd_log_error(( "fsd_dt_error: %s", msg ));
311        free( msg );
312}
313
314
315
316int
317fsd_dt_lex( YYSTYPE *lvalp, fsd_dt_lexer_t *lex )
318{
319        const unsigned char *end = lex->end;
320        /* int sign = +1; */
321        while( isspace(*lex->p)  &&  lex->p != end )
322                lex->p++;
323        if( lex->p == end )
324                return -1;
325        switch( *lex->p )
326         {
327                case '/':  case ':':
328                case '+':  case '-':
329                case 'T':  case 'Z':
330                        return * lex->p++;
331#if 0
332                case '-':
333                        sign = -1;
334                case '+': /* fall through */
335                        if( ++(lex->p) == end )
336                         {
337                                fsd_dt_error( lex->parser, lex, "unexpected EOT" );
338                                return -1;
339                         }
340                default: /* fall through */
341#endif
342                default:
343                 {
344                        int num = 0;
345                        if( ! ('0' <= *lex->p  &&  *lex->p <= '9') )
346                         {
347                                fsd_dt_error( lex->parser, lex, "invalid char '%c'", *(lex->p)++ );
348                                return LEXER_ERROR;
349                         }
350                        while( lex->p != end  &&  '0' <= *lex->p  &&  *lex->p <= '9' )
351                         {
352                                num *= 10;
353                                num += *(lex->p)++ - '0';
354                         }
355                        lvalp->integer = num;
356                        return NUM;
357                 }
358         }
359}
360
361
Note: See TracBrowser for help on using the repository browser.