static VALUE
time_mdump(VALUE time)
{
struct time_object *tobj;
struct tm *tm;
unsigned long p, s;
char buf[8];
time_t t;
int nsec;
int i;
VALUE str;
IF_HAVE_GMTIME_R(struct tm result);
GetTimeval(time, tobj);
t = tobj->ts.tv_sec;
tm = GMTIME(&t, result);
if ((tm->tm_year & 0xffff) != tm->tm_year)
rb_raise(rb_eArgError, "year too big to marshal: %ld", (long)tm->tm_year);
p = 0x1UL << 31 | /* 1 */
tobj->gmt << 30 | /* 1 */
tm->tm_year << 14 | /* 16 */
tm->tm_mon << 10 | /* 4 */
tm->tm_mday << 5 | /* 5 */
tm->tm_hour; /* 5 */
s = tm->tm_min << 26 | /* 6 */
tm->tm_sec << 20 | /* 6 */
tobj->ts.tv_nsec / 1000; /* 20 */
nsec = tobj->ts.tv_nsec % 1000;
for (i=0; i<4; i++) {
buf[i] = p & 0xff;
p = RSHIFT(p, 8);
}
for (i=4; i<8; i++) {
buf[i] = s & 0xff;
s = RSHIFT(s, 8);
}
str = rb_str_new(buf, 8);
rb_copy_generic_ivar(str, time);
if (nsec) {
/*
* submicro is formatted in fixed-point packed BCD (without sign).
* It represent digits under microsecond.
* For nanosecond resolution, 3 digits (2 bytes) are used.
* However it can be longer.
* Extra digits are ignored for loading.
*/
unsigned char buf[2];
int len = sizeof(buf);
buf[1] = (nsec % 10) << 4;
nsec /= 10;
buf[0] = nsec % 10;
nsec /= 10;
buf[0] |= (nsec % 10) << 4;
if (buf[1] == 0)
len = 1;
rb_ivar_set(str, id_submicro, rb_str_new((char *)buf, len));
}
return str;
}