openMSX
Date.cc
Go to the documentation of this file.
1 #include "Date.hh"
2 #include <sstream>
3 #include <iomanip>
4 
5 namespace openmsx {
6 
7 namespace Date {
8 
9 const char* const days[7] = {
10  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
11 };
12 
13 const char* const months[12] = {
14  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
15  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
16 };
17 
18 template<bool FIRST, unsigned MUL, typename T>
19 static inline bool parseDigit(unsigned c, T& t)
20 {
21  c -= '0';
22  if (c > 9) return false;
23  if (FIRST) {
24  t = c * MUL;
25  } else {
26  t += c * MUL;
27  }
28  return true;
29 }
30 
31 time_t fromString(const char* p)
32 {
33  struct tm tm;
34 
35  // skip day
36  p += 3;
37 
38  // space
39  if (*p++ != ' ') return time_t(-1);
40 
41  // Parse month
42  switch (*p++) {
43  case 'J': // Jan Jun Jul
44  switch (*p++) {
45  case 'a': // Jan
46  if (*p++ != 'n') return time_t(-1);
47  tm.tm_mon = 0; break;
48  case 'u': // Jun Jul
49  switch (*p++) {
50  case 'n': tm.tm_mon = 5; break;
51  case 'l': tm.tm_mon = 6; break;
52  default: return time_t(-1);
53  }
54  break;
55  default: return time_t(-1);
56  }
57  break;
58  case 'F': // Feb
59  if (*p++ != 'e') return time_t(-1);
60  if (*p++ != 'b') return time_t(-1);
61  tm.tm_mon = 1;
62  break;
63  case 'M': // Mar May
64  if (*p++ != 'a') return time_t(-1);
65  switch (*p++) {
66  case 'r': tm.tm_mon = 2; break;
67  case 'y': tm.tm_mon = 4; break;
68  default: return time_t(-1);
69  }
70  break;
71  case 'A': // Apr Aug
72  switch (*p++) {
73  case 'p': // Apr
74  if (*p++ != 'r') return time_t(-1);
75  tm.tm_mon = 3; break;
76  case 'u': // Aug
77  if (*p++ != 'g') return time_t(-1);
78  tm.tm_mon = 7; break;
79  default: return time_t(-1);
80  }
81  break;
82  case 'S': // Sep
83  if (*p++ != 'e') return time_t(-1);
84  if (*p++ != 'p') return time_t(-1);
85  tm.tm_mon = 8;
86  break;
87  case 'O': // Oct
88  if (*p++ != 'c') return time_t(-1);
89  if (*p++ != 't') return time_t(-1);
90  tm.tm_mon = 9;
91  break;
92  case 'N': // Nov
93  if (*p++ != 'o') return time_t(-1);
94  if (*p++ != 'v') return time_t(-1);
95  tm.tm_mon = 10;
96  break;
97  case 'D': // Dec
98  if (*p++ != 'e') return time_t(-1);
99  if (*p++ != 'c') return time_t(-1);
100  tm.tm_mon = 11;
101  break;
102  default: return time_t(-1);
103  }
104 
105  // space
106  if (*p++ != ' ') return time_t(-1);
107 
108  // parse mday
109  if (!parseDigit<true, 10>(*p++, tm.tm_mday)) return time_t(-1);
110  if (!parseDigit<false, 1>(*p++, tm.tm_mday)) return time_t(-1);
111  if ((tm.tm_mday < 1) || (31 < tm.tm_mday) ) return time_t(-1);
112 
113  // space
114  if (*p++ != ' ') return time_t(-1);
115 
116  // parse hour
117  if (!parseDigit<true, 10>(*p++, tm.tm_hour)) return time_t(-1);
118  if (!parseDigit<false, 1>(*p++, tm.tm_hour)) return time_t(-1);
119  if ((tm.tm_hour < 0) || (23 < tm.tm_hour)) return time_t(-1);
120 
121  // colon
122  if (*p++ != ':') return time_t(-1);
123 
124  // parse minute
125  if (!parseDigit<true, 10>(*p++, tm.tm_min)) return time_t(-1);
126  if (!parseDigit<false, 1>(*p++, tm.tm_min)) return time_t(-1);
127  if ((tm.tm_min < 0) || (59 < tm.tm_min)) return time_t(-1);
128 
129  // colon
130  if (*p++ != ':') return time_t(-1);
131 
132  // parse second
133  if (!parseDigit<true, 10>(*p++, tm.tm_sec)) return time_t(-1);
134  if (!parseDigit<false, 1>(*p++, tm.tm_sec)) return time_t(-1);
135  if ((tm.tm_sec < 0) || (59 < tm.tm_sec)) return time_t(-1);
136 
137  // space
138  if (*p++ != ' ') return time_t(-1);
139 
140  // parse year
141  if (!parseDigit<true, 1000>(*p++, tm.tm_year)) return time_t(-1);
142  if (!parseDigit<false, 100>(*p++, tm.tm_year)) return time_t(-1);
143  if (!parseDigit<false, 10>(*p++, tm.tm_year)) return time_t(-1);
144  if (!parseDigit<false, 1>(*p++, tm.tm_year)) return time_t(-1);
145  tm.tm_year -= 1900;
146  if (tm.tm_year < 0) return time_t(-1);
147 
148  tm.tm_isdst = -1;
149  return mktime(&tm);
150 }
151 
152 std::string toString(time_t time)
153 {
154  if (time < 0) time = 0;
155  struct tm* tm;
156  tm = localtime(&time);
157  std::ostringstream sstr;
158  sstr << std::setfill('0')
159  << days [tm->tm_wday] << ' '
160  << months[tm->tm_mon] << ' '
161  << std::setw(2) << tm->tm_mday << ' '
162  << std::setw(2) << tm->tm_hour << ':'
163  << std::setw(2) << tm->tm_min << ':'
164  << std::setw(2) << tm->tm_sec << ' '
165  << std::setw(4) << (tm->tm_year + 1900);
166  return sstr.str();
167 }
168 
169 } // namespace Date
170 
171 } // namespace openmsx
const char *const days[7]
Definition: Date.cc:9
const char *const months[12]
Definition: Date.cc:13
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:7
std::string toString(time_t time)
Definition: Date.cc:152
time_t fromString(const char *p)
Definition: Date.cc:31