Valeriy K.
Valeriy K.

Reputation: 2904

Can't get local and utc Instant

I need to get local time and utc time in seconds. I read some posts in StackOverflow and found some solution, which is correct as mentioned:

    Instant time = Instant.now();
    OffsetDateTime utc = time.atOffset(ZoneOffset.UTC);
    int utcTime = (int) utc.toEpochSecond();
    int localTime = (int) time.getEpochSecond();
    System.out.println("utc " + utcTime + " local " + localTime);

But result is not what I expected. It is utc time. The output:

utc   1593762925
local 1593762925

After debugging I found that Instant.now() is already utc. I can't find how to get time in current time zone, i.e. my system zone.

I found some solution in API but got error:

OffsetDateTime utc = time.atOffset(ZoneOffset.of(ZoneOffset.systemDefault().getId()));

Exception in thread "main" java.time.DateTimeException: Invalid ID for ZoneOffset, invalid format: Europe/Astrakhan at java.base/java.time.ZoneOffset.of(ZoneOffset.java:241)

UPD: My question is How to get current time in seconds in local time zone and in UTC? I.e. the number of seconds since 1970-01-01T00:00:00 GMT+4 and 1970-01-01T00:00:00 GMT+0

UPD2: I have some device that needs response with utc time in seconds from 1970 and sender local time in seconds. Why? I don't know. It is black box for me.

Upvotes: 6

Views: 1696

Answers (3)

Anonymous
Anonymous

Reputation: 86281

TL;DR: Your expectations are wrong. Your results are correct.

The results you are getting is the count of seconds since the Unix/Java epoch. This is also known as a Unix timestamp. The epoch is one point in time and is independent of time zone. It’s the same point in time in all time zones. Therefore the count of seconds is the same in all time zones too.

The epoch is 1970-01-01T00:00:00 GMT+0. In some time zones (yours?) this point in time would be given as 1970-01-01T04:00:00 GMT+4. Please note the time of day is 4 AM, not 00:00.

In case someone else was wrong

UPD2: I have some device that needs response with utc time in seconds from 1970 and sender local time in seconds. Why? I don't know. It is black box for me.

It’s a possibility, of course, that the designers of that device misunderstood and probably inadvertently invented their own way of counting seconds. It doesn’t sound very likely, though, so I would at least double-check and triple-check this piece of information. If it turns out to be correct, I would do something like:

    LocalDateTime misunderstoodEpoch = LocalDate.EPOCH.atStartOfDay();
    
    ZoneId zone = ZoneId.of("Europe/Astrakhan");
    long secondsLong = ChronoUnit.SECONDS
            .between(misunderstoodEpoch.atZone(zone), ZonedDateTime.now(zone));
    int seconds = Math.toIntExact(secondsLong);
    
    System.out.println(seconds);

Output when running just now:

1593881344

Also if your device insists on using an int for your seconds, at least use Math.toIntExact() for the conversion. This will throw an exception in case of int overflow so that in January 2038 (just 17 years 6 months from now) you and your users will be made aware of the fact that your device is no longer working.

Upvotes: 0

Valeriy K.
Valeriy K.

Reputation: 2904

Found solution here:

    TimeZone tz = TimeZone.getDefault();
    Instant instant = Instant.now();
    int offsetFromUtc = tz.getOffset(instant.getEpochSecond()) / 1000;
    

Or as wrote @deHaar:

    int offsetFromUtc = Instant.now().atZone(ZoneOffset.systemDefault()).getOffset().getTotalSeconds();

It gives 14400 s that is correct for my timezone. I can add this to utc.

Upvotes: 0

deHaar
deHaar

Reputation: 18568

I think you need to take the Instant, create a ZonedDateTime (OffsetDateTime may be suitable as well) by applying a ZoneId.of("UTC") and then take that ZonedDateTime and use it to shift the locale:

public static void main(String[] args) {
    Instant now = Instant.now();
    
    ZonedDateTime utcZdt = now.atZone(ZoneId.of("UTC"));
    ZonedDateTime localZdt = utcZdt.withZoneSameLocal(ZoneId.systemDefault());
    
    System.out.println(utcZdt.toEpochSecond() + " <== " + utcZdt);
    System.out.println(localZdt.toEpochSecond() + " <== " + localZdt);
}

On my system, this outputs

1593765852 <== 2020-07-03T08:44:12.070Z[UTC]
1593758652 <== 2020-07-03T08:44:12.070+02:00[Europe/Berlin]

Two hours difference are affecting the sixth digit of the epoch seconds.

Upvotes: 3

Related Questions