[ci] Fix netbsd job to upgrade existing packages
[xapian.git] / xapian-applications / omega / datetime.cc
blob678cb4e4842a00c48002c440f541e6e48ffdf158
1 /** @file
2 * @brief Parse and format date/time strings
3 */
4 /* Copyright (c) 2013,2014,2015,2016,2019 Olly Betts
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
25 #include <config.h>
27 #include "datetime.h"
29 #include "timegm.h"
31 #include <algorithm>
32 #include <cstdlib>
34 using namespace std;
36 time_t
37 parse_datetime(const string & s)
39 struct tm t;
40 const char * p = s.c_str();
41 char * q;
42 if (s.find('T') != string::npos || s.find('-') != string::npos) {
43 // E.g. "2013-01-17T09:10:55Z"
44 t.tm_year = strtoul(p, &q, 10) - 1900;
45 p = q;
46 if (*p == '-') {
47 t.tm_mon = strtoul(p + 1, &q, 10) - 1;
48 p = q;
49 } else {
50 t.tm_mon = 0;
52 if (*p == '-') {
53 t.tm_mday = strtoul(p + 1, &q, 10);
54 p = q;
55 } else {
56 t.tm_mday = 1;
58 if (*p == 'T') {
59 t.tm_hour = strtoul(p + 1, &q, 10);
60 p = q;
61 if (*p == ':') {
62 t.tm_min = strtoul(p + 1, &q, 10);
63 p = q;
64 } else {
65 t.tm_min = 0;
67 if (*p == ':') {
68 t.tm_sec = strtoul(p + 1, &q, 10);
69 p = q;
70 } else {
71 t.tm_sec = 0;
73 } else {
74 t.tm_hour = t.tm_min = t.tm_sec = 0;
76 if (*p == 'Z') {
77 // FIXME: always assume UTC for now...
79 } else {
80 // As produced by LibreOffice HTML export.
81 // E.g.
82 // "20130117;09105500" == 2013-01-17T09:10:55
83 // "20070903;200000000000" == 2007-09-03T00:02:00
84 // "20070831;5100000000000" == 2007-08-31T00:51:00
85 unsigned long v = strtoul(p, &q, 10);
86 if (v == 0) {
87 // LibreOffice sometimes exports "0;0". A date of "0" is
88 // clearly invalid.
89 return time_t(-1);
91 p = q;
92 t.tm_mday = v % 100;
93 v /= 100;
94 t.tm_mon = v % 100 - 1;
95 t.tm_year = v / 100 - 1900;
96 if (*p == ';') {
97 ++p;
98 v = strtoul(p, &q, 10);
99 v /= (q - p > 10) ? 1000000000 : 100;
100 t.tm_sec = v % 100;
101 v /= 100;
102 t.tm_min = v % 100;
103 t.tm_hour = v / 100;
104 } else {
105 t.tm_hour = t.tm_min = t.tm_sec = 0;
108 t.tm_isdst = -1;
110 return timegm(&t);
113 // Write exactly w chars to buffer p representing integer v.
115 // The result is left padded with zeros if v < pow(10, w - 1).
117 // If v >= pow(10, w), then the output will show v % pow(10, w) (i.e. the
118 // most significant digits are lost).
119 static void
120 format_int_fixed_width(char* p, int v, int w)
122 while (--w >= 0) {
123 p[w] = '0' + (v % 10);
124 v /= 10;
128 string
129 date_to_string(int year, int month, int day)
131 year = std::clamp(year, 0, 9999);
132 month = std::clamp(month, 1, 12);
133 day = std::clamp(day, 1, 31);
134 char buf[8];
135 format_int_fixed_width(buf, year, 4);
136 format_int_fixed_width(buf + 4, month, 2);
137 format_int_fixed_width(buf + 6, day, 2);
138 return string(buf, 8);