glpmpl05.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /* glpmpl05.c */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Authors: Andrew Makhorin <mao@gnu.org>
  6. * Heinrich Schuchardt <xypron.glpk@gmx.de>
  7. *
  8. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  9. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  10. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  11. * E-mail: <mao@gnu.org>.
  12. *
  13. * GLPK is free software: you can redistribute it and/or modify it
  14. * under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation, either version 3 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  19. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  20. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  21. * License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  25. ***********************************************************************/
  26. #define _GLPSTD_STDIO
  27. #define _GLPSTD_TIME
  28. #include "glpmpl.h"
  29. double fn_gmtime(MPL *mpl)
  30. { /* obtain the current calendar time (UTC) */
  31. time_t timer;
  32. struct tm *tm;
  33. int j;
  34. time(&timer);
  35. if (timer == (time_t)(-1))
  36. err: mpl_error(mpl, "gmtime(); unable to obtain current calendar time");
  37. tm = gmtime(&timer);
  38. if (tm == NULL) goto err;
  39. j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
  40. if (j < 0) goto err;
  41. return (((double)(j - jday(1, 1, 1970)) * 24.0 +
  42. (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
  43. (double)tm->tm_sec;
  44. }
  45. static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
  46. "Friday", "Saturday", "Sunday" };
  47. static char *moon[] = { "January", "February", "March", "April", "May",
  48. "June", "July", "August", "September", "October", "November",
  49. "December" };
  50. static void error1(MPL *mpl, const char *str, const char *s,
  51. const char *fmt, const char *f, const char *msg)
  52. { xprintf("Input string passed to str2time:\n");
  53. xprintf("%s\n", str);
  54. xprintf("%*s\n", (s - str) + 1, "^");
  55. xprintf("Format string passed to str2time:\n");
  56. xprintf("%s\n", fmt);
  57. xprintf("%*s\n", (f - fmt) + 1, "^");
  58. mpl_error(mpl, "%s", msg);
  59. /* no return */
  60. }
  61. double fn_str2time(MPL *mpl, const char *str, const char *fmt)
  62. { /* convert character string to the calendar time */
  63. int j, year, month, day, hh, mm, ss, zone;
  64. const char *s, *f;
  65. year = month = day = hh = mm = ss = -1, zone = INT_MAX;
  66. s = str;
  67. for (f = fmt; *f != '\0'; f++)
  68. { if (*f == '%')
  69. { f++;
  70. if (*f == 'b' || *f == 'h')
  71. { /* the abbreviated month name */
  72. int k;
  73. char *name;
  74. if (month >= 0)
  75. error1(mpl, str, s, fmt, f, "month multiply specified"
  76. );
  77. while (*s == ' ') s++;
  78. for (month = 1; month <= 12; month++)
  79. { name = moon[month-1];
  80. for (k = 0; k <= 2; k++)
  81. { if (toupper((unsigned char)s[k]) !=
  82. toupper((unsigned char)name[k])) goto next;
  83. }
  84. s += 3;
  85. for (k = 3; name[k] != '\0'; k++)
  86. { if (toupper((unsigned char)*s) !=
  87. toupper((unsigned char)name[k])) break;
  88. s++;
  89. }
  90. break;
  91. next: ;
  92. }
  93. if (month > 12)
  94. error1(mpl, str, s, fmt, f, "abbreviated month name m"
  95. "issing or invalid");
  96. }
  97. else if (*f == 'd')
  98. { /* the day of the month as a decimal number (01..31) */
  99. if (day >= 0)
  100. error1(mpl, str, s, fmt, f, "day multiply specified");
  101. while (*s == ' ') s++;
  102. if (!('0' <= *s && *s <= '9'))
  103. error1(mpl, str, s, fmt, f, "day missing or invalid");
  104. day = (*s++) - '0';
  105. if ('0' <= *s && *s <= '9')
  106. day = 10 * day + ((*s++) - '0');
  107. if (!(1 <= day && day <= 31))
  108. error1(mpl, str, s, fmt, f, "day out of range");
  109. }
  110. else if (*f == 'H')
  111. { /* the hour as a decimal number, using a 24-hour clock
  112. (00..23) */
  113. if (hh >= 0)
  114. error1(mpl, str, s, fmt, f, "hour multiply specified")
  115. ;
  116. while (*s == ' ') s++;
  117. if (!('0' <= *s && *s <= '9'))
  118. error1(mpl, str, s, fmt, f, "hour missing or invalid")
  119. ;
  120. hh = (*s++) - '0';
  121. if ('0' <= *s && *s <= '9')
  122. hh = 10 * hh + ((*s++) - '0');
  123. if (!(0 <= hh && hh <= 23))
  124. error1(mpl, str, s, fmt, f, "hour out of range");
  125. }
  126. else if (*f == 'm')
  127. { /* the month as a decimal number (01..12) */
  128. if (month >= 0)
  129. error1(mpl, str, s, fmt, f, "month multiply specified"
  130. );
  131. while (*s == ' ') s++;
  132. if (!('0' <= *s && *s <= '9'))
  133. error1(mpl, str, s, fmt, f, "month missing or invalid"
  134. );
  135. month = (*s++) - '0';
  136. if ('0' <= *s && *s <= '9')
  137. month = 10 * month + ((*s++) - '0');
  138. if (!(1 <= month && month <= 12))
  139. error1(mpl, str, s, fmt, f, "month out of range");
  140. }
  141. else if (*f == 'M')
  142. { /* the minute as a decimal number (00..59) */
  143. if (mm >= 0)
  144. error1(mpl, str, s, fmt, f, "minute multiply specifie"
  145. "d");
  146. while (*s == ' ') s++;
  147. if (!('0' <= *s && *s <= '9'))
  148. error1(mpl, str, s, fmt, f, "minute missing or invali"
  149. "d");
  150. mm = (*s++) - '0';
  151. if ('0' <= *s && *s <= '9')
  152. mm = 10 * mm + ((*s++) - '0');
  153. if (!(0 <= mm && mm <= 59))
  154. error1(mpl, str, s, fmt, f, "minute out of range");
  155. }
  156. else if (*f == 'S')
  157. { /* the second as a decimal number (00..60) */
  158. if (ss >= 0)
  159. error1(mpl, str, s, fmt, f, "second multiply specifie"
  160. "d");
  161. while (*s == ' ') s++;
  162. if (!('0' <= *s && *s <= '9'))
  163. error1(mpl, str, s, fmt, f, "second missing or invali"
  164. "d");
  165. ss = (*s++) - '0';
  166. if ('0' <= *s && *s <= '9')
  167. ss = 10 * ss + ((*s++) - '0');
  168. if (!(0 <= ss && ss <= 60))
  169. error1(mpl, str, s, fmt, f, "second out of range");
  170. }
  171. else if (*f == 'y')
  172. { /* the year without a century as a decimal number
  173. (00..99); the values 00 to 68 mean the years 2000 to
  174. 2068 while the values 69 to 99 mean the years 1969 to
  175. 1999 */
  176. if (year >= 0)
  177. error1(mpl, str, s, fmt, f, "year multiply specified")
  178. ;
  179. while (*s == ' ') s++;
  180. if (!('0' <= *s && *s <= '9'))
  181. error1(mpl, str, s, fmt, f, "year missing or invalid")
  182. ;
  183. year = (*s++) - '0';
  184. if ('0' <= *s && *s <= '9')
  185. year = 10 * year + ((*s++) - '0');
  186. year += (year >= 69 ? 1900 : 2000);
  187. }
  188. else if (*f == 'Y')
  189. { /* the year as a decimal number, using the Gregorian
  190. calendar */
  191. if (year >= 0)
  192. error1(mpl, str, s, fmt, f, "year multiply specified")
  193. ;
  194. while (*s == ' ') s++;
  195. if (!('0' <= *s && *s <= '9'))
  196. error1(mpl, str, s, fmt, f, "year missing or invalid")
  197. ;
  198. year = 0;
  199. for (j = 1; j <= 4; j++)
  200. { if (!('0' <= *s && *s <= '9')) break;
  201. year = 10 * year + ((*s++) - '0');
  202. }
  203. if (!(1 <= year && year <= 4000))
  204. error1(mpl, str, s, fmt, f, "year out of range");
  205. }
  206. else if (*f == 'z')
  207. { /* time zone offset in the form zhhmm */
  208. int z, hh, mm;
  209. if (zone != INT_MAX)
  210. error1(mpl, str, s, fmt, f, "time zone offset multipl"
  211. "y specified");
  212. while (*s == ' ') s++;
  213. if (*s == 'Z')
  214. { z = hh = mm = 0, s++;
  215. goto skip;
  216. }
  217. if (*s == '+')
  218. z = +1, s++;
  219. else if (*s == '-')
  220. z = -1, s++;
  221. else
  222. error1(mpl, str, s, fmt, f, "time zone offset sign mi"
  223. "ssing");
  224. hh = 0;
  225. for (j = 1; j <= 2; j++)
  226. { if (!('0' <= *s && *s <= '9'))
  227. err1: error1(mpl, str, s, fmt, f, "time zone offset valu"
  228. "e incomplete or invalid");
  229. hh = 10 * hh + ((*s++) - '0');
  230. }
  231. if (hh > 23)
  232. err2: error1(mpl, str, s, fmt, f, "time zone offset value o"
  233. "ut of range");
  234. if (*s == ':')
  235. { s++;
  236. if (!('0' <= *s && *s <= '9')) goto err1;
  237. }
  238. mm = 0;
  239. if (!('0' <= *s && *s <= '9')) goto skip;
  240. for (j = 1; j <= 2; j++)
  241. { if (!('0' <= *s && *s <= '9')) goto err1;
  242. mm = 10 * mm + ((*s++) - '0');
  243. }
  244. if (mm > 59) goto err2;
  245. skip: zone = z * (60 * hh + mm);
  246. }
  247. else if (*f == '%')
  248. { /* literal % character */
  249. goto test;
  250. }
  251. else
  252. error1(mpl, str, s, fmt, f, "invalid conversion specifie"
  253. "r");
  254. }
  255. else if (*f == ' ')
  256. ;
  257. else
  258. test: { /* check a matching character in the input string */
  259. if (*s != *f)
  260. error1(mpl, str, s, fmt, f, "character mismatch");
  261. s++;
  262. }
  263. }
  264. if (year < 0) year = 1970;
  265. if (month < 0) month = 1;
  266. if (day < 0) day = 1;
  267. if (hh < 0) hh = 0;
  268. if (mm < 0) mm = 0;
  269. if (ss < 0) ss = 0;
  270. if (zone == INT_MAX) zone = 0;
  271. j = jday(day, month, year);
  272. xassert(j >= 0);
  273. return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
  274. 60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
  275. }
  276. static void error2(MPL *mpl, const char *fmt, const char *f,
  277. const char *msg)
  278. { xprintf("Format string passed to time2str:\n");
  279. xprintf("%s\n", fmt);
  280. xprintf("%*s\n", (f - fmt) + 1, "^");
  281. mpl_error(mpl, "%s", msg);
  282. /* no return */
  283. }
  284. static int weekday(int j)
  285. { /* determine weekday number (1 = Mon, ..., 7 = Sun) */
  286. return (j + jday(1, 1, 1970)) % 7 + 1;
  287. }
  288. static int firstday(int year)
  289. { /* determine the first day of the first week for a specified year
  290. according to ISO 8601 */
  291. int j;
  292. /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
  293. in week 01; if 1 January is Friday, Saturday or Sunday, it is
  294. in week 52 or 53 of the previous year */
  295. j = jday(1, 1, year) - jday(1, 1, 1970);
  296. switch (weekday(j))
  297. { case 1: /* 1 Jan is Mon */ j += 0; break;
  298. case 2: /* 1 Jan is Tue */ j -= 1; break;
  299. case 3: /* 1 Jan is Wed */ j -= 2; break;
  300. case 4: /* 1 Jan is Thu */ j -= 3; break;
  301. case 5: /* 1 Jan is Fri */ j += 3; break;
  302. case 6: /* 1 Jan is Sat */ j += 2; break;
  303. case 7: /* 1 Jan is Sun */ j += 1; break;
  304. default: xassert(j != j);
  305. }
  306. /* the first day of the week must be Monday */
  307. xassert(weekday(j) == 1);
  308. return j;
  309. }
  310. void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
  311. { /* convert the calendar time to character string */
  312. int j, year, month, day, hh, mm, ss, len;
  313. double temp;
  314. const char *f;
  315. char buf[MAX_LENGTH+1];
  316. if (!(-62135596800.0 <= t && t <= 64092211199.0))
  317. mpl_error(mpl, "time2str(%.*g,...); argument out of range",
  318. DBL_DIG, t);
  319. t = floor(t + 0.5);
  320. temp = fabs(t) / 86400.0;
  321. j = (int)floor(temp);
  322. if (t < 0.0)
  323. { if (temp == floor(temp))
  324. j = - j;
  325. else
  326. j = - (j + 1);
  327. }
  328. xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
  329. ss = (int)(t - 86400.0 * (double)j);
  330. xassert(0 <= ss && ss < 86400);
  331. mm = ss / 60, ss %= 60;
  332. hh = mm / 60, mm %= 60;
  333. len = 0;
  334. for (f = fmt; *f != '\0'; f++)
  335. { if (*f == '%')
  336. { f++;
  337. if (*f == 'a')
  338. { /* the abbreviated weekday name */
  339. memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
  340. }
  341. else if (*f == 'A')
  342. { /* the full weekday name */
  343. strcpy(buf, week[weekday(j)-1]);
  344. }
  345. else if (*f == 'b' || *f == 'h')
  346. { /* the abbreviated month name */
  347. memcpy(buf, moon[month-1], 3), buf[3] = '\0';
  348. }
  349. else if (*f == 'B')
  350. { /* the full month name */
  351. strcpy(buf, moon[month-1]);
  352. }
  353. else if (*f == 'C')
  354. { /* the century of the year */
  355. sprintf(buf, "%02d", year / 100);
  356. }
  357. else if (*f == 'd')
  358. { /* the day of the month as a decimal number (01..31) */
  359. sprintf(buf, "%02d", day);
  360. }
  361. else if (*f == 'D')
  362. { /* the date using the format %m/%d/%y */
  363. sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
  364. }
  365. else if (*f == 'e')
  366. { /* the day of the month like with %d, but padded with
  367. blank (1..31) */
  368. sprintf(buf, "%2d", day);
  369. }
  370. else if (*f == 'F')
  371. { /* the date using the format %Y-%m-%d */
  372. sprintf(buf, "%04d-%02d-%02d", year, month, day);
  373. }
  374. else if (*f == 'g')
  375. { /* the year corresponding to the ISO week number, but
  376. without the century (range 00 through 99); this has
  377. the same format and value as %y, except that if the
  378. ISO week number (see %V) belongs to the previous or
  379. next year, that year is used instead */
  380. int iso;
  381. if (j < firstday(year))
  382. iso = year - 1;
  383. else if (j < firstday(year + 1))
  384. iso = year;
  385. else
  386. iso = year + 1;
  387. sprintf(buf, "%02d", iso % 100);
  388. }
  389. else if (*f == 'G')
  390. { /* the year corresponding to the ISO week number; this
  391. has the same format and value as %Y, excepth that if
  392. the ISO week number (see %V) belongs to the previous
  393. or next year, that year is used instead */
  394. int iso;
  395. if (j < firstday(year))
  396. iso = year - 1;
  397. else if (j < firstday(year + 1))
  398. iso = year;
  399. else
  400. iso = year + 1;
  401. sprintf(buf, "%04d", iso);
  402. }
  403. else if (*f == 'H')
  404. { /* the hour as a decimal number, using a 24-hour clock
  405. (00..23) */
  406. sprintf(buf, "%02d", hh);
  407. }
  408. else if (*f == 'I')
  409. { /* the hour as a decimal number, using a 12-hour clock
  410. (01..12) */
  411. sprintf(buf, "%02d",
  412. hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
  413. }
  414. else if (*f == 'j')
  415. { /* the day of the year as a decimal number (001..366) */
  416. sprintf(buf, "%03d",
  417. jday(day, month, year) - jday(1, 1, year) + 1);
  418. }
  419. else if (*f == 'k')
  420. { /* the hour as a decimal number, using a 24-hour clock
  421. like %H, but padded with blank (0..23) */
  422. sprintf(buf, "%2d", hh);
  423. }
  424. else if (*f == 'l')
  425. { /* the hour as a decimal number, using a 12-hour clock
  426. like %I, but padded with blank (1..12) */
  427. sprintf(buf, "%2d",
  428. hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
  429. }
  430. else if (*f == 'm')
  431. { /* the month as a decimal number (01..12) */
  432. sprintf(buf, "%02d", month);
  433. }
  434. else if (*f == 'M')
  435. { /* the minute as a decimal number (00..59) */
  436. sprintf(buf, "%02d", mm);
  437. }
  438. else if (*f == 'p')
  439. { /* either AM or PM, according to the given time value;
  440. noon is treated as PM and midnight as AM */
  441. strcpy(buf, hh <= 11 ? "AM" : "PM");
  442. }
  443. else if (*f == 'P')
  444. { /* either am or pm, according to the given time value;
  445. noon is treated as pm and midnight as am */
  446. strcpy(buf, hh <= 11 ? "am" : "pm");
  447. }
  448. else if (*f == 'r')
  449. { /* the calendar time using the format %I:%M:%S %p */
  450. sprintf(buf, "%02d:%02d:%02d %s",
  451. hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
  452. mm, ss, hh <= 11 ? "AM" : "PM");
  453. }
  454. else if (*f == 'R')
  455. { /* the hour and minute using the format %H:%M */
  456. sprintf(buf, "%02d:%02d", hh, mm);
  457. }
  458. else if (*f == 'S')
  459. { /* the second as a decimal number (00..59) */
  460. sprintf(buf, "%02d", ss);
  461. }
  462. else if (*f == 'T')
  463. { /* the time of day using the format %H:%M:%S */
  464. sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
  465. }
  466. else if (*f == 'u')
  467. { /* the day of the week as a decimal number (1..7),
  468. Monday being 1 */
  469. sprintf(buf, "%d", weekday(j));
  470. }
  471. else if (*f == 'U')
  472. { /* the week number of the current year as a decimal
  473. number (range 00 through 53), starting with the first
  474. Sunday as the first day of the first week; days
  475. preceding the first Sunday in the year are considered
  476. to be in week 00 */
  477. #if 1 /* 09/I-2009 */
  478. #undef sun
  479. /* causes compilation error in SunOS */
  480. #endif
  481. int sun;
  482. /* sun = the first Sunday of the year */
  483. sun = jday(1, 1, year) - jday(1, 1, 1970);
  484. sun += (7 - weekday(sun));
  485. sprintf(buf, "%02d", (j + 7 - sun) / 7);
  486. }
  487. else if (*f == 'V')
  488. { /* the ISO week number as a decimal number (range 01
  489. through 53); ISO weeks start with Monday and end with
  490. Sunday; week 01 of a year is the first week which has
  491. the majority of its days in that year; week 01 of
  492. a year can contain days from the previous year; the
  493. week before week 01 of a year is the last week (52 or
  494. 53) of the previous year even if it contains days
  495. from the new year */
  496. int iso;
  497. if (j < firstday(year))
  498. iso = j - firstday(year - 1);
  499. else if (j < firstday(year + 1))
  500. iso = j - firstday(year);
  501. else
  502. iso = j - firstday(year + 1);
  503. sprintf(buf, "%02d", iso / 7 + 1);
  504. }
  505. else if (*f == 'w')
  506. { /* the day of the week as a decimal number (0..6),
  507. Sunday being 0 */
  508. sprintf(buf, "%d", weekday(j) % 7);
  509. }
  510. else if (*f == 'W')
  511. { /* the week number of the current year as a decimal
  512. number (range 00 through 53), starting with the first
  513. Monday as the first day of the first week; days
  514. preceding the first Monday in the year are considered
  515. to be in week 00 */
  516. int mon;
  517. /* mon = the first Monday of the year */
  518. mon = jday(1, 1, year) - jday(1, 1, 1970);
  519. mon += (8 - weekday(mon)) % 7;
  520. sprintf(buf, "%02d", (j + 7 - mon) / 7);
  521. }
  522. else if (*f == 'y')
  523. { /* the year without a century as a decimal number
  524. (00..99) */
  525. sprintf(buf, "%02d", year % 100);
  526. }
  527. else if (*f == 'Y')
  528. { /* the year as a decimal number, using the Gregorian
  529. calendar */
  530. sprintf(buf, "%04d", year);
  531. }
  532. else if (*f == '%')
  533. { /* a literal % character */
  534. buf[0] = '%', buf[1] = '\0';
  535. }
  536. else
  537. error2(mpl, fmt, f, "invalid conversion specifier");
  538. }
  539. else
  540. buf[0] = *f, buf[1] = '\0';
  541. if (len + strlen(buf) > MAX_LENGTH)
  542. mpl_error(mpl, "time2str; output string length exceeds %d chara"
  543. "cters", MAX_LENGTH);
  544. memcpy(str+len, buf, strlen(buf));
  545. len += strlen(buf);
  546. }
  547. str[len] = '\0';
  548. return;
  549. }
  550. /* eof */