androidgeofencingandroid-geofence

How to convert the Geofence expirationTime into readable format?


I'm creating a geofence in Android as shown in the Android documentation. The expiration duration in the example is 10 minutes, i.e. 600000 milliseconds.

geofenceList.add(new Geofence.Builder()
    .setRequestId("Victoria Station")
    .setCircularRegion(51.4954, -0.1443054, 500)
    .setExpirationDuration(600000)
    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
    .build());

public Geofence.Builder setExpirationDuration (long durationMillis)
Sets the expiration duration of geofence. This geofence will be removed automatically after this period of time.

Later I'm checking the entered values of the geofence like this

Geofence geofence = geofenceList.get(0);
Log.d(LOG_TAG, "expirationTime: " + geofence.getExpirationTime());

which results in an expirationTime of 525501519

public abstract long getExpirationTime ()
Returns the expiration elapsed realtime of geofence in milliseconds, or NEVER_EXPIRE if there's no expiration. When positive, this geofence will be removed automatically after that time.

How can I convert this expirationTime 525501519 into readable format?
Note: It is NOT a unix timestamp, which would be something like 1669823453000...


Solution

  • I don’t think it is well documented, but the time you get from GeoFence.getExpirationTime() is on the system clock’s elapsed real time (not measured from the epoch and also not meaning the time until expiration). So a conversion is needed.

    Combining java.time, the modern Java date and time API, with the conversion found in another answer (links at the bottom), the following could be a way to obtain a human-readable wall-clock time of the geo-fence expiration.

    The code is not tested because I haven’t got an Android development environment here, so forgive if there’s a typo.

    Instant expiration = Instant.ofEpochMilli(
        System.currentTimeMillis()
            - SystemClock.elapsedRealTime()
            + geoFence.getExpirationTime()
    );
    
    ZonedDateTime expirationTime = expiration.atZone(ZoneId.systemDefault());
    String expirationString = expirationTime
        .format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
    
    System.out.println("Geo-fence expira a las: " + expirationString);
    

    Example output:

    Geo-fence expira a las: 04:05:52

    From the documentation of SystemClock:

    elapsedRealtime() and elapsedRealtimeNanos() return the time since the system was booted, and include deep sleep. This clock is guaranteed to be monotonic, and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing.

    So this time is the right one for an expiration. The fence will expire 10 minutes after it’s been set no matter if the device goes to sleep in the meantime or the user tampers with the clock (on the other hand, the output from above code will relate to the Android clock and the time the user sees on that clock, which I take for desired).

    DateTimeFormatter.ofLocalizedTime() implicitly relies upon the JVM’s current default Locale for producing the particular localized text, which is often a good bet for making users happy. If you want the time formatted differently, you can format the obtained ZonedDateTime in countless ways. Use the tutorial link at the bottom and/or search. If you are developing for older Android versions (under API level 26), the above code will require core library desugaring (link below).

    Links