123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- /* glpmpl05.c */
- /***********************************************************************
- * This code is part of GLPK (GNU Linear Programming Kit).
- *
- * Authors: Andrew Makhorin <mao@gnu.org>
- * Heinrich Schuchardt <xypron.glpk@gmx.de>
- *
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
- * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
- * E-mail: <mao@gnu.org>.
- *
- * GLPK 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 3 of the License, or
- * (at your option) any later version.
- *
- * GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>.
- ***********************************************************************/
- #define _GLPSTD_STDIO
- #define _GLPSTD_TIME
- #include "glpmpl.h"
- double fn_gmtime(MPL *mpl)
- { /* obtain the current calendar time (UTC) */
- time_t timer;
- struct tm *tm;
- int j;
- time(&timer);
- if (timer == (time_t)(-1))
- err: mpl_error(mpl, "gmtime(); unable to obtain current calendar time");
- tm = gmtime(&timer);
- if (tm == NULL) goto err;
- j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
- if (j < 0) goto err;
- return (((double)(j - jday(1, 1, 1970)) * 24.0 +
- (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
- (double)tm->tm_sec;
- }
- static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday", "Sunday" };
- static char *moon[] = { "January", "February", "March", "April", "May",
- "June", "July", "August", "September", "October", "November",
- "December" };
- static void error1(MPL *mpl, const char *str, const char *s,
- const char *fmt, const char *f, const char *msg)
- { xprintf("Input string passed to str2time:\n");
- xprintf("%s\n", str);
- xprintf("%*s\n", (s - str) + 1, "^");
- xprintf("Format string passed to str2time:\n");
- xprintf("%s\n", fmt);
- xprintf("%*s\n", (f - fmt) + 1, "^");
- mpl_error(mpl, "%s", msg);
- /* no return */
- }
- double fn_str2time(MPL *mpl, const char *str, const char *fmt)
- { /* convert character string to the calendar time */
- int j, year, month, day, hh, mm, ss, zone;
- const char *s, *f;
- year = month = day = hh = mm = ss = -1, zone = INT_MAX;
- s = str;
- for (f = fmt; *f != '\0'; f++)
- { if (*f == '%')
- { f++;
- if (*f == 'b' || *f == 'h')
- { /* the abbreviated month name */
- int k;
- char *name;
- if (month >= 0)
- error1(mpl, str, s, fmt, f, "month multiply specified"
- );
- while (*s == ' ') s++;
- for (month = 1; month <= 12; month++)
- { name = moon[month-1];
- for (k = 0; k <= 2; k++)
- { if (toupper((unsigned char)s[k]) !=
- toupper((unsigned char)name[k])) goto next;
- }
- s += 3;
- for (k = 3; name[k] != '\0'; k++)
- { if (toupper((unsigned char)*s) !=
- toupper((unsigned char)name[k])) break;
- s++;
- }
- break;
- next: ;
- }
- if (month > 12)
- error1(mpl, str, s, fmt, f, "abbreviated month name m"
- "issing or invalid");
- }
- else if (*f == 'd')
- { /* the day of the month as a decimal number (01..31) */
- if (day >= 0)
- error1(mpl, str, s, fmt, f, "day multiply specified");
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "day missing or invalid");
- day = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- day = 10 * day + ((*s++) - '0');
- if (!(1 <= day && day <= 31))
- error1(mpl, str, s, fmt, f, "day out of range");
- }
- else if (*f == 'H')
- { /* the hour as a decimal number, using a 24-hour clock
- (00..23) */
- if (hh >= 0)
- error1(mpl, str, s, fmt, f, "hour multiply specified")
- ;
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "hour missing or invalid")
- ;
- hh = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- hh = 10 * hh + ((*s++) - '0');
- if (!(0 <= hh && hh <= 23))
- error1(mpl, str, s, fmt, f, "hour out of range");
- }
- else if (*f == 'm')
- { /* the month as a decimal number (01..12) */
- if (month >= 0)
- error1(mpl, str, s, fmt, f, "month multiply specified"
- );
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "month missing or invalid"
- );
- month = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- month = 10 * month + ((*s++) - '0');
- if (!(1 <= month && month <= 12))
- error1(mpl, str, s, fmt, f, "month out of range");
- }
- else if (*f == 'M')
- { /* the minute as a decimal number (00..59) */
- if (mm >= 0)
- error1(mpl, str, s, fmt, f, "minute multiply specifie"
- "d");
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "minute missing or invali"
- "d");
- mm = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- mm = 10 * mm + ((*s++) - '0');
- if (!(0 <= mm && mm <= 59))
- error1(mpl, str, s, fmt, f, "minute out of range");
- }
- else if (*f == 'S')
- { /* the second as a decimal number (00..60) */
- if (ss >= 0)
- error1(mpl, str, s, fmt, f, "second multiply specifie"
- "d");
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "second missing or invali"
- "d");
- ss = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- ss = 10 * ss + ((*s++) - '0');
- if (!(0 <= ss && ss <= 60))
- error1(mpl, str, s, fmt, f, "second out of range");
- }
- else if (*f == 'y')
- { /* the year without a century as a decimal number
- (00..99); the values 00 to 68 mean the years 2000 to
- 2068 while the values 69 to 99 mean the years 1969 to
- 1999 */
- if (year >= 0)
- error1(mpl, str, s, fmt, f, "year multiply specified")
- ;
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "year missing or invalid")
- ;
- year = (*s++) - '0';
- if ('0' <= *s && *s <= '9')
- year = 10 * year + ((*s++) - '0');
- year += (year >= 69 ? 1900 : 2000);
- }
- else if (*f == 'Y')
- { /* the year as a decimal number, using the Gregorian
- calendar */
- if (year >= 0)
- error1(mpl, str, s, fmt, f, "year multiply specified")
- ;
- while (*s == ' ') s++;
- if (!('0' <= *s && *s <= '9'))
- error1(mpl, str, s, fmt, f, "year missing or invalid")
- ;
- year = 0;
- for (j = 1; j <= 4; j++)
- { if (!('0' <= *s && *s <= '9')) break;
- year = 10 * year + ((*s++) - '0');
- }
- if (!(1 <= year && year <= 4000))
- error1(mpl, str, s, fmt, f, "year out of range");
- }
- else if (*f == 'z')
- { /* time zone offset in the form zhhmm */
- int z, hh, mm;
- if (zone != INT_MAX)
- error1(mpl, str, s, fmt, f, "time zone offset multipl"
- "y specified");
- while (*s == ' ') s++;
- if (*s == 'Z')
- { z = hh = mm = 0, s++;
- goto skip;
- }
- if (*s == '+')
- z = +1, s++;
- else if (*s == '-')
- z = -1, s++;
- else
- error1(mpl, str, s, fmt, f, "time zone offset sign mi"
- "ssing");
- hh = 0;
- for (j = 1; j <= 2; j++)
- { if (!('0' <= *s && *s <= '9'))
- err1: error1(mpl, str, s, fmt, f, "time zone offset valu"
- "e incomplete or invalid");
- hh = 10 * hh + ((*s++) - '0');
- }
- if (hh > 23)
- err2: error1(mpl, str, s, fmt, f, "time zone offset value o"
- "ut of range");
- if (*s == ':')
- { s++;
- if (!('0' <= *s && *s <= '9')) goto err1;
- }
- mm = 0;
- if (!('0' <= *s && *s <= '9')) goto skip;
- for (j = 1; j <= 2; j++)
- { if (!('0' <= *s && *s <= '9')) goto err1;
- mm = 10 * mm + ((*s++) - '0');
- }
- if (mm > 59) goto err2;
- skip: zone = z * (60 * hh + mm);
- }
- else if (*f == '%')
- { /* literal % character */
- goto test;
- }
- else
- error1(mpl, str, s, fmt, f, "invalid conversion specifie"
- "r");
- }
- else if (*f == ' ')
- ;
- else
- test: { /* check a matching character in the input string */
- if (*s != *f)
- error1(mpl, str, s, fmt, f, "character mismatch");
- s++;
- }
- }
- if (year < 0) year = 1970;
- if (month < 0) month = 1;
- if (day < 0) day = 1;
- if (hh < 0) hh = 0;
- if (mm < 0) mm = 0;
- if (ss < 0) ss = 0;
- if (zone == INT_MAX) zone = 0;
- j = jday(day, month, year);
- xassert(j >= 0);
- return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
- 60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
- }
- static void error2(MPL *mpl, const char *fmt, const char *f,
- const char *msg)
- { xprintf("Format string passed to time2str:\n");
- xprintf("%s\n", fmt);
- xprintf("%*s\n", (f - fmt) + 1, "^");
- mpl_error(mpl, "%s", msg);
- /* no return */
- }
- static int weekday(int j)
- { /* determine weekday number (1 = Mon, ..., 7 = Sun) */
- return (j + jday(1, 1, 1970)) % 7 + 1;
- }
- static int firstday(int year)
- { /* determine the first day of the first week for a specified year
- according to ISO 8601 */
- int j;
- /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
- in week 01; if 1 January is Friday, Saturday or Sunday, it is
- in week 52 or 53 of the previous year */
- j = jday(1, 1, year) - jday(1, 1, 1970);
- switch (weekday(j))
- { case 1: /* 1 Jan is Mon */ j += 0; break;
- case 2: /* 1 Jan is Tue */ j -= 1; break;
- case 3: /* 1 Jan is Wed */ j -= 2; break;
- case 4: /* 1 Jan is Thu */ j -= 3; break;
- case 5: /* 1 Jan is Fri */ j += 3; break;
- case 6: /* 1 Jan is Sat */ j += 2; break;
- case 7: /* 1 Jan is Sun */ j += 1; break;
- default: xassert(j != j);
- }
- /* the first day of the week must be Monday */
- xassert(weekday(j) == 1);
- return j;
- }
- void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
- { /* convert the calendar time to character string */
- int j, year, month, day, hh, mm, ss, len;
- double temp;
- const char *f;
- char buf[MAX_LENGTH+1];
- if (!(-62135596800.0 <= t && t <= 64092211199.0))
- mpl_error(mpl, "time2str(%.*g,...); argument out of range",
- DBL_DIG, t);
- t = floor(t + 0.5);
- temp = fabs(t) / 86400.0;
- j = (int)floor(temp);
- if (t < 0.0)
- { if (temp == floor(temp))
- j = - j;
- else
- j = - (j + 1);
- }
- xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
- ss = (int)(t - 86400.0 * (double)j);
- xassert(0 <= ss && ss < 86400);
- mm = ss / 60, ss %= 60;
- hh = mm / 60, mm %= 60;
- len = 0;
- for (f = fmt; *f != '\0'; f++)
- { if (*f == '%')
- { f++;
- if (*f == 'a')
- { /* the abbreviated weekday name */
- memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
- }
- else if (*f == 'A')
- { /* the full weekday name */
- strcpy(buf, week[weekday(j)-1]);
- }
- else if (*f == 'b' || *f == 'h')
- { /* the abbreviated month name */
- memcpy(buf, moon[month-1], 3), buf[3] = '\0';
- }
- else if (*f == 'B')
- { /* the full month name */
- strcpy(buf, moon[month-1]);
- }
- else if (*f == 'C')
- { /* the century of the year */
- sprintf(buf, "%02d", year / 100);
- }
- else if (*f == 'd')
- { /* the day of the month as a decimal number (01..31) */
- sprintf(buf, "%02d", day);
- }
- else if (*f == 'D')
- { /* the date using the format %m/%d/%y */
- sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
- }
- else if (*f == 'e')
- { /* the day of the month like with %d, but padded with
- blank (1..31) */
- sprintf(buf, "%2d", day);
- }
- else if (*f == 'F')
- { /* the date using the format %Y-%m-%d */
- sprintf(buf, "%04d-%02d-%02d", year, month, day);
- }
- else if (*f == 'g')
- { /* the year corresponding to the ISO week number, but
- without the century (range 00 through 99); this has
- the same format and value as %y, except that if the
- ISO week number (see %V) belongs to the previous or
- next year, that year is used instead */
- int iso;
- if (j < firstday(year))
- iso = year - 1;
- else if (j < firstday(year + 1))
- iso = year;
- else
- iso = year + 1;
- sprintf(buf, "%02d", iso % 100);
- }
- else if (*f == 'G')
- { /* the year corresponding to the ISO week number; this
- has the same format and value as %Y, excepth that if
- the ISO week number (see %V) belongs to the previous
- or next year, that year is used instead */
- int iso;
- if (j < firstday(year))
- iso = year - 1;
- else if (j < firstday(year + 1))
- iso = year;
- else
- iso = year + 1;
- sprintf(buf, "%04d", iso);
- }
- else if (*f == 'H')
- { /* the hour as a decimal number, using a 24-hour clock
- (00..23) */
- sprintf(buf, "%02d", hh);
- }
- else if (*f == 'I')
- { /* the hour as a decimal number, using a 12-hour clock
- (01..12) */
- sprintf(buf, "%02d",
- hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
- }
- else if (*f == 'j')
- { /* the day of the year as a decimal number (001..366) */
- sprintf(buf, "%03d",
- jday(day, month, year) - jday(1, 1, year) + 1);
- }
- else if (*f == 'k')
- { /* the hour as a decimal number, using a 24-hour clock
- like %H, but padded with blank (0..23) */
- sprintf(buf, "%2d", hh);
- }
- else if (*f == 'l')
- { /* the hour as a decimal number, using a 12-hour clock
- like %I, but padded with blank (1..12) */
- sprintf(buf, "%2d",
- hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
- }
- else if (*f == 'm')
- { /* the month as a decimal number (01..12) */
- sprintf(buf, "%02d", month);
- }
- else if (*f == 'M')
- { /* the minute as a decimal number (00..59) */
- sprintf(buf, "%02d", mm);
- }
- else if (*f == 'p')
- { /* either AM or PM, according to the given time value;
- noon is treated as PM and midnight as AM */
- strcpy(buf, hh <= 11 ? "AM" : "PM");
- }
- else if (*f == 'P')
- { /* either am or pm, according to the given time value;
- noon is treated as pm and midnight as am */
- strcpy(buf, hh <= 11 ? "am" : "pm");
- }
- else if (*f == 'r')
- { /* the calendar time using the format %I:%M:%S %p */
- sprintf(buf, "%02d:%02d:%02d %s",
- hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
- mm, ss, hh <= 11 ? "AM" : "PM");
- }
- else if (*f == 'R')
- { /* the hour and minute using the format %H:%M */
- sprintf(buf, "%02d:%02d", hh, mm);
- }
- else if (*f == 'S')
- { /* the second as a decimal number (00..59) */
- sprintf(buf, "%02d", ss);
- }
- else if (*f == 'T')
- { /* the time of day using the format %H:%M:%S */
- sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
- }
- else if (*f == 'u')
- { /* the day of the week as a decimal number (1..7),
- Monday being 1 */
- sprintf(buf, "%d", weekday(j));
- }
- else if (*f == 'U')
- { /* the week number of the current year as a decimal
- number (range 00 through 53), starting with the first
- Sunday as the first day of the first week; days
- preceding the first Sunday in the year are considered
- to be in week 00 */
- #if 1 /* 09/I-2009 */
- #undef sun
- /* causes compilation error in SunOS */
- #endif
- int sun;
- /* sun = the first Sunday of the year */
- sun = jday(1, 1, year) - jday(1, 1, 1970);
- sun += (7 - weekday(sun));
- sprintf(buf, "%02d", (j + 7 - sun) / 7);
- }
- else if (*f == 'V')
- { /* the ISO week number as a decimal number (range 01
- through 53); ISO weeks start with Monday and end with
- Sunday; week 01 of a year is the first week which has
- the majority of its days in that year; week 01 of
- a year can contain days from the previous year; the
- week before week 01 of a year is the last week (52 or
- 53) of the previous year even if it contains days
- from the new year */
- int iso;
- if (j < firstday(year))
- iso = j - firstday(year - 1);
- else if (j < firstday(year + 1))
- iso = j - firstday(year);
- else
- iso = j - firstday(year + 1);
- sprintf(buf, "%02d", iso / 7 + 1);
- }
- else if (*f == 'w')
- { /* the day of the week as a decimal number (0..6),
- Sunday being 0 */
- sprintf(buf, "%d", weekday(j) % 7);
- }
- else if (*f == 'W')
- { /* the week number of the current year as a decimal
- number (range 00 through 53), starting with the first
- Monday as the first day of the first week; days
- preceding the first Monday in the year are considered
- to be in week 00 */
- int mon;
- /* mon = the first Monday of the year */
- mon = jday(1, 1, year) - jday(1, 1, 1970);
- mon += (8 - weekday(mon)) % 7;
- sprintf(buf, "%02d", (j + 7 - mon) / 7);
- }
- else if (*f == 'y')
- { /* the year without a century as a decimal number
- (00..99) */
- sprintf(buf, "%02d", year % 100);
- }
- else if (*f == 'Y')
- { /* the year as a decimal number, using the Gregorian
- calendar */
- sprintf(buf, "%04d", year);
- }
- else if (*f == '%')
- { /* a literal % character */
- buf[0] = '%', buf[1] = '\0';
- }
- else
- error2(mpl, fmt, f, "invalid conversion specifier");
- }
- else
- buf[0] = *f, buf[1] = '\0';
- if (len + strlen(buf) > MAX_LENGTH)
- mpl_error(mpl, "time2str; output string length exceeds %d chara"
- "cters", MAX_LENGTH);
- memcpy(str+len, buf, strlen(buf));
- len += strlen(buf);
- }
- str[len] = '\0';
- return;
- }
- /* eof */
|