|
1 | 1 | #include <string.h> |
2 | | -#include <time.h> |
3 | 2 | #if defined(_MSC_VER) |
4 | 3 |
|
5 | | -#define timegm _mkgmtime |
6 | 4 | #define strncasecmp _strnicmp |
7 | 5 | #define strcasecmp _stricmp |
8 | 6 |
|
@@ -193,20 +191,15 @@ void duckdb_read_stat_init(duckdb_init_info info) |
193 | 191 | duckdb_init_set_init_data(info, data, duckdb_free); |
194 | 192 | } |
195 | 193 |
|
196 | | -const struct tm sas_epoch = {.tm_year = 60, .tm_mon = 0, .tm_mday = 1, .tm_isdst = 0}; |
197 | | -const struct tm spss_epoch = {.tm_year = -318, .tm_mon = 9, .tm_mday = 14, .tm_isdst = 0}; |
198 | | -const struct tm stata_epoch = {.tm_year = 60, .tm_mon = 0, .tm_mday = 1, .tm_isdst = 0}; |
| 194 | +const int days_between_unix_epoch_and_sas_epoch = -3653; |
| 195 | +const int days_between_unix_epoch_and_spss_epoch = -141428; |
| 196 | +const int days_between_unix_epoch_and_stata_epoch = -3653; |
199 | 197 |
|
200 | | -duckdb_date duckdb_read_stat_convert_date(int days, int seconds, struct tm epoch) |
| 198 | +duckdb_date duckdb_read_stat_convert_date(int days, int seconds, int days_between_epochs) |
201 | 199 | { |
202 | | - struct tm datetime_struct = {.tm_year = epoch.tm_year, .tm_mon = epoch.tm_mon, .tm_mday = epoch.tm_mday + days, .tm_sec = epoch.tm_sec + seconds, .tm_isdst = 0}; |
203 | | - time_t datetime = timegm(&datetime_struct); |
204 | | - struct tm *datetime_struct_epoch = gmtime(&datetime); |
205 | | - duckdb_date_struct date_struct; |
206 | | - date_struct.year = datetime_struct_epoch->tm_year + 1900; |
207 | | - date_struct.month = datetime_struct_epoch->tm_mon + 1; |
208 | | - date_struct.day = datetime_struct_epoch->tm_mday; |
209 | | - return duckdb_to_date(date_struct); |
| 200 | + duckdb_date date; |
| 201 | + date.days = days_between_epochs + days + (seconds / (3600 * 24)); |
| 202 | + return date; |
210 | 203 | } |
211 | 204 |
|
212 | 205 | double duckdb_read_stat_modulo(double dividend, double divisor) |
@@ -234,58 +227,47 @@ duckdb_date duckdb_read_stat_to_date(double timestamp, duckdb_read_stat_file_for |
234 | 227 | switch (file_format) |
235 | 228 | { |
236 | 229 | case DUCKDB_READ_STAT_FILE_FORMAT_SAS: |
237 | | - return duckdb_read_stat_convert_date(days, seconds, sas_epoch); |
| 230 | + return duckdb_read_stat_convert_date(days, seconds, days_between_unix_epoch_and_sas_epoch); |
238 | 231 | case DUCKDB_READ_STAT_FILE_FORMAT_SPSS: |
239 | | - return duckdb_read_stat_convert_date(days, seconds, spss_epoch); |
| 232 | + return duckdb_read_stat_convert_date(days, seconds, days_between_unix_epoch_and_spss_epoch); |
240 | 233 | case DUCKDB_READ_STAT_FILE_FORMAT_STATA: |
241 | | - return duckdb_read_stat_convert_date(days, seconds, stata_epoch); |
| 234 | + return duckdb_read_stat_convert_date(days, seconds, days_between_unix_epoch_and_stata_epoch); |
242 | 235 | } |
243 | 236 | } |
244 | 237 |
|
245 | | -duckdb_timestamp duckdb_read_stat_convert_timestamp(int days, int seconds, struct tm epoch) |
| 238 | +duckdb_timestamp duckdb_read_stat_convert_timestamp(int days, int seconds, int days_between_epochs) |
246 | 239 | { |
247 | | - struct tm datetime_struct = {.tm_year = epoch.tm_year, .tm_mon = epoch.tm_mon, .tm_mday = epoch.tm_mday + days, .tm_sec = epoch.tm_sec + seconds, .tm_isdst = 0}; |
248 | | - time_t datetime = timegm(&datetime_struct); |
249 | | - struct tm *datetime_struct_epoch = gmtime(&datetime); |
250 | | - duckdb_timestamp_struct timestamp_struct; |
251 | | - |
252 | | - timestamp_struct.date.year = datetime_struct_epoch->tm_year + 1900; |
253 | | - timestamp_struct.date.month = datetime_struct_epoch->tm_mon + 1; |
254 | | - timestamp_struct.date.day = datetime_struct_epoch->tm_mday; |
255 | | - timestamp_struct.time.hour = datetime_struct_epoch->tm_hour; |
256 | | - timestamp_struct.time.min = datetime_struct_epoch->tm_min; |
257 | | - timestamp_struct.time.sec = datetime_struct_epoch->tm_sec; |
258 | | - timestamp_struct.time.micros = 0; |
259 | | - |
260 | | - return duckdb_to_timestamp(timestamp_struct); |
| 240 | + duckdb_timestamp timestamp; |
| 241 | + timestamp.micros = ((((int64_t)days_between_epochs + (int64_t)days) * 24L * 3600L) + (int64_t)seconds) * 1000000L; |
| 242 | + return timestamp; |
261 | 243 | } |
262 | 244 |
|
263 | 245 | duckdb_timestamp duckdb_read_stat_to_timestamp(double timestamp, duckdb_read_stat_file_format file_format) |
264 | 246 | { |
265 | 247 | int days = 0; |
266 | | - double msecs = 0; |
| 248 | + double milliseconds = 0; |
267 | 249 | int seconds = 0; |
268 | | - int usecs = 0; |
| 250 | + |
269 | 251 | if (file_format == DUCKDB_READ_STAT_FILE_FORMAT_STATA) |
270 | 252 | { |
271 | 253 | days = (int)(floor(timestamp / 86400000.0)); |
272 | | - msecs = duckdb_read_stat_modulo(timestamp, 86400000.0); |
273 | | - seconds = (int)(msecs / 1000.0); |
274 | | - usecs = (int)duckdb_read_stat_modulo(msecs, 1000.0); |
| 254 | + milliseconds = duckdb_read_stat_modulo(timestamp, 86400000.0); |
| 255 | + seconds = (int)(milliseconds / 1000.0); |
275 | 256 | } |
276 | 257 | else |
277 | 258 | { |
278 | 259 | days = (int)(floor(timestamp / 86400.0)); |
279 | 260 | seconds = (int)duckdb_read_stat_modulo(timestamp, 86400.0); |
280 | 261 | } |
| 262 | + |
281 | 263 | switch (file_format) |
282 | 264 | { |
283 | 265 | case DUCKDB_READ_STAT_FILE_FORMAT_SAS: |
284 | | - return duckdb_read_stat_convert_timestamp(days, seconds, sas_epoch); |
| 266 | + return duckdb_read_stat_convert_timestamp(days, seconds, days_between_unix_epoch_and_sas_epoch); |
285 | 267 | case DUCKDB_READ_STAT_FILE_FORMAT_SPSS: |
286 | | - return duckdb_read_stat_convert_timestamp(days, seconds, spss_epoch); |
| 268 | + return duckdb_read_stat_convert_timestamp(days, seconds, days_between_unix_epoch_and_spss_epoch); |
287 | 269 | case DUCKDB_READ_STAT_FILE_FORMAT_STATA: |
288 | | - return duckdb_read_stat_convert_timestamp(days, seconds, stata_epoch); |
| 270 | + return duckdb_read_stat_convert_timestamp(days, seconds, days_between_unix_epoch_and_stata_epoch); |
289 | 271 | } |
290 | 272 | } |
291 | 273 |
|
|
0 commit comments