Created
August 27, 2010 00:14
-
-
Save deepfryed/552507 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ruby/ruby.h> | |
#include <time.h> | |
#include <unistd.h> | |
#define CONST_GET(scope, constant) rb_const_get(scope, rb_intern(constant)) | |
VALUE day_secs; | |
VALUE cDateTime; | |
VALUE fNewBang; | |
uint64_t epoch_ajd_n, epoch_ajd_d; | |
// calculates local offset at a given time, including any DST variations. | |
size_t client_tzoffset(struct tm *given) { | |
struct tm tm; | |
uint64_t utc, local; | |
memcpy(&tm, given, sizeof(tm)); | |
tm.tm_isdst = -1; | |
local = mktime(&tm); | |
gmtime_r(&local, &tm); | |
tm.tm_isdst = -1; | |
utc = mktime(&tm); | |
return local-utc; | |
} | |
VALUE rb_datetime_parse_iso8601(VALUE self, VALUE str) { | |
struct tm tm; | |
uint64_t epoch, adjust, offset, tzoffset; | |
const char* data = RSTRING_PTR(str); | |
double usec = 0; | |
char tzsign = 0; | |
int tzhour = 0, tzmin = 0; | |
memset(&tm, 0, sizeof(struct tm)); | |
if (strchr(data, '.')) { | |
sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%lf%c%02d:%02d", | |
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, | |
&usec, &tzsign, &tzhour, &tzmin); | |
} | |
else { | |
sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d", | |
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, | |
&tzsign, &tzhour, &tzmin); | |
} | |
tm.tm_year -= 1900; | |
tm.tm_mon -= 1; | |
tm.tm_isdst = -1; | |
if (tm.tm_mday > 0) { | |
epoch = mktime(&tm); | |
adjust = client_tzoffset(&tm); | |
offset = adjust; | |
if (tzsign == '+' || tzsign == '-') { | |
offset = tzsign == '+' ? | |
(time_t)tzhour * 3600 + (time_t)tzmin * 60 | |
: (time_t)tzhour * -3600 + (time_t)tzmin * -60; | |
} | |
VALUE ajd = rb_rational_new(ULONG2NUM(epoch_ajd_n + epoch + adjust - offset), day_secs); | |
return rb_funcall(cDateTime, fNewBang, 3, ajd, rb_rational_new(INT2FIX(offset), day_secs), INT2NUM(2299161)); | |
} | |
return Qnil; | |
} | |
void Init_parser(void) { | |
rb_require("date"); | |
// astronomical julian date for 1970-01-01 00:00:00 is 2440587.5 | |
// epoch_ajd = Rational(epoch_ajd_n, epoch_ajd_d) | |
epoch_ajd_d = 86400; | |
epoch_ajd_n = (2440587L*2+1) * 43200L; | |
day_secs = INT2FIX(86400); | |
fNewBang = rb_intern("new!"); | |
cDateTime = CONST_GET(rb_mKernel, "DateTime"); | |
rb_define_module_function(cDateTime, "parse_iso8601", RUBY_METHOD_FUNC(rb_datetime_parse_iso8601), 1); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment