By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,725 Members | 1,040 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,725 IT Pros & Developers. It's quick & easy.

Convert Java <long> to C <?>

P: n/a
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().

Mar 31 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
On 2006-03-31, Simple Simon <ss****@domain.invalid> wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

Java values are, IIRC, stored as twos-complement big-endian.

unsigned long long x = 0;
signed long long y;
/* you may want to put this part in a loop,
or use an extension like be64dec() */
x |= buffer[0]
x <<= 8; x |= buffer[1];
x <<= 8; x |= buffer[2];
x <<= 8; x |= buffer[3];
x <<= 8; x |= buffer[4];
x <<= 8; x |= buffer[5];
x <<= 8; x |= buffer[6];
x <<= 8; x |= buffer[7];
/* sign-extend if long long is wider than 64 bits */
#if ULLONG_MAX > 0xFFFFFFFFFFFFFFFFull
if(x & 0x8000000000000000ull) x |= ~0xFFFFFFFFFFFFFFFFull;
#endif
y = x;
/* at this point, y = 1143151069156 */
t.tv_sec = y/1000;
t.tv_usec = (y%1000) * 1000;
/* if you even care.
I'd just store y/1000 in a time_t */
I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().

Mar 31 '06 #2

P: n/a
Me
Simple Simon wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().


Wha? timeval isn't in standard C and ctime takes a time_t *. All C says
is that time_t is an arithmetic type, it doesn't say the start time or
what unit of measurement it uses. Many C implementations use the number
of seconds since UNIX's epoch so you can get by with:

unsigned long long val = 0;
for (size_t i = 0; i < 8; ++i)
val = val<<8 | buffer[i];
time_t time = val/1000;
const char *tstr = ctime(&time);

But odds are, if you have access to sockets on your implementation, the
above should work.

Mar 31 '06 #3

P: n/a
On 2006-03-31, Me <an*****************@yahoo.com> wrote:
Simple Simon wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().
Wha? timeval isn't in standard C and ctime takes a time_t *. All C says
is that time_t is an arithmetic type, it doesn't say the start time or
what unit of measurement it uses. Many C implementations use the number
of seconds since UNIX's epoch so you can get by with:

unsigned long long val = 0;
for (size_t i = 0; i < 8; ++i)
val = val<<8 | buffer[i];
time_t time = val/1000;


You're risking an overflow there, and certainly incorrect results if the
value is negative. Sign-extend, convert to signed long long, THEN divide
by 1000 to put in the time_t. Still can overflow, but then it'll only do
it on values that deserve it.

Suppose i have the unsigned long long value 0xFFFFFFFFFFFF0000, that is,
what is meant to be the signed value -65536. that divided by 1000 is
0x4189374BC6A7AE, which is a huge positive value. Converting it to
a 32-bit signed value will result in 0x4BC6A7AE, which is the time Thu
Apr 15 01:44:14 2010, instead of the time Wed Dec 31 18:58:55 1969 [both
times converted using Eastern time.]

And portable code to convert seconds-since-1970 to a time_t is certainly
_possible_. You can probably even get mktime to do most of the work, but
you'll have to know [or cleverly determine] what timezone you're working
in.

const char *tstr = ctime(&time);

But odds are, if you have access to sockets on your implementation, the
above should work.

Mar 31 '06 #4

P: n/a
an*****************@yahoo.com wrote...
Simple Simon wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().
Wha? timeval isn't in standard C and ctime takes a time_t *.


OK: "...if stuffed into a time_t var whose address is used as an
argument to ctime()."
All C says
is that time_t is an arithmetic type, it doesn't say the start time or
what unit of measurement it uses. Many C implementations use the number
of seconds since UNIX's epoch so you can get by with:

unsigned long long val = 0;
Didn't know about 'long long' though. Thanks very much.
for (size_t i = 0; i < 8; ++i)
val = val<<8 | buffer[i];
time_t time = val/1000;
const char *tstr = ctime(&time);

But odds are, if you have access to sockets on your implementation, the
above should work.

Mar 31 '06 #5

P: n/a
In article <sl***********************@random.yi.org>
Jordan Abel <ra*******@gmail.com> wrote:
Java values are, IIRC, stored as twos-complement big-endian.

unsigned long long x = 0;
signed long long y; .../* sign-extend if long long is wider than 64 bits */
#if ULLONG_MAX > 0xFFFFFFFFFFFFFFFFull
if(x & 0x8000000000000000ull) x |= ~0xFFFFFFFFFFFFFFFFull;
#endif
y = x;


This only works if the C implementation happens to use two's
complement as well (of course, most do).

There is a general formulation that "does the right thing" no matter
what, provided the value is representable at all. Suppose "x" is
some unsigned integral type (preferably unsigned int, in this case)
holding a 7-bit two's complement value, so that it represents values
in [-64..+63]. To convert it to a signed "int":

unsigned int x;
int result;
... set x to a 7-bit value ...
result = (int)(x ^ 64U) - 64;

The trick is that 64 (or 0x40) is the "sign bit" in the two's
complement representation. If it is off, the number is positive,
so we turn it on, giving a value in the range [64..127]. If that
bit is on, however, we turn it off, giving a value in the range
[0..63]. Then we convert that value to (signed) int and subtract
off the +64 bias.

The only problem with this general technique is that it uses values
in the range [0..2-sup-k] as intermediates. If ULLONG_MAX is
2-sup-64-minus-1 (18446744073709551615) -- e.g., if long long is 64
bits as is typical -- and LLONG_MAX is half that (as is typical),
we would need a type wider than 64 bits to hold the intermediate number.

But of course, you already have the conversion code using a "#if",
so we can handle the problem by doing the arithmetic mod 2-sup-64
if ULLONG_MAX is 0xffffffffffffffffULL:

#if ULLONG_MAX == 0xffffffffffffffffULL
/* we do not have a sufficiently wide type to use the
100% guaranteed portable method, so we'll just cross
fingers here */
y = x;
#else
/* ULLONG_MAX is more than 64 bits, so use the portable method */
y = ((long long)(x ^ 0x8000000000000000ULL)) - 0x8000000000000000LL;
#endif

It might actually be better to test LLONG_MAX rather than
ULLONG_MAX, since the portable trick depends on LLONG_MAX
being at least 18446744073709551615.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Mar 31 '06 #6

P: n/a
On 2006-03-31, Chris Torek <no****@torek.net> wrote:
In article <sl***********************@random.yi.org>
Jordan Abel <ra*******@gmail.com> wrote:
Java values are, IIRC, stored as twos-complement big-endian.

unsigned long long x = 0;
signed long long y; ...
/* sign-extend if long long is wider than 64 bits */
#if ULLONG_MAX > 0xFFFFFFFFFFFFFFFFull
if(x & 0x8000000000000000ull) x |= ~0xFFFFFFFFFFFFFFFFull;
#endif
y = x;


This only works if the C implementation happens to use two's
complement as well (of course, most do).


I thought conversion of unsigned to signed always converted to
[unsigned value]-(UINT_MAX+1) where that result would be in the range of
the signed type and the original value would not.
But of course, you already have the conversion code using a "#if",
so we can handle the problem by doing the arithmetic mod 2-sup-64
if ULLONG_MAX is 0xffffffffffffffffULL:


that #if was to sign-extend if long long is wider than 64 bits.
Mar 31 '06 #7

P: n/a
Apologies for top-posting, but...

Thank you Jordan!

ra*******@gmail.com wrote...
On 2006-03-31, Me <an*****************@yahoo.com> wrote:
Simple Simon wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().


Wha? timeval isn't in standard C and ctime takes a time_t *. All C says
is that time_t is an arithmetic type, it doesn't say the start time or
what unit of measurement it uses. Many C implementations use the number
of seconds since UNIX's epoch so you can get by with:

unsigned long long val = 0;
for (size_t i = 0; i < 8; ++i)
val = val<<8 | buffer[i];
time_t time = val/1000;


You're risking an overflow there, and certainly incorrect results if the
value is negative. Sign-extend, convert to signed long long, THEN divide
by 1000 to put in the time_t. Still can overflow, but then it'll only do
it on values that deserve it.

Suppose i have the unsigned long long value 0xFFFFFFFFFFFF0000, that is,
what is meant to be the signed value -65536. that divided by 1000 is
0x4189374BC6A7AE, which is a huge positive value. Converting it to
a 32-bit signed value will result in 0x4BC6A7AE, which is the time Thu
Apr 15 01:44:14 2010, instead of the time Wed Dec 31 18:58:55 1969 [both
times converted using Eastern time.]

And portable code to convert seconds-since-1970 to a time_t is certainly
_possible_. You can probably even get mktime to do most of the work, but
you'll have to know [or cleverly determine] what timezone you're working
in.

const char *tstr = ctime(&time);

But odds are, if you have access to sockets on your implementation, the
above should work.

Mar 31 '06 #8

P: n/a
Simple Simon wrote:
Java longs are 8 bytes. I have a Java long that is coming in from
the network, and that represents milliseconds since Epoch (Jan 1 1970
00:00:00). I'm having trouble understanding how to get it into a
struct timeval object.

I get the ByteBuffer as an array of const unsigned char, 'buffer'.

Here's an example: 00 00 01 0A 29 1D 07 E4

This value maps somehow to Thu Mar 23 16:57:49 2006 and some
millisecs which I haven't sussed out yet.

I'm beating my simple brains out trying to figure out how to get that
into a struct timeval t so that t.tv_sec would spit out
You no doubt mean a struct tm t, with t.tm_sec, since there ain't no
such thing as a struct timeval in standard C (until you define it).
You really don't want to assign your value (divided by 1000) to
t.tm_sec, which need not be able to hold it and for which such value may
be meaningless.

Thu Mar 23 16:57:49 2006

if used as an argument to ctime().


You might try an experiment like the following.
You can see that I am 5 hours off. That suggests that I have not
resolved a time zone problem. Your value is very likely a UTC time for
which gmtime rather than localtime is represented. There are several
unresolved issues in this code which I will leave as an exercise.

#include <stdio.h>
#include <time.h>
#include <string.h>

int main(void)
{
struct tm now = {
.tm_year = 106,
.tm_mon = 2,
.tm_mday = 23,
.tm_hour = 16,
.tm_min = 57,
.tm_sec = 49,
.tm_isdst = -1
};
time_t t;
unsigned char buf[sizeof t];
size_t ndx;
unsigned long long tx;
unsigned char bufx[sizeof tx];
t = mktime(&now);
memcpy(buf, &t, sizeof t);
printf("asctime(&now) = %s", asctime(&now));
printf("ctime(&t) = %s", ctime(&t));
for (ndx = 0; ndx < sizeof t; ndx++)
printf("buf[%lu] = %#04hx\n", (unsigned long) ndx, buf[ndx]);
putchar('\n');
tx = 1000ull * t;
memcpy(bufx, &tx, sizeof tx);
for (ndx = 0; ndx < sizeof tx; ndx++)
printf("buf[%lu] = %#04hx\n", (unsigned long) ndx, bufx[ndx]);

printf("\n\nHaving run this experiment before, I will place\n"
"the OP's values into the array,\n"
"move that to the unsigned long long,\n"
"divide by 1000, assign that value to a time_t,\n"
"and see what happens.\n");
memcpy(bufx, &(unsigned char[sizeof bufx]) {
0xe4, 0x07, 0x1d, 0x29, 0x0a, 0x01, 0, 0}
, sizeof bufx);
printf("The buffer as I have assigned it:\n");
for (ndx = 0; ndx < sizeof tx; ndx++)
printf("buf[%lu] = %#04hx\n", (unsigned long) ndx, bufx[ndx]);
memcpy(&tx, bufx, sizeof tx);
printf("corresponding to %llu (%#018llx)\n", tx, tx);
t = tx / 1000;
printf("The time_t now holds %lu\n", (unsigned long) t);
printf("ctime(&t) = %s", ctime(&t));
return 0;
}

asctime(&now) = Thu Mar 23 16:57:49 2006
ctime(&t) = Thu Mar 23 16:57:49 2006
buf[0] = 0x8d
buf[1] = 0xd3
buf[2] = 0x22
buf[3] = 0x44

buf[0] = 0xc8
buf[1] = 0x5e
buf[2] = 0x0a
buf[3] = 0x28
buf[4] = 0x0a
buf[5] = 0x01
buf[6] = 0000
buf[7] = 0000
Having run this experiment before, I will place
the OP's values into the array,
move that to the unsigned long long,
divide by 1000, assign that value to a time_t,
and see what happens.
The buffer as I have assigned it:
buf[0] = 0xe4
buf[1] = 0x07
buf[2] = 0x1d
buf[3] = 0x29
buf[4] = 0x0a
buf[5] = 0x01
buf[6] = 0000
buf[7] = 0000
corresponding to 1143151069156 (0x0000010a291d07e4)
The time_t now holds 1143151069
ctime(&t) = Thu Mar 23 21:57:49 2006

Mar 31 '06 #9

P: n/a
>On 2006-03-31, Chris Torek <no****@torek.net> wrote:
This [assignment that depends on 2's complement] only works if
the C implementation happens to use two's complement as well
(of course, most do).

In article <sl***********************@random.yi.org>
Jordan Abel <ra*******@gmail.com> wrote:I thought conversion of unsigned to signed always converted to
[unsigned value]-(UINT_MAX+1) where that result would be in the range of
the signed type and the original value would not.


No: from a C99 draft:

6.2.1.2 Signed and unsigned integers

When a value with integer type is converted to another
integer type, if the value can be represented by the new
type, it is unchanged.

(this covers values between 0 and LLONG_MAX, in this case)

[#2] Otherwise, if the new type is unsigned, ...

(this does not apply as the new type was signed long long)

[#3] Otherwise, the new type is signed and the value cannot
be represented in it; the result is implementation-defined.

This is the case I noted.

It is probably not worth attempting to handle this case, since
the places where it would be a problem are on machines like the
Univac that use ones' complement and would have trouble with
0x8000000000000000LL (except that the Univac would do this in
72 bits, so that LLONG_MIN, LLONG_MAX, and ULLONG_MAX are based
on 71 and 72 bit values, not 63 and 64; here my "guaranteed
100% portable" trick -- the xor and subtract up-thread -- would
have taken care of the problem).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Apr 23 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.